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