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