1c2c66affSColin Finck /* 2c2c66affSColin Finck * PROJECT: ReactOS Kernel 3c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory 4c2c66affSColin Finck * FILE: ntoskrnl/po/power.c 5c2c66affSColin Finck * PURPOSE: Power Manager 6c2c66affSColin Finck * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) 7c2c66affSColin Finck * Herv� Poussineau (hpoussin@reactos.com) 8c2c66affSColin Finck */ 9c2c66affSColin Finck 10c2c66affSColin Finck /* INCLUDES ******************************************************************/ 11c2c66affSColin Finck 12c2c66affSColin Finck #include <ntoskrnl.h> 13c2c66affSColin Finck #define NDEBUG 14c2c66affSColin Finck #include <debug.h> 15c2c66affSColin Finck 16c2c66affSColin Finck /* GLOBALS *******************************************************************/ 17c2c66affSColin Finck 18c2c66affSColin Finck typedef struct _POWER_STATE_TRAVERSE_CONTEXT 19c2c66affSColin Finck { 20c2c66affSColin Finck SYSTEM_POWER_STATE SystemPowerState; 21c2c66affSColin Finck POWER_ACTION PowerAction; 22c2c66affSColin Finck PDEVICE_OBJECT PowerDevice; 23c2c66affSColin Finck } POWER_STATE_TRAVERSE_CONTEXT, *PPOWER_STATE_TRAVERSE_CONTEXT; 24c2c66affSColin Finck 25c2c66affSColin Finck PDEVICE_NODE PopSystemPowerDeviceNode = NULL; 26c2c66affSColin Finck BOOLEAN PopAcpiPresent = FALSE; 27c2c66affSColin Finck POP_POWER_ACTION PopAction; 28c2c66affSColin Finck WORK_QUEUE_ITEM PopShutdownWorkItem; 29626aaf22SEric Kohl SYSTEM_POWER_CAPABILITIES PopCapabilities; 30c2c66affSColin Finck 31c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/ 32c2c66affSColin Finck 3334f4b218SThomas Faber static WORKER_THREAD_ROUTINE PopPassivePowerCall; 3434f4b218SThomas Faber _Use_decl_annotations_ 3534f4b218SThomas Faber static 3634f4b218SThomas Faber VOID 3734f4b218SThomas Faber NTAPI 3834f4b218SThomas Faber PopPassivePowerCall( 3934f4b218SThomas Faber PVOID Parameter) 4034f4b218SThomas Faber { 4134f4b218SThomas Faber PIRP Irp = Parameter; 4234f4b218SThomas Faber PIO_STACK_LOCATION IoStack; 4334f4b218SThomas Faber 4434f4b218SThomas Faber ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); 4534f4b218SThomas Faber 4634f4b218SThomas Faber _Analysis_assume_(Irp != NULL); 4734f4b218SThomas Faber IoStack = IoGetNextIrpStackLocation(Irp); 4834f4b218SThomas Faber 4934f4b218SThomas Faber (VOID)IoCallDriver(IoStack->DeviceObject, Irp); 5034f4b218SThomas Faber } 5134f4b218SThomas Faber 5234f4b218SThomas Faber _IRQL_requires_max_(DISPATCH_LEVEL) 5334f4b218SThomas Faber _IRQL_requires_same_ 5434f4b218SThomas Faber static 5534f4b218SThomas Faber NTSTATUS 5634f4b218SThomas Faber PopPresentIrp( 5734f4b218SThomas Faber _In_ PIO_STACK_LOCATION NextStack, 5834f4b218SThomas Faber _In_ PIRP Irp) 5934f4b218SThomas Faber { 6034f4b218SThomas Faber NTSTATUS Status; 6134f4b218SThomas Faber BOOLEAN CallAtPassiveLevel; 6234f4b218SThomas Faber PDEVICE_OBJECT DeviceObject; 6334f4b218SThomas Faber PWORK_QUEUE_ITEM WorkQueueItem; 6434f4b218SThomas Faber 6534f4b218SThomas Faber ASSERT(NextStack->MajorFunction == IRP_MJ_POWER); 6634f4b218SThomas Faber 6734f4b218SThomas Faber DeviceObject = NextStack->DeviceObject; 6834f4b218SThomas Faber 6934f4b218SThomas Faber /* Determine whether the IRP must be handled at PASSIVE_LEVEL. 7034f4b218SThomas Faber * Only SET_POWER to working state can happen at raised IRQL. */ 7134f4b218SThomas Faber CallAtPassiveLevel = TRUE; 7234f4b218SThomas Faber if ((NextStack->MinorFunction == IRP_MN_SET_POWER) && 7334f4b218SThomas Faber !(DeviceObject->Flags & DO_POWER_PAGABLE)) 7434f4b218SThomas Faber { 7534f4b218SThomas Faber if (NextStack->Parameters.Power.Type == DevicePowerState && 7634f4b218SThomas Faber NextStack->Parameters.Power.State.DeviceState == PowerDeviceD0) 7734f4b218SThomas Faber { 7834f4b218SThomas Faber CallAtPassiveLevel = FALSE; 7934f4b218SThomas Faber } 8034f4b218SThomas Faber if (NextStack->Parameters.Power.Type == SystemPowerState && 8134f4b218SThomas Faber NextStack->Parameters.Power.State.SystemState == PowerSystemWorking) 8234f4b218SThomas Faber { 8334f4b218SThomas Faber CallAtPassiveLevel = FALSE; 8434f4b218SThomas Faber } 8534f4b218SThomas Faber } 8634f4b218SThomas Faber 8734f4b218SThomas Faber if (CallAtPassiveLevel) 8834f4b218SThomas Faber { 8934f4b218SThomas Faber /* We need to fit a work item into the DriverContext below */ 9034f4b218SThomas Faber C_ASSERT(sizeof(Irp->Tail.Overlay.DriverContext) >= sizeof(WORK_QUEUE_ITEM)); 9134f4b218SThomas Faber 9234f4b218SThomas Faber if (KeGetCurrentIrql() == PASSIVE_LEVEL) 9334f4b218SThomas Faber { 9434f4b218SThomas Faber /* Already at passive, call next driver directly */ 9534f4b218SThomas Faber return IoCallDriver(DeviceObject, Irp); 9634f4b218SThomas Faber } 9734f4b218SThomas Faber 9834f4b218SThomas Faber /* Need to schedule a work item and return pending */ 9934f4b218SThomas Faber NextStack->Control |= SL_PENDING_RETURNED; 10034f4b218SThomas Faber 10134f4b218SThomas Faber WorkQueueItem = (PWORK_QUEUE_ITEM)&Irp->Tail.Overlay.DriverContext; 10234f4b218SThomas Faber ExInitializeWorkItem(WorkQueueItem, 10334f4b218SThomas Faber PopPassivePowerCall, 10434f4b218SThomas Faber Irp); 10534f4b218SThomas Faber ExQueueWorkItem(WorkQueueItem, DelayedWorkQueue); 10634f4b218SThomas Faber 10734f4b218SThomas Faber return STATUS_PENDING; 10834f4b218SThomas Faber } 10934f4b218SThomas Faber 11034f4b218SThomas Faber /* Direct call. Raise IRQL in debug to catch invalid paged memory access. */ 11134f4b218SThomas Faber #if DBG 11234f4b218SThomas Faber { 11334f4b218SThomas Faber KIRQL OldIrql; 11434f4b218SThomas Faber KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); 11534f4b218SThomas Faber #endif 11634f4b218SThomas Faber 11734f4b218SThomas Faber Status = IoCallDriver(DeviceObject, Irp); 11834f4b218SThomas Faber 11934f4b218SThomas Faber #if DBG 12034f4b218SThomas Faber KeLowerIrql(OldIrql); 12134f4b218SThomas Faber } 12234f4b218SThomas Faber #endif 12334f4b218SThomas Faber 12434f4b218SThomas Faber return Status; 12534f4b218SThomas Faber } 12634f4b218SThomas Faber 127c2c66affSColin Finck static 128c2c66affSColin Finck NTSTATUS 129c2c66affSColin Finck NTAPI 130c2c66affSColin Finck PopRequestPowerIrpCompletion(IN PDEVICE_OBJECT DeviceObject, 131c2c66affSColin Finck IN PIRP Irp, 132c2c66affSColin Finck IN PVOID Context) 133c2c66affSColin Finck { 134c2c66affSColin Finck PIO_STACK_LOCATION Stack; 135c2c66affSColin Finck PREQUEST_POWER_COMPLETE CompletionRoutine; 136c2c66affSColin Finck POWER_STATE PowerState; 137c2c66affSColin Finck 138c2c66affSColin Finck Stack = IoGetCurrentIrpStackLocation(Irp); 139c2c66affSColin Finck CompletionRoutine = Context; 140c2c66affSColin Finck 141c2c66affSColin Finck PowerState.DeviceState = (ULONG_PTR)Stack->Parameters.Others.Argument3; 142c2c66affSColin Finck CompletionRoutine(Stack->Parameters.Others.Argument1, 143c2c66affSColin Finck (UCHAR)(ULONG_PTR)Stack->Parameters.Others.Argument2, 144c2c66affSColin Finck PowerState, 145c2c66affSColin Finck Stack->Parameters.Others.Argument4, 146c2c66affSColin Finck &Irp->IoStatus); 147c2c66affSColin Finck 148c2c66affSColin Finck IoSkipCurrentIrpStackLocation(Irp); 149c2c66affSColin Finck IoFreeIrp(Irp); 150c2c66affSColin Finck ObDereferenceObject(DeviceObject); 151c2c66affSColin Finck 152c2c66affSColin Finck return STATUS_MORE_PROCESSING_REQUIRED; 153c2c66affSColin Finck } 154c2c66affSColin Finck 155c2c66affSColin Finck VOID 156c2c66affSColin Finck NTAPI 157c2c66affSColin Finck PopCleanupPowerState(IN PPOWER_STATE PowerState) 158c2c66affSColin Finck { 159c2c66affSColin Finck //UNIMPLEMENTED; 160c2c66affSColin Finck } 161c2c66affSColin Finck 162c2c66affSColin Finck NTSTATUS 163c2c66affSColin Finck PopSendQuerySystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction) 164c2c66affSColin Finck { 165c2c66affSColin Finck KEVENT Event; 166c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock; 167c2c66affSColin Finck PIO_STACK_LOCATION IrpSp; 168c2c66affSColin Finck PIRP Irp; 169c2c66affSColin Finck NTSTATUS Status; 170c2c66affSColin Finck 171c2c66affSColin Finck KeInitializeEvent(&Event, 172c2c66affSColin Finck NotificationEvent, 173c2c66affSColin Finck FALSE); 174c2c66affSColin Finck 175c2c66affSColin Finck Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER, 176c2c66affSColin Finck DeviceObject, 177c2c66affSColin Finck NULL, 178c2c66affSColin Finck 0, 179c2c66affSColin Finck NULL, 180c2c66affSColin Finck &Event, 181c2c66affSColin Finck &IoStatusBlock); 182c2c66affSColin Finck if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 183c2c66affSColin Finck 184c2c66affSColin Finck IrpSp = IoGetNextIrpStackLocation(Irp); 185c2c66affSColin Finck IrpSp->MinorFunction = IRP_MN_QUERY_POWER; 186c2c66affSColin Finck IrpSp->Parameters.Power.Type = SystemPowerState; 187c2c66affSColin Finck IrpSp->Parameters.Power.State.SystemState = SystemState; 188c2c66affSColin Finck IrpSp->Parameters.Power.ShutdownType = PowerAction; 189c2c66affSColin Finck 190c2c66affSColin Finck Status = PoCallDriver(DeviceObject, Irp); 191c2c66affSColin Finck if (Status == STATUS_PENDING) 192c2c66affSColin Finck { 193c2c66affSColin Finck KeWaitForSingleObject(&Event, 194c2c66affSColin Finck Executive, 195c2c66affSColin Finck KernelMode, 196c2c66affSColin Finck FALSE, 197c2c66affSColin Finck NULL); 198c2c66affSColin Finck Status = IoStatusBlock.Status; 199c2c66affSColin Finck } 200c2c66affSColin Finck 201c2c66affSColin Finck return Status; 202c2c66affSColin Finck } 203c2c66affSColin Finck 204c2c66affSColin Finck NTSTATUS 205c2c66affSColin Finck PopSendSetSystemPowerState(PDEVICE_OBJECT DeviceObject, SYSTEM_POWER_STATE SystemState, POWER_ACTION PowerAction) 206c2c66affSColin Finck { 207c2c66affSColin Finck KEVENT Event; 208c2c66affSColin Finck IO_STATUS_BLOCK IoStatusBlock; 209c2c66affSColin Finck PIO_STACK_LOCATION IrpSp; 210c2c66affSColin Finck PIRP Irp; 211c2c66affSColin Finck NTSTATUS Status; 212c2c66affSColin Finck 213c2c66affSColin Finck KeInitializeEvent(&Event, 214c2c66affSColin Finck NotificationEvent, 215c2c66affSColin Finck FALSE); 216c2c66affSColin Finck 217c2c66affSColin Finck Irp = IoBuildSynchronousFsdRequest(IRP_MJ_POWER, 218c2c66affSColin Finck DeviceObject, 219c2c66affSColin Finck NULL, 220c2c66affSColin Finck 0, 221c2c66affSColin Finck NULL, 222c2c66affSColin Finck &Event, 223c2c66affSColin Finck &IoStatusBlock); 224c2c66affSColin Finck if (!Irp) return STATUS_INSUFFICIENT_RESOURCES; 225c2c66affSColin Finck 226c2c66affSColin Finck IrpSp = IoGetNextIrpStackLocation(Irp); 227c2c66affSColin Finck IrpSp->MinorFunction = IRP_MN_SET_POWER; 228c2c66affSColin Finck IrpSp->Parameters.Power.Type = SystemPowerState; 229c2c66affSColin Finck IrpSp->Parameters.Power.State.SystemState = SystemState; 230c2c66affSColin Finck IrpSp->Parameters.Power.ShutdownType = PowerAction; 231c2c66affSColin Finck 232c2c66affSColin Finck Status = PoCallDriver(DeviceObject, Irp); 233c2c66affSColin Finck if (Status == STATUS_PENDING) 234c2c66affSColin Finck { 235c2c66affSColin Finck KeWaitForSingleObject(&Event, 236c2c66affSColin Finck Executive, 237c2c66affSColin Finck KernelMode, 238c2c66affSColin Finck FALSE, 239c2c66affSColin Finck NULL); 240c2c66affSColin Finck Status = IoStatusBlock.Status; 241c2c66affSColin Finck } 242c2c66affSColin Finck 243c2c66affSColin Finck return Status; 244c2c66affSColin Finck } 245c2c66affSColin Finck 246c2c66affSColin Finck NTSTATUS 247c2c66affSColin Finck PopQuerySystemPowerStateTraverse(PDEVICE_NODE DeviceNode, 248c2c66affSColin Finck PVOID Context) 249c2c66affSColin Finck { 250c2c66affSColin Finck PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context; 251c2c66affSColin Finck PDEVICE_OBJECT TopDeviceObject; 252c2c66affSColin Finck NTSTATUS Status; 253c2c66affSColin Finck 254c2c66affSColin Finck DPRINT("PopQuerySystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context); 255c2c66affSColin Finck 256c2c66affSColin Finck if (DeviceNode == IopRootDeviceNode) 257c2c66affSColin Finck return STATUS_SUCCESS; 258c2c66affSColin Finck 259c2c66affSColin Finck if (DeviceNode->Flags & DNF_LEGACY_DRIVER) 260c2c66affSColin Finck return STATUS_SUCCESS; 261c2c66affSColin Finck 262c2c66affSColin Finck TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject); 263c2c66affSColin Finck 264c2c66affSColin Finck Status = PopSendQuerySystemPowerState(TopDeviceObject, 265c2c66affSColin Finck PowerStateContext->SystemPowerState, 266c2c66affSColin Finck PowerStateContext->PowerAction); 267c2c66affSColin Finck if (!NT_SUCCESS(Status)) 268c2c66affSColin Finck { 269c2c66affSColin Finck DPRINT1("Device '%wZ' failed IRP_MN_QUERY_POWER\n", &DeviceNode->InstancePath); 270c2c66affSColin Finck } 271c2c66affSColin Finck ObDereferenceObject(TopDeviceObject); 272c2c66affSColin Finck 273c2c66affSColin Finck #if 0 274c2c66affSColin Finck return Status; 275c2c66affSColin Finck #else 276c2c66affSColin Finck return STATUS_SUCCESS; 277c2c66affSColin Finck #endif 278c2c66affSColin Finck } 279c2c66affSColin Finck 280c2c66affSColin Finck NTSTATUS 281c2c66affSColin Finck PopSetSystemPowerStateTraverse(PDEVICE_NODE DeviceNode, 282c2c66affSColin Finck PVOID Context) 283c2c66affSColin Finck { 284c2c66affSColin Finck PPOWER_STATE_TRAVERSE_CONTEXT PowerStateContext = Context; 285c2c66affSColin Finck PDEVICE_OBJECT TopDeviceObject; 286c2c66affSColin Finck NTSTATUS Status; 287c2c66affSColin Finck 288c2c66affSColin Finck DPRINT("PopSetSystemPowerStateTraverse(%p, %p)\n", DeviceNode, Context); 289c2c66affSColin Finck 290c2c66affSColin Finck if (DeviceNode == IopRootDeviceNode) 291c2c66affSColin Finck return STATUS_SUCCESS; 292c2c66affSColin Finck 293c2c66affSColin Finck if (DeviceNode->PhysicalDeviceObject == PowerStateContext->PowerDevice) 294c2c66affSColin Finck return STATUS_SUCCESS; 295c2c66affSColin Finck 296c2c66affSColin Finck if (DeviceNode->Flags & DNF_LEGACY_DRIVER) 297c2c66affSColin Finck return STATUS_SUCCESS; 298c2c66affSColin Finck 299c2c66affSColin Finck TopDeviceObject = IoGetAttachedDeviceReference(DeviceNode->PhysicalDeviceObject); 300c2c66affSColin Finck if (TopDeviceObject == PowerStateContext->PowerDevice) 301c2c66affSColin Finck { 302c2c66affSColin Finck ObDereferenceObject(TopDeviceObject); 303c2c66affSColin Finck return STATUS_SUCCESS; 304c2c66affSColin Finck } 305c2c66affSColin Finck 306c2c66affSColin Finck Status = PopSendSetSystemPowerState(TopDeviceObject, 307c2c66affSColin Finck PowerStateContext->SystemPowerState, 308c2c66affSColin Finck PowerStateContext->PowerAction); 309c2c66affSColin Finck if (!NT_SUCCESS(Status)) 310c2c66affSColin Finck { 311c2c66affSColin Finck DPRINT1("Device '%wZ' failed IRP_MN_SET_POWER\n", &DeviceNode->InstancePath); 312c2c66affSColin Finck } 313c2c66affSColin Finck 314c2c66affSColin Finck ObDereferenceObject(TopDeviceObject); 315c2c66affSColin Finck 316c2c66affSColin Finck #if 0 317c2c66affSColin Finck return Status; 318c2c66affSColin Finck #else 319c2c66affSColin Finck return STATUS_SUCCESS; 320c2c66affSColin Finck #endif 321c2c66affSColin Finck } 322c2c66affSColin Finck 323c2c66affSColin Finck NTSTATUS 324c2c66affSColin Finck NTAPI 325c2c66affSColin Finck PopSetSystemPowerState(SYSTEM_POWER_STATE PowerState, POWER_ACTION PowerAction) 326c2c66affSColin Finck { 327c2c66affSColin Finck PDEVICE_OBJECT DeviceObject; 328c2c66affSColin Finck PDEVICE_OBJECT Fdo; 329c2c66affSColin Finck NTSTATUS Status; 330c2c66affSColin Finck DEVICETREE_TRAVERSE_CONTEXT Context; 331c2c66affSColin Finck POWER_STATE_TRAVERSE_CONTEXT PowerContext; 332c2c66affSColin Finck 333c2c66affSColin Finck Status = IopGetSystemPowerDeviceObject(&DeviceObject); 334c2c66affSColin Finck if (!NT_SUCCESS(Status)) 335c2c66affSColin Finck { 336c2c66affSColin Finck DPRINT1("No system power driver available\n"); 337c2c66affSColin Finck Fdo = NULL; 338c2c66affSColin Finck } 339c2c66affSColin Finck else 340c2c66affSColin Finck { 341c2c66affSColin Finck Fdo = IoGetAttachedDeviceReference(DeviceObject); 342c2c66affSColin Finck if (Fdo == DeviceObject) 343c2c66affSColin Finck { 344c2c66affSColin Finck DPRINT("An FDO was not attached\n"); 345c2c66affSColin Finck return STATUS_UNSUCCESSFUL; 346c2c66affSColin Finck } 347c2c66affSColin Finck } 348c2c66affSColin Finck 349c2c66affSColin Finck /* Set up context */ 350c2c66affSColin Finck PowerContext.PowerAction = PowerAction; 351c2c66affSColin Finck PowerContext.SystemPowerState = PowerState; 352c2c66affSColin Finck PowerContext.PowerDevice = Fdo; 353c2c66affSColin Finck 354c2c66affSColin Finck /* Query for system power change */ 355c2c66affSColin Finck IopInitDeviceTreeTraverseContext(&Context, 356c2c66affSColin Finck IopRootDeviceNode, 357c2c66affSColin Finck PopQuerySystemPowerStateTraverse, 358c2c66affSColin Finck &PowerContext); 359c2c66affSColin Finck 360c2c66affSColin Finck Status = IopTraverseDeviceTree(&Context); 361c2c66affSColin Finck if (!NT_SUCCESS(Status)) 362c2c66affSColin Finck { 363c2c66affSColin Finck DPRINT1("Query system power state failed; changing state anyway\n"); 364c2c66affSColin Finck } 365c2c66affSColin Finck 366c2c66affSColin Finck /* Set system power change */ 367c2c66affSColin Finck IopInitDeviceTreeTraverseContext(&Context, 368c2c66affSColin Finck IopRootDeviceNode, 369c2c66affSColin Finck PopSetSystemPowerStateTraverse, 370c2c66affSColin Finck &PowerContext); 371c2c66affSColin Finck 372c2c66affSColin Finck IopTraverseDeviceTree(&Context); 373c2c66affSColin Finck 374c2c66affSColin Finck if (!PopAcpiPresent) return STATUS_NOT_IMPLEMENTED; 375c2c66affSColin Finck 376c2c66affSColin Finck if (Fdo != NULL) 377c2c66affSColin Finck { 378c2c66affSColin Finck if (PowerAction != PowerActionShutdownReset) 379c2c66affSColin Finck PopSendSetSystemPowerState(Fdo, PowerState, PowerAction); 380c2c66affSColin Finck 381c2c66affSColin Finck ObDereferenceObject(Fdo); 382c2c66affSColin Finck } 383c2c66affSColin Finck 384c2c66affSColin Finck return Status; 385c2c66affSColin Finck } 386c2c66affSColin Finck 387*5c7ce447SVictor Perevertkin CODE_SEG("INIT") 388c2c66affSColin Finck BOOLEAN 389c2c66affSColin Finck NTAPI 390c2c66affSColin Finck PoInitSystem(IN ULONG BootPhase) 391c2c66affSColin Finck { 392c2c66affSColin Finck PVOID NotificationEntry; 393c2c66affSColin Finck PCHAR CommandLine; 394c2c66affSColin Finck BOOLEAN ForceAcpiDisable = FALSE; 395c2c66affSColin Finck 396c2c66affSColin Finck /* Check if this is phase 1 init */ 397c2c66affSColin Finck if (BootPhase == 1) 398c2c66affSColin Finck { 399c2c66affSColin Finck /* Register power button notification */ 400c2c66affSColin Finck IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, 401c2c66affSColin Finck PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 402c2c66affSColin Finck (PVOID)&GUID_DEVICE_SYS_BUTTON, 403c2c66affSColin Finck IopRootDeviceNode-> 404c2c66affSColin Finck PhysicalDeviceObject->DriverObject, 405c2c66affSColin Finck PopAddRemoveSysCapsCallback, 406c2c66affSColin Finck NULL, 407c2c66affSColin Finck &NotificationEntry); 408c2c66affSColin Finck 409c2c66affSColin Finck /* Register lid notification */ 410c2c66affSColin Finck IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange, 411c2c66affSColin Finck PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, 412c2c66affSColin Finck (PVOID)&GUID_DEVICE_LID, 413c2c66affSColin Finck IopRootDeviceNode-> 414c2c66affSColin Finck PhysicalDeviceObject->DriverObject, 415c2c66affSColin Finck PopAddRemoveSysCapsCallback, 416c2c66affSColin Finck NULL, 417c2c66affSColin Finck &NotificationEntry); 418c2c66affSColin Finck return TRUE; 419c2c66affSColin Finck } 420c2c66affSColin Finck 421626aaf22SEric Kohl /* Initialize the power capabilities */ 422626aaf22SEric Kohl RtlZeroMemory(&PopCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES)); 423626aaf22SEric Kohl 424c2c66affSColin Finck /* Get the Command Line */ 425c2c66affSColin Finck CommandLine = KeLoaderBlock->LoadOptions; 426c2c66affSColin Finck 427c2c66affSColin Finck /* Upcase it */ 428c2c66affSColin Finck _strupr(CommandLine); 429c2c66affSColin Finck 430c2c66affSColin Finck /* Check for ACPI disable */ 431c2c66affSColin Finck if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE; 432c2c66affSColin Finck 433c2c66affSColin Finck if (ForceAcpiDisable) 434c2c66affSColin Finck { 435c2c66affSColin Finck /* Set the ACPI State to False if it's been forced that way */ 436c2c66affSColin Finck PopAcpiPresent = FALSE; 437c2c66affSColin Finck } 438c2c66affSColin Finck else 439c2c66affSColin Finck { 440c2c66affSColin Finck /* Otherwise check if the LoaderBlock has a ACPI Table */ 441c2c66affSColin Finck PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE; 442c2c66affSColin Finck } 443c2c66affSColin Finck 444626aaf22SEric Kohl /* Enable shutdown by power button */ 445626aaf22SEric Kohl if (PopAcpiPresent) 446626aaf22SEric Kohl PopCapabilities.SystemS5 = TRUE; 447c2c66affSColin Finck 448c2c66affSColin Finck /* Initialize volume support */ 449c2c66affSColin Finck InitializeListHead(&PopVolumeDevices); 450c2c66affSColin Finck KeInitializeGuardedMutex(&PopVolumeLock); 451c2c66affSColin Finck 452c2c66affSColin Finck /* Initialize support for dope */ 453c2c66affSColin Finck KeInitializeSpinLock(&PopDopeGlobalLock); 454c2c66affSColin Finck 455c2c66affSColin Finck /* Initialize support for shutdown waits and work-items */ 456c2c66affSColin Finck PopInitShutdownList(); 457c2c66affSColin Finck 458c2c66affSColin Finck return TRUE; 459c2c66affSColin Finck } 460c2c66affSColin Finck 461c2c66affSColin Finck VOID 462c2c66affSColin Finck NTAPI 463c2c66affSColin Finck PopPerfIdle(PPROCESSOR_POWER_STATE PowerState) 464c2c66affSColin Finck { 465c2c66affSColin Finck DPRINT1("PerfIdle function: %p\n", PowerState); 466c2c66affSColin Finck } 467c2c66affSColin Finck 468c2c66affSColin Finck VOID 469c2c66affSColin Finck NTAPI 470c2c66affSColin Finck PopPerfIdleDpc(IN PKDPC Dpc, 471c2c66affSColin Finck IN PVOID DeferredContext, 472c2c66affSColin Finck IN PVOID SystemArgument1, 473c2c66affSColin Finck IN PVOID SystemArgument2) 474c2c66affSColin Finck { 475c2c66affSColin Finck /* Call the Perf Idle function */ 476c2c66affSColin Finck PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState); 477c2c66affSColin Finck } 478c2c66affSColin Finck 479c2c66affSColin Finck VOID 480c2c66affSColin Finck FASTCALL 481c2c66affSColin Finck PopIdle0(IN PPROCESSOR_POWER_STATE PowerState) 482c2c66affSColin Finck { 483c2c66affSColin Finck /* FIXME: Extremly naive implementation */ 484c2c66affSColin Finck HalProcessorIdle(); 485c2c66affSColin Finck } 486c2c66affSColin Finck 487*5c7ce447SVictor Perevertkin CODE_SEG("INIT") 488c2c66affSColin Finck VOID 489c2c66affSColin Finck NTAPI 490c2c66affSColin Finck PoInitializePrcb(IN PKPRCB Prcb) 491c2c66affSColin Finck { 492c2c66affSColin Finck /* Initialize the Power State */ 493c2c66affSColin Finck RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState)); 494c2c66affSColin Finck Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF; 495c2c66affSColin Finck Prcb->PowerState.CurrentThrottle = 100; 496c2c66affSColin Finck Prcb->PowerState.CurrentThrottleIndex = 0; 497c2c66affSColin Finck Prcb->PowerState.IdleFunction = PopIdle0; 498c2c66affSColin Finck 499c2c66affSColin Finck /* Initialize the Perf DPC and Timer */ 500c2c66affSColin Finck KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb); 501c2c66affSColin Finck KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number); 502c2c66affSColin Finck KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer); 503c2c66affSColin Finck } 504c2c66affSColin Finck 505c2c66affSColin Finck /* PUBLIC FUNCTIONS **********************************************************/ 506c2c66affSColin Finck 507c2c66affSColin Finck /* 508c2c66affSColin Finck * @unimplemented 509c2c66affSColin Finck */ 510c2c66affSColin Finck NTSTATUS 511c2c66affSColin Finck NTAPI 512c2c66affSColin Finck PoCancelDeviceNotify(IN PVOID NotifyBlock) 513c2c66affSColin Finck { 514c2c66affSColin Finck UNIMPLEMENTED; 515c2c66affSColin Finck return STATUS_NOT_IMPLEMENTED; 516c2c66affSColin Finck } 517c2c66affSColin Finck 518c2c66affSColin Finck /* 519c2c66affSColin Finck * @unimplemented 520c2c66affSColin Finck */ 521c2c66affSColin Finck NTSTATUS 522c2c66affSColin Finck NTAPI 523c2c66affSColin Finck PoRegisterDeviceNotify(OUT PVOID Unknown0, 524c2c66affSColin Finck IN ULONG Unknown1, 525c2c66affSColin Finck IN ULONG Unknown2, 526c2c66affSColin Finck IN ULONG Unknown3, 527c2c66affSColin Finck IN PVOID Unknown4, 528c2c66affSColin Finck IN PVOID Unknown5) 529c2c66affSColin Finck { 530c2c66affSColin Finck UNIMPLEMENTED; 531c2c66affSColin Finck return STATUS_NOT_IMPLEMENTED; 532c2c66affSColin Finck } 533c2c66affSColin Finck 534c2c66affSColin Finck /* 535c2c66affSColin Finck * @unimplemented 536c2c66affSColin Finck */ 537c2c66affSColin Finck VOID 538c2c66affSColin Finck NTAPI 539c2c66affSColin Finck PoShutdownBugCheck(IN BOOLEAN LogError, 540c2c66affSColin Finck IN ULONG BugCheckCode, 541c2c66affSColin Finck IN ULONG_PTR BugCheckParameter1, 542c2c66affSColin Finck IN ULONG_PTR BugCheckParameter2, 543c2c66affSColin Finck IN ULONG_PTR BugCheckParameter3, 544c2c66affSColin Finck IN ULONG_PTR BugCheckParameter4) 545c2c66affSColin Finck { 546c2c66affSColin Finck DPRINT1("PoShutdownBugCheck called\n"); 547c2c66affSColin Finck 548c2c66affSColin Finck /* FIXME: Log error if requested */ 549c2c66affSColin Finck /* FIXME: Initiate a shutdown */ 550c2c66affSColin Finck 551c2c66affSColin Finck /* Bugcheck the system */ 552c2c66affSColin Finck KeBugCheckEx(BugCheckCode, 553c2c66affSColin Finck BugCheckParameter1, 554c2c66affSColin Finck BugCheckParameter2, 555c2c66affSColin Finck BugCheckParameter3, 556c2c66affSColin Finck BugCheckParameter4); 557c2c66affSColin Finck } 558c2c66affSColin Finck 559c2c66affSColin Finck /* 560c2c66affSColin Finck * @unimplemented 561c2c66affSColin Finck */ 562c2c66affSColin Finck VOID 563c2c66affSColin Finck NTAPI 564c2c66affSColin Finck PoSetHiberRange(IN PVOID HiberContext, 565c2c66affSColin Finck IN ULONG Flags, 566c2c66affSColin Finck IN OUT PVOID StartPage, 567c2c66affSColin Finck IN ULONG Length, 568c2c66affSColin Finck IN ULONG PageTag) 569c2c66affSColin Finck { 570c2c66affSColin Finck UNIMPLEMENTED; 571c2c66affSColin Finck return; 572c2c66affSColin Finck } 573c2c66affSColin Finck 574c2c66affSColin Finck /* 575c2c66affSColin Finck * @implemented 576c2c66affSColin Finck */ 57734f4b218SThomas Faber _IRQL_requires_max_(DISPATCH_LEVEL) 578c2c66affSColin Finck NTSTATUS 579c2c66affSColin Finck NTAPI 58034f4b218SThomas Faber PoCallDriver( 58134f4b218SThomas Faber _In_ PDEVICE_OBJECT DeviceObject, 58234f4b218SThomas Faber _Inout_ __drv_aliasesMem PIRP Irp) 583c2c66affSColin Finck { 58434f4b218SThomas Faber PIO_STACK_LOCATION NextStack; 585c2c66affSColin Finck 58634f4b218SThomas Faber ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 587c2c66affSColin Finck 58834f4b218SThomas Faber ASSERT(DeviceObject); 58934f4b218SThomas Faber ASSERT(Irp); 59034f4b218SThomas Faber 59134f4b218SThomas Faber NextStack = IoGetNextIrpStackLocation(Irp); 59234f4b218SThomas Faber ASSERT(NextStack->MajorFunction == IRP_MJ_POWER); 59334f4b218SThomas Faber 59434f4b218SThomas Faber /* Set DeviceObject for PopPresentIrp */ 59534f4b218SThomas Faber NextStack->DeviceObject = DeviceObject; 59634f4b218SThomas Faber 59734f4b218SThomas Faber /* Only QUERY_POWER and SET_POWER use special handling */ 59834f4b218SThomas Faber if (NextStack->MinorFunction != IRP_MN_SET_POWER && 59934f4b218SThomas Faber NextStack->MinorFunction != IRP_MN_QUERY_POWER) 60034f4b218SThomas Faber { 60134f4b218SThomas Faber return IoCallDriver(DeviceObject, Irp); 60234f4b218SThomas Faber } 60334f4b218SThomas Faber 60434f4b218SThomas Faber /* Call the next driver, either directly or at PASSIVE_LEVEL */ 60534f4b218SThomas Faber return PopPresentIrp(NextStack, Irp); 606c2c66affSColin Finck } 607c2c66affSColin Finck 608c2c66affSColin Finck /* 609c2c66affSColin Finck * @unimplemented 610c2c66affSColin Finck */ 611c2c66affSColin Finck PULONG 612c2c66affSColin Finck NTAPI 613c2c66affSColin Finck PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject, 614c2c66affSColin Finck IN ULONG ConservationIdleTime, 615c2c66affSColin Finck IN ULONG PerformanceIdleTime, 616c2c66affSColin Finck IN DEVICE_POWER_STATE State) 617c2c66affSColin Finck { 618c2c66affSColin Finck UNIMPLEMENTED; 619c2c66affSColin Finck return NULL; 620c2c66affSColin Finck } 621c2c66affSColin Finck 622c2c66affSColin Finck /* 623c2c66affSColin Finck * @unimplemented 624c2c66affSColin Finck */ 625c2c66affSColin Finck PVOID 626c2c66affSColin Finck NTAPI 627c2c66affSColin Finck PoRegisterSystemState(IN PVOID StateHandle, 628c2c66affSColin Finck IN EXECUTION_STATE Flags) 629c2c66affSColin Finck { 630c2c66affSColin Finck UNIMPLEMENTED; 631c2c66affSColin Finck return NULL; 632c2c66affSColin Finck } 633c2c66affSColin Finck 634c2c66affSColin Finck /* 635c2c66affSColin Finck * @implemented 636c2c66affSColin Finck */ 637c2c66affSColin Finck NTSTATUS 638c2c66affSColin Finck NTAPI 639c2c66affSColin Finck PoRequestPowerIrp(IN PDEVICE_OBJECT DeviceObject, 640c2c66affSColin Finck IN UCHAR MinorFunction, 641c2c66affSColin Finck IN POWER_STATE PowerState, 642c2c66affSColin Finck IN PREQUEST_POWER_COMPLETE CompletionFunction, 643c2c66affSColin Finck IN PVOID Context, 644c2c66affSColin Finck OUT PIRP *pIrp OPTIONAL) 645c2c66affSColin Finck { 646c2c66affSColin Finck PDEVICE_OBJECT TopDeviceObject; 647c2c66affSColin Finck PIO_STACK_LOCATION Stack; 648c2c66affSColin Finck PIRP Irp; 649c2c66affSColin Finck 650c2c66affSColin Finck if (MinorFunction != IRP_MN_QUERY_POWER 651c2c66affSColin Finck && MinorFunction != IRP_MN_SET_POWER 652c2c66affSColin Finck && MinorFunction != IRP_MN_WAIT_WAKE) 653c2c66affSColin Finck return STATUS_INVALID_PARAMETER_2; 654c2c66affSColin Finck 655c2c66affSColin Finck /* Always call the top of the device stack */ 656c2c66affSColin Finck TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject); 657c2c66affSColin Finck 658c2c66affSColin Finck Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE); 659c2c66affSColin Finck if (!Irp) 660c2c66affSColin Finck { 661c2c66affSColin Finck ObDereferenceObject(TopDeviceObject); 662c2c66affSColin Finck return STATUS_INSUFFICIENT_RESOURCES; 663c2c66affSColin Finck } 664c2c66affSColin Finck 665c2c66affSColin Finck Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 666c2c66affSColin Finck Irp->IoStatus.Information = 0; 667c2c66affSColin Finck 668c2c66affSColin Finck IoSetNextIrpStackLocation(Irp); 669c2c66affSColin Finck 670c2c66affSColin Finck Stack = IoGetNextIrpStackLocation(Irp); 671c2c66affSColin Finck Stack->Parameters.Others.Argument1 = DeviceObject; 672c2c66affSColin Finck Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction; 673c2c66affSColin Finck Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState; 674c2c66affSColin Finck Stack->Parameters.Others.Argument4 = Context; 675c2c66affSColin Finck Stack->DeviceObject = TopDeviceObject; 676c2c66affSColin Finck IoSetNextIrpStackLocation(Irp); 677c2c66affSColin Finck 678c2c66affSColin Finck Stack = IoGetNextIrpStackLocation(Irp); 679c2c66affSColin Finck Stack->MajorFunction = IRP_MJ_POWER; 680c2c66affSColin Finck Stack->MinorFunction = MinorFunction; 681c2c66affSColin Finck if (MinorFunction == IRP_MN_WAIT_WAKE) 682c2c66affSColin Finck { 683c2c66affSColin Finck Stack->Parameters.WaitWake.PowerState = PowerState.SystemState; 684c2c66affSColin Finck } 685c2c66affSColin Finck else 686c2c66affSColin Finck { 687c2c66affSColin Finck Stack->Parameters.Power.Type = DevicePowerState; 688c2c66affSColin Finck Stack->Parameters.Power.State = PowerState; 689c2c66affSColin Finck } 690c2c66affSColin Finck 691c2c66affSColin Finck if (pIrp != NULL) 692c2c66affSColin Finck *pIrp = Irp; 693c2c66affSColin Finck 694c2c66affSColin Finck IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE); 695c2c66affSColin Finck PoCallDriver(TopDeviceObject, Irp); 696c2c66affSColin Finck 697c2c66affSColin Finck /* Always return STATUS_PENDING. The completion routine 698c2c66affSColin Finck * will call CompletionFunction and complete the Irp. 699c2c66affSColin Finck */ 700c2c66affSColin Finck return STATUS_PENDING; 701c2c66affSColin Finck } 702c2c66affSColin Finck 703c2c66affSColin Finck /* 704c2c66affSColin Finck * @unimplemented 705c2c66affSColin Finck */ 706c2c66affSColin Finck POWER_STATE 707c2c66affSColin Finck NTAPI 708c2c66affSColin Finck PoSetPowerState(IN PDEVICE_OBJECT DeviceObject, 709c2c66affSColin Finck IN POWER_STATE_TYPE Type, 710c2c66affSColin Finck IN POWER_STATE State) 711c2c66affSColin Finck { 712c2c66affSColin Finck POWER_STATE ps; 713c2c66affSColin Finck 714c2c66affSColin Finck ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 715c2c66affSColin Finck 716c2c66affSColin Finck ps.SystemState = PowerSystemWorking; // Fully on 717c2c66affSColin Finck ps.DeviceState = PowerDeviceD0; // Fully on 718c2c66affSColin Finck 719c2c66affSColin Finck return ps; 720c2c66affSColin Finck } 721c2c66affSColin Finck 722c2c66affSColin Finck /* 723c2c66affSColin Finck * @unimplemented 724c2c66affSColin Finck */ 725c2c66affSColin Finck VOID 726c2c66affSColin Finck NTAPI 727c2c66affSColin Finck PoSetSystemState(IN EXECUTION_STATE Flags) 728c2c66affSColin Finck { 729c2c66affSColin Finck UNIMPLEMENTED; 730c2c66affSColin Finck } 731c2c66affSColin Finck 732c2c66affSColin Finck /* 733c2c66affSColin Finck * @unimplemented 734c2c66affSColin Finck */ 735c2c66affSColin Finck VOID 736c2c66affSColin Finck NTAPI 737c2c66affSColin Finck PoStartNextPowerIrp(IN PIRP Irp) 738c2c66affSColin Finck { 7391539fb14SMark Jansen UNIMPLEMENTED_ONCE; 740c2c66affSColin Finck } 741c2c66affSColin Finck 742c2c66affSColin Finck /* 743c2c66affSColin Finck * @unimplemented 744c2c66affSColin Finck */ 745c2c66affSColin Finck VOID 746c2c66affSColin Finck NTAPI 747c2c66affSColin Finck PoUnregisterSystemState(IN PVOID StateHandle) 748c2c66affSColin Finck { 749c2c66affSColin Finck UNIMPLEMENTED; 750c2c66affSColin Finck } 751c2c66affSColin Finck 752c2c66affSColin Finck /* 753c2c66affSColin Finck * @unimplemented 754c2c66affSColin Finck */ 755c2c66affSColin Finck NTSTATUS 756c2c66affSColin Finck NTAPI 757c2c66affSColin Finck NtInitiatePowerAction(IN POWER_ACTION SystemAction, 758c2c66affSColin Finck IN SYSTEM_POWER_STATE MinSystemState, 759c2c66affSColin Finck IN ULONG Flags, 760c2c66affSColin Finck IN BOOLEAN Asynchronous) 761c2c66affSColin Finck { 762c2c66affSColin Finck UNIMPLEMENTED; 763c2c66affSColin Finck return STATUS_NOT_IMPLEMENTED; 764c2c66affSColin Finck } 765c2c66affSColin Finck 766c2c66affSColin Finck /* 767c2c66affSColin Finck * @unimplemented 768c2c66affSColin Finck */ 769c2c66affSColin Finck NTSTATUS 770c2c66affSColin Finck NTAPI 771c2c66affSColin Finck NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel, 772c2c66affSColin Finck IN PVOID InputBuffer OPTIONAL, 773c2c66affSColin Finck IN ULONG InputBufferLength, 774c2c66affSColin Finck OUT PVOID OutputBuffer OPTIONAL, 775c2c66affSColin Finck IN ULONG OutputBufferLength) 776c2c66affSColin Finck { 777c2c66affSColin Finck NTSTATUS Status; 778c2c66affSColin Finck KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 779c2c66affSColin Finck 780c2c66affSColin Finck PAGED_CODE(); 781c2c66affSColin Finck 782c2c66affSColin Finck DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, " 783c2c66affSColin Finck "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n", 784c2c66affSColin Finck PowerInformationLevel, 785c2c66affSColin Finck InputBuffer, InputBufferLength, 786c2c66affSColin Finck OutputBuffer, OutputBufferLength); 787c2c66affSColin Finck 788c2c66affSColin Finck if (PreviousMode != KernelMode) 789c2c66affSColin Finck { 790c2c66affSColin Finck _SEH2_TRY 791c2c66affSColin Finck { 792c2c66affSColin Finck ProbeForRead(InputBuffer, InputBufferLength, 1); 793c2c66affSColin Finck ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG)); 794c2c66affSColin Finck } 795c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 796c2c66affSColin Finck { 797c2c66affSColin Finck _SEH2_YIELD(return _SEH2_GetExceptionCode()); 798c2c66affSColin Finck } 799c2c66affSColin Finck _SEH2_END; 800c2c66affSColin Finck } 801c2c66affSColin Finck 802c2c66affSColin Finck switch (PowerInformationLevel) 803c2c66affSColin Finck { 804c2c66affSColin Finck case SystemBatteryState: 805c2c66affSColin Finck { 806c2c66affSColin Finck PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer; 807c2c66affSColin Finck 808c2c66affSColin Finck if (InputBuffer != NULL) 809c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 810c2c66affSColin Finck if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE)) 811c2c66affSColin Finck return STATUS_BUFFER_TOO_SMALL; 812c2c66affSColin Finck 813c2c66affSColin Finck _SEH2_TRY 814c2c66affSColin Finck { 815c2c66affSColin Finck /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */ 816c2c66affSColin Finck RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE)); 817cfe54aa4SEric Kohl BatteryState->EstimatedTime = MAXULONG; 818cfe54aa4SEric Kohl // BatteryState->AcOnLine = TRUE; 819c2c66affSColin Finck 820c2c66affSColin Finck Status = STATUS_SUCCESS; 821c2c66affSColin Finck } 822c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 823c2c66affSColin Finck { 824c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 825c2c66affSColin Finck } 826c2c66affSColin Finck _SEH2_END; 827c2c66affSColin Finck 828c2c66affSColin Finck break; 829c2c66affSColin Finck } 830c2c66affSColin Finck 831c2c66affSColin Finck case SystemPowerCapabilities: 832c2c66affSColin Finck { 833c2c66affSColin Finck PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer; 834c2c66affSColin Finck 835c2c66affSColin Finck if (InputBuffer != NULL) 836c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 837c2c66affSColin Finck if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES)) 838c2c66affSColin Finck return STATUS_BUFFER_TOO_SMALL; 839c2c66affSColin Finck 840c2c66affSColin Finck _SEH2_TRY 841c2c66affSColin Finck { 842626aaf22SEric Kohl RtlCopyMemory(PowerCapabilities, 843626aaf22SEric Kohl &PopCapabilities, 844626aaf22SEric Kohl sizeof(SYSTEM_POWER_CAPABILITIES)); 845c2c66affSColin Finck 846c2c66affSColin Finck Status = STATUS_SUCCESS; 847c2c66affSColin Finck } 848c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 849c2c66affSColin Finck { 850c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 851c2c66affSColin Finck } 852c2c66affSColin Finck _SEH2_END; 853c2c66affSColin Finck 854c2c66affSColin Finck break; 855c2c66affSColin Finck } 856c2c66affSColin Finck 857c2c66affSColin Finck case ProcessorInformation: 858c2c66affSColin Finck { 859c2c66affSColin Finck PPROCESSOR_POWER_INFORMATION PowerInformation = (PPROCESSOR_POWER_INFORMATION)OutputBuffer; 860c2c66affSColin Finck 861c2c66affSColin Finck if (InputBuffer != NULL) 862c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 863c2c66affSColin Finck if (OutputBufferLength < sizeof(PROCESSOR_POWER_INFORMATION)) 864c2c66affSColin Finck return STATUS_BUFFER_TOO_SMALL; 865c2c66affSColin Finck 8664c78b2c3SStanislav Motylkov /* FIXME: return structures for all processors */ 8674c78b2c3SStanislav Motylkov 868c2c66affSColin Finck _SEH2_TRY 869c2c66affSColin Finck { 8704c78b2c3SStanislav Motylkov /* FIXME: some values are hardcoded */ 871c2c66affSColin Finck PowerInformation->Number = 0; 872c2c66affSColin Finck PowerInformation->MaxMhz = 1000; 8734c78b2c3SStanislav Motylkov PowerInformation->CurrentMhz = KeGetCurrentPrcb()->MHz; 874c2c66affSColin Finck PowerInformation->MhzLimit = 1000; 875c2c66affSColin Finck PowerInformation->MaxIdleState = 0; 876c2c66affSColin Finck PowerInformation->CurrentIdleState = 0; 877c2c66affSColin Finck 878c2c66affSColin Finck Status = STATUS_SUCCESS; 879c2c66affSColin Finck } 880c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 881c2c66affSColin Finck { 882c2c66affSColin Finck Status = _SEH2_GetExceptionCode(); 883c2c66affSColin Finck } 884c2c66affSColin Finck _SEH2_END; 885c2c66affSColin Finck 886c2c66affSColin Finck break; 887c2c66affSColin Finck } 888c2c66affSColin Finck 889c2c66affSColin Finck default: 890c2c66affSColin Finck Status = STATUS_NOT_IMPLEMENTED; 891c2c66affSColin Finck DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n", 892c2c66affSColin Finck PowerInformationLevel); 893c2c66affSColin Finck break; 894c2c66affSColin Finck } 895c2c66affSColin Finck 896c2c66affSColin Finck return Status; 897c2c66affSColin Finck } 898c2c66affSColin Finck 899c2c66affSColin Finck NTSTATUS 900c2c66affSColin Finck NTAPI 901c2c66affSColin Finck NtGetDevicePowerState(IN HANDLE Device, 902c2c66affSColin Finck IN PDEVICE_POWER_STATE PowerState) 903c2c66affSColin Finck { 904c2c66affSColin Finck UNIMPLEMENTED; 905c2c66affSColin Finck return STATUS_NOT_IMPLEMENTED; 906c2c66affSColin Finck } 907c2c66affSColin Finck 908c2c66affSColin Finck BOOLEAN 909c2c66affSColin Finck NTAPI 910c2c66affSColin Finck NtIsSystemResumeAutomatic(VOID) 911c2c66affSColin Finck { 912c2c66affSColin Finck UNIMPLEMENTED; 913c2c66affSColin Finck return FALSE; 914c2c66affSColin Finck } 915c2c66affSColin Finck 916c2c66affSColin Finck NTSTATUS 917c2c66affSColin Finck NTAPI 918c2c66affSColin Finck NtRequestWakeupLatency(IN LATENCY_TIME Latency) 919c2c66affSColin Finck { 920c2c66affSColin Finck UNIMPLEMENTED; 921c2c66affSColin Finck return STATUS_NOT_IMPLEMENTED; 922c2c66affSColin Finck } 923c2c66affSColin Finck 924c2c66affSColin Finck NTSTATUS 925c2c66affSColin Finck NTAPI 926c2c66affSColin Finck NtSetThreadExecutionState(IN EXECUTION_STATE esFlags, 927c2c66affSColin Finck OUT EXECUTION_STATE *PreviousFlags) 928c2c66affSColin Finck { 929c2c66affSColin Finck PKTHREAD Thread = KeGetCurrentThread(); 930c2c66affSColin Finck KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 931c2c66affSColin Finck EXECUTION_STATE PreviousState; 932c2c66affSColin Finck PAGED_CODE(); 933c2c66affSColin Finck 934c2c66affSColin Finck /* Validate flags */ 935c2c66affSColin Finck if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT)) 936c2c66affSColin Finck { 937c2c66affSColin Finck /* Fail the request */ 938c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 939c2c66affSColin Finck } 940c2c66affSColin Finck 941c2c66affSColin Finck /* Check for user parameters */ 942c2c66affSColin Finck if (PreviousMode != KernelMode) 943c2c66affSColin Finck { 944c2c66affSColin Finck /* Protect the probes */ 945c2c66affSColin Finck _SEH2_TRY 946c2c66affSColin Finck { 947c2c66affSColin Finck /* Check if the pointer is valid */ 948c2c66affSColin Finck ProbeForWriteUlong(PreviousFlags); 949c2c66affSColin Finck } 950c2c66affSColin Finck _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 951c2c66affSColin Finck { 952c2c66affSColin Finck /* It isn't -- fail */ 953c2c66affSColin Finck _SEH2_YIELD(return _SEH2_GetExceptionCode()); 954c2c66affSColin Finck } 955c2c66affSColin Finck _SEH2_END; 956c2c66affSColin Finck } 957c2c66affSColin Finck 958c2c66affSColin Finck /* Save the previous state, always masking in the continous flag */ 959c2c66affSColin Finck PreviousState = Thread->PowerState | ES_CONTINUOUS; 960c2c66affSColin Finck 961c2c66affSColin Finck /* Check if we need to update the power state */ 962c2c66affSColin Finck if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags; 963c2c66affSColin Finck 964c2c66affSColin Finck /* Protect the write back to user mode */ 965c2c66affSColin Finck _SEH2_TRY 966c2c66affSColin Finck { 967c2c66affSColin Finck /* Return the previous flags */ 968c2c66affSColin Finck *PreviousFlags = PreviousState; 969c2c66affSColin Finck } 970c2c66affSColin Finck _SEH2_EXCEPT(ExSystemExceptionFilter()) 971c2c66affSColin Finck { 972c2c66affSColin Finck /* Something's wrong, fail */ 973c2c66affSColin Finck _SEH2_YIELD(return _SEH2_GetExceptionCode()); 974c2c66affSColin Finck } 975c2c66affSColin Finck _SEH2_END; 976c2c66affSColin Finck 977c2c66affSColin Finck /* All is good */ 978c2c66affSColin Finck return STATUS_SUCCESS; 979c2c66affSColin Finck } 980c2c66affSColin Finck 981c2c66affSColin Finck NTSTATUS 982c2c66affSColin Finck NTAPI 983c2c66affSColin Finck NtSetSystemPowerState(IN POWER_ACTION SystemAction, 984c2c66affSColin Finck IN SYSTEM_POWER_STATE MinSystemState, 985c2c66affSColin Finck IN ULONG Flags) 986c2c66affSColin Finck { 987c2c66affSColin Finck KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 988c2c66affSColin Finck POP_POWER_ACTION Action = {0}; 989c2c66affSColin Finck NTSTATUS Status; 990c2c66affSColin Finck ULONG Dummy; 991c2c66affSColin Finck 992c2c66affSColin Finck /* Check for invalid parameter combinations */ 993c2c66affSColin Finck if ((MinSystemState >= PowerSystemMaximum) || 994c2c66affSColin Finck (MinSystemState <= PowerSystemUnspecified) || 995c2c66affSColin Finck (SystemAction > PowerActionWarmEject) || 996c2c66affSColin Finck (SystemAction < PowerActionReserved) || 997c2c66affSColin Finck (Flags & ~(POWER_ACTION_QUERY_ALLOWED | 998c2c66affSColin Finck POWER_ACTION_UI_ALLOWED | 999c2c66affSColin Finck POWER_ACTION_OVERRIDE_APPS | 1000c2c66affSColin Finck POWER_ACTION_LIGHTEST_FIRST | 1001c2c66affSColin Finck POWER_ACTION_LOCK_CONSOLE | 1002c2c66affSColin Finck POWER_ACTION_DISABLE_WAKES | 1003c2c66affSColin Finck POWER_ACTION_CRITICAL))) 1004c2c66affSColin Finck { 1005c2c66affSColin Finck DPRINT1("NtSetSystemPowerState: Bad parameters!\n"); 1006c2c66affSColin Finck DPRINT1(" SystemAction: 0x%x\n", SystemAction); 1007c2c66affSColin Finck DPRINT1(" MinSystemState: 0x%x\n", MinSystemState); 1008c2c66affSColin Finck DPRINT1(" Flags: 0x%x\n", Flags); 1009c2c66affSColin Finck return STATUS_INVALID_PARAMETER; 1010c2c66affSColin Finck } 1011c2c66affSColin Finck 1012c2c66affSColin Finck /* Check for user caller */ 1013c2c66affSColin Finck if (PreviousMode != KernelMode) 1014c2c66affSColin Finck { 1015c2c66affSColin Finck /* Check for shutdown permission */ 1016c2c66affSColin Finck if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode)) 1017c2c66affSColin Finck { 1018c2c66affSColin Finck /* Not granted */ 1019c2c66affSColin Finck DPRINT1("ERROR: Privilege not held for shutdown\n"); 1020c2c66affSColin Finck return STATUS_PRIVILEGE_NOT_HELD; 1021c2c66affSColin Finck } 1022c2c66affSColin Finck 1023c2c66affSColin Finck /* Do it as a kernel-mode caller for consistency with system state */ 1024c2c66affSColin Finck return ZwSetSystemPowerState(SystemAction, MinSystemState, Flags); 1025c2c66affSColin Finck } 1026c2c66affSColin Finck 1027c2c66affSColin Finck /* Read policy settings (partial shutdown vs. full shutdown) */ 1028c2c66affSColin Finck if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy(); 1029c2c66affSColin Finck 1030c2c66affSColin Finck /* Disable lazy flushing of registry */ 1031c2c66affSColin Finck DPRINT("Stopping lazy flush\n"); 1032c2c66affSColin Finck CmSetLazyFlushState(FALSE); 1033c2c66affSColin Finck 1034c2c66affSColin Finck /* Setup the power action */ 1035c2c66affSColin Finck Action.Action = SystemAction; 1036c2c66affSColin Finck Action.Flags = Flags; 1037c2c66affSColin Finck 1038c2c66affSColin Finck /* Notify callbacks */ 1039c2c66affSColin Finck DPRINT("Notifying callbacks\n"); 1040c2c66affSColin Finck ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL); 1041c2c66affSColin Finck 1042c2c66affSColin Finck /* Swap in any worker thread stacks */ 1043c2c66affSColin Finck DPRINT("Swapping worker threads\n"); 1044c2c66affSColin Finck ExSwapinWorkerThreads(FALSE); 1045c2c66affSColin Finck 1046c2c66affSColin Finck /* Make our action global */ 1047c2c66affSColin Finck PopAction = Action; 1048c2c66affSColin Finck 1049c2c66affSColin Finck /* Start power loop */ 1050c2c66affSColin Finck Status = STATUS_CANCELLED; 1051c2c66affSColin Finck while (TRUE) 1052c2c66affSColin Finck { 1053c2c66affSColin Finck /* Break out if there's nothing to do */ 1054c2c66affSColin Finck if (Action.Action == PowerActionNone) break; 1055c2c66affSColin Finck 1056c2c66affSColin Finck /* Check for first-pass or restart */ 1057c2c66affSColin Finck if (Status == STATUS_CANCELLED) 1058c2c66affSColin Finck { 1059c2c66affSColin Finck /* Check for shutdown action */ 1060c2c66affSColin Finck if ((PopAction.Action == PowerActionShutdown) || 1061c2c66affSColin Finck (PopAction.Action == PowerActionShutdownReset) || 1062c2c66affSColin Finck (PopAction.Action == PowerActionShutdownOff)) 1063c2c66affSColin Finck { 1064c2c66affSColin Finck /* Set the action */ 1065c2c66affSColin Finck PopAction.Shutdown = TRUE; 1066c2c66affSColin Finck } 1067c2c66affSColin Finck 1068c2c66affSColin Finck /* Now we are good to go */ 1069c2c66affSColin Finck Status = STATUS_SUCCESS; 1070c2c66affSColin Finck } 1071c2c66affSColin Finck 1072c2c66affSColin Finck /* Check if we're still in an invalid status */ 1073c2c66affSColin Finck if (!NT_SUCCESS(Status)) break; 1074c2c66affSColin Finck 1075c2c66affSColin Finck #ifndef NEWCC 1076c2c66affSColin Finck /* Flush dirty cache pages */ 1077c7ad200fSPierre Schweitzer /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */ 1078c7ad200fSPierre Schweitzer CcRosFlushDirtyPages(-1, &Dummy, FALSE, FALSE); //HACK: We really should wait here! 1079c2c66affSColin Finck #else 1080c2c66affSColin Finck Dummy = 0; 1081c2c66affSColin Finck #endif 1082c2c66affSColin Finck 1083c2c66affSColin Finck /* Flush all volumes and the registry */ 1084c2c66affSColin Finck DPRINT("Flushing volumes, cache flushed %lu pages\n", Dummy); 1085c2c66affSColin Finck PopFlushVolumes(PopAction.Shutdown); 1086c2c66affSColin Finck 1087c2c66affSColin Finck /* Set IRP for drivers */ 1088c2c66affSColin Finck PopAction.IrpMinor = IRP_MN_SET_POWER; 1089c2c66affSColin Finck if (PopAction.Shutdown) 1090c2c66affSColin Finck { 1091c2c66affSColin Finck DPRINT("Queueing shutdown thread\n"); 1092c2c66affSColin Finck /* Check if we are running in the system context */ 1093c2c66affSColin Finck if (PsGetCurrentProcess() != PsInitialSystemProcess) 1094c2c66affSColin Finck { 1095c2c66affSColin Finck /* We're not, so use a worker thread for shutdown */ 1096c2c66affSColin Finck ExInitializeWorkItem(&PopShutdownWorkItem, 1097c2c66affSColin Finck &PopGracefulShutdown, 1098c2c66affSColin Finck NULL); 1099c2c66affSColin Finck 1100c2c66affSColin Finck ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue); 1101c2c66affSColin Finck 1102c2c66affSColin Finck /* Spend us -- when we wake up, the system is good to go down */ 1103c2c66affSColin Finck KeSuspendThread(KeGetCurrentThread()); 1104c2c66affSColin Finck Status = STATUS_SYSTEM_SHUTDOWN; 1105c2c66affSColin Finck goto Exit; 1106c2c66affSColin Finck 1107c2c66affSColin Finck } 1108c2c66affSColin Finck else 1109c2c66affSColin Finck { 1110c2c66affSColin Finck /* Do the shutdown inline */ 1111c2c66affSColin Finck PopGracefulShutdown(NULL); 1112c2c66affSColin Finck } 1113c2c66affSColin Finck } 1114c2c66affSColin Finck 1115c2c66affSColin Finck /* You should not have made it this far */ 11167d6bda16SSerge Gautherie // ASSERTMSG("System is still up and running?!\n", FALSE); 1117c2c66affSColin Finck DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction.Action); 1118c2c66affSColin Finck break; 1119c2c66affSColin Finck } 1120c2c66affSColin Finck 1121c2c66affSColin Finck Exit: 1122c2c66affSColin Finck /* We're done, return */ 1123c2c66affSColin Finck return Status; 1124c2c66affSColin Finck } 1125