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 NULL, 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 NULL, 425 &NotificationEntry); 426 return NT_SUCCESS(Status); 427 } 428 429 /* Initialize the power capabilities */ 430 RtlZeroMemory(&PopCapabilities, sizeof(SYSTEM_POWER_CAPABILITIES)); 431 432 /* Get the Command Line */ 433 CommandLine = KeLoaderBlock->LoadOptions; 434 435 /* Upcase it */ 436 _strupr(CommandLine); 437 438 /* Check for ACPI disable */ 439 if (strstr(CommandLine, "NOACPI")) ForceAcpiDisable = TRUE; 440 441 if (ForceAcpiDisable) 442 { 443 /* Set the ACPI State to False if it's been forced that way */ 444 PopAcpiPresent = FALSE; 445 } 446 else 447 { 448 /* Otherwise check if the LoaderBlock has a ACPI Table */ 449 PopAcpiPresent = KeLoaderBlock->Extension->AcpiTable != NULL ? TRUE : FALSE; 450 } 451 452 /* Enable shutdown by power button */ 453 if (PopAcpiPresent) 454 PopCapabilities.SystemS5 = TRUE; 455 456 /* Initialize volume support */ 457 InitializeListHead(&PopVolumeDevices); 458 KeInitializeGuardedMutex(&PopVolumeLock); 459 460 /* Initialize support for dope */ 461 KeInitializeSpinLock(&PopDopeGlobalLock); 462 463 /* Initialize support for shutdown waits and work-items */ 464 PopInitShutdownList(); 465 466 return TRUE; 467 } 468 469 VOID 470 NTAPI 471 PopPerfIdle(PPROCESSOR_POWER_STATE PowerState) 472 { 473 DPRINT1("PerfIdle function: %p\n", PowerState); 474 } 475 476 VOID 477 NTAPI 478 PopPerfIdleDpc(IN PKDPC Dpc, 479 IN PVOID DeferredContext, 480 IN PVOID SystemArgument1, 481 IN PVOID SystemArgument2) 482 { 483 /* Call the Perf Idle function */ 484 PopPerfIdle(&((PKPRCB)DeferredContext)->PowerState); 485 } 486 487 VOID 488 FASTCALL 489 PopIdle0(IN PPROCESSOR_POWER_STATE PowerState) 490 { 491 /* FIXME: Extremly naive implementation */ 492 HalProcessorIdle(); 493 } 494 495 CODE_SEG("INIT") 496 VOID 497 NTAPI 498 PoInitializePrcb(IN PKPRCB Prcb) 499 { 500 /* Initialize the Power State */ 501 RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState)); 502 Prcb->PowerState.Idle0KernelTimeLimit = 0xFFFFFFFF; 503 Prcb->PowerState.CurrentThrottle = 100; 504 Prcb->PowerState.CurrentThrottleIndex = 0; 505 Prcb->PowerState.IdleFunction = PopIdle0; 506 507 /* Initialize the Perf DPC and Timer */ 508 KeInitializeDpc(&Prcb->PowerState.PerfDpc, PopPerfIdleDpc, Prcb); 509 KeSetTargetProcessorDpc(&Prcb->PowerState.PerfDpc, Prcb->Number); 510 KeInitializeTimerEx(&Prcb->PowerState.PerfTimer, SynchronizationTimer); 511 } 512 513 /* PUBLIC FUNCTIONS **********************************************************/ 514 515 /* 516 * @unimplemented 517 */ 518 NTSTATUS 519 NTAPI 520 PoCancelDeviceNotify(IN PVOID NotifyBlock) 521 { 522 UNIMPLEMENTED; 523 return STATUS_NOT_IMPLEMENTED; 524 } 525 526 /* 527 * @unimplemented 528 */ 529 NTSTATUS 530 NTAPI 531 PoRegisterDeviceNotify(OUT PVOID Unknown0, 532 IN ULONG Unknown1, 533 IN ULONG Unknown2, 534 IN ULONG Unknown3, 535 IN PVOID Unknown4, 536 IN PVOID Unknown5) 537 { 538 UNIMPLEMENTED; 539 return STATUS_NOT_IMPLEMENTED; 540 } 541 542 /* 543 * @unimplemented 544 */ 545 VOID 546 NTAPI 547 PoShutdownBugCheck(IN BOOLEAN LogError, 548 IN ULONG BugCheckCode, 549 IN ULONG_PTR BugCheckParameter1, 550 IN ULONG_PTR BugCheckParameter2, 551 IN ULONG_PTR BugCheckParameter3, 552 IN ULONG_PTR BugCheckParameter4) 553 { 554 DPRINT1("PoShutdownBugCheck called\n"); 555 556 /* FIXME: Log error if requested */ 557 /* FIXME: Initiate a shutdown */ 558 559 /* Bugcheck the system */ 560 KeBugCheckEx(BugCheckCode, 561 BugCheckParameter1, 562 BugCheckParameter2, 563 BugCheckParameter3, 564 BugCheckParameter4); 565 } 566 567 /* 568 * @unimplemented 569 */ 570 VOID 571 NTAPI 572 PoSetHiberRange(IN PVOID HiberContext, 573 IN ULONG Flags, 574 IN OUT PVOID StartPage, 575 IN ULONG Length, 576 IN ULONG PageTag) 577 { 578 UNIMPLEMENTED; 579 return; 580 } 581 582 /* 583 * @implemented 584 */ 585 _IRQL_requires_max_(DISPATCH_LEVEL) 586 NTSTATUS 587 NTAPI 588 PoCallDriver( 589 _In_ PDEVICE_OBJECT DeviceObject, 590 _Inout_ __drv_aliasesMem PIRP Irp) 591 { 592 PIO_STACK_LOCATION NextStack; 593 594 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 595 596 ASSERT(DeviceObject); 597 ASSERT(Irp); 598 599 NextStack = IoGetNextIrpStackLocation(Irp); 600 ASSERT(NextStack->MajorFunction == IRP_MJ_POWER); 601 602 /* Set DeviceObject for PopPresentIrp */ 603 NextStack->DeviceObject = DeviceObject; 604 605 /* Only QUERY_POWER and SET_POWER use special handling */ 606 if (NextStack->MinorFunction != IRP_MN_SET_POWER && 607 NextStack->MinorFunction != IRP_MN_QUERY_POWER) 608 { 609 return IoCallDriver(DeviceObject, Irp); 610 } 611 612 /* Call the next driver, either directly or at PASSIVE_LEVEL */ 613 return PopPresentIrp(NextStack, Irp); 614 } 615 616 /* 617 * @unimplemented 618 */ 619 PULONG 620 NTAPI 621 PoRegisterDeviceForIdleDetection(IN PDEVICE_OBJECT DeviceObject, 622 IN ULONG ConservationIdleTime, 623 IN ULONG PerformanceIdleTime, 624 IN DEVICE_POWER_STATE State) 625 { 626 UNIMPLEMENTED; 627 return NULL; 628 } 629 630 /* 631 * @unimplemented 632 */ 633 PVOID 634 NTAPI 635 PoRegisterSystemState(IN PVOID StateHandle, 636 IN EXECUTION_STATE Flags) 637 { 638 UNIMPLEMENTED; 639 return NULL; 640 } 641 642 /* 643 * @implemented 644 */ 645 NTSTATUS 646 NTAPI 647 PoRequestPowerIrp( 648 _In_ PDEVICE_OBJECT DeviceObject, 649 _In_ UCHAR MinorFunction, 650 _In_ POWER_STATE PowerState, 651 _In_opt_ PREQUEST_POWER_COMPLETE CompletionFunction, 652 _In_opt_ __drv_aliasesMem PVOID Context, 653 _Outptr_opt_ PIRP *pIrp) 654 { 655 PDEVICE_OBJECT TopDeviceObject; 656 PIO_STACK_LOCATION Stack; 657 PIRP Irp; 658 659 if (MinorFunction != IRP_MN_QUERY_POWER 660 && MinorFunction != IRP_MN_SET_POWER 661 && MinorFunction != IRP_MN_WAIT_WAKE) 662 return STATUS_INVALID_PARAMETER_2; 663 664 /* Always call the top of the device stack */ 665 TopDeviceObject = IoGetAttachedDeviceReference(DeviceObject); 666 667 Irp = IoAllocateIrp(TopDeviceObject->StackSize + 2, FALSE); 668 if (!Irp) 669 { 670 ObDereferenceObject(TopDeviceObject); 671 return STATUS_INSUFFICIENT_RESOURCES; 672 } 673 674 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 675 Irp->IoStatus.Information = 0; 676 677 IoSetNextIrpStackLocation(Irp); 678 679 Stack = IoGetNextIrpStackLocation(Irp); 680 Stack->Parameters.Others.Argument1 = DeviceObject; 681 Stack->Parameters.Others.Argument2 = (PVOID)(ULONG_PTR)MinorFunction; 682 Stack->Parameters.Others.Argument3 = (PVOID)(ULONG_PTR)PowerState.DeviceState; 683 Stack->Parameters.Others.Argument4 = Context; 684 Stack->DeviceObject = TopDeviceObject; 685 IoSetNextIrpStackLocation(Irp); 686 687 Stack = IoGetNextIrpStackLocation(Irp); 688 Stack->MajorFunction = IRP_MJ_POWER; 689 Stack->MinorFunction = MinorFunction; 690 if (MinorFunction == IRP_MN_WAIT_WAKE) 691 { 692 Stack->Parameters.WaitWake.PowerState = PowerState.SystemState; 693 } 694 else 695 { 696 Stack->Parameters.Power.Type = DevicePowerState; 697 Stack->Parameters.Power.State = PowerState; 698 } 699 700 if (pIrp != NULL) 701 *pIrp = Irp; 702 703 IoSetCompletionRoutine(Irp, PopRequestPowerIrpCompletion, CompletionFunction, TRUE, TRUE, TRUE); 704 PoCallDriver(TopDeviceObject, Irp); 705 706 /* Always return STATUS_PENDING. The completion routine 707 * will call CompletionFunction and complete the Irp. 708 */ 709 return STATUS_PENDING; 710 } 711 712 /* 713 * @unimplemented 714 */ 715 POWER_STATE 716 NTAPI 717 PoSetPowerState(IN PDEVICE_OBJECT DeviceObject, 718 IN POWER_STATE_TYPE Type, 719 IN POWER_STATE State) 720 { 721 POWER_STATE ps; 722 723 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 724 725 ps.SystemState = PowerSystemWorking; // Fully on 726 ps.DeviceState = PowerDeviceD0; // Fully on 727 728 return ps; 729 } 730 731 /* 732 * @unimplemented 733 */ 734 VOID 735 NTAPI 736 PoSetSystemState(IN EXECUTION_STATE Flags) 737 { 738 UNIMPLEMENTED; 739 } 740 741 /* 742 * @unimplemented 743 */ 744 VOID 745 NTAPI 746 PoStartNextPowerIrp(IN PIRP Irp) 747 { 748 UNIMPLEMENTED_ONCE; 749 } 750 751 /* 752 * @unimplemented 753 */ 754 VOID 755 NTAPI 756 PoUnregisterSystemState(IN PVOID StateHandle) 757 { 758 UNIMPLEMENTED; 759 } 760 761 /* 762 * @unimplemented 763 */ 764 NTSTATUS 765 NTAPI 766 NtInitiatePowerAction(IN POWER_ACTION SystemAction, 767 IN SYSTEM_POWER_STATE MinSystemState, 768 IN ULONG Flags, 769 IN BOOLEAN Asynchronous) 770 { 771 UNIMPLEMENTED; 772 return STATUS_NOT_IMPLEMENTED; 773 } 774 775 /* 776 * @unimplemented 777 */ 778 NTSTATUS 779 NTAPI 780 NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel, 781 IN PVOID InputBuffer OPTIONAL, 782 IN ULONG InputBufferLength, 783 OUT PVOID OutputBuffer OPTIONAL, 784 IN ULONG OutputBufferLength) 785 { 786 NTSTATUS Status; 787 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 788 789 PAGED_CODE(); 790 791 DPRINT("NtPowerInformation(PowerInformationLevel 0x%x, InputBuffer 0x%p, " 792 "InputBufferLength 0x%x, OutputBuffer 0x%p, OutputBufferLength 0x%x)\n", 793 PowerInformationLevel, 794 InputBuffer, InputBufferLength, 795 OutputBuffer, OutputBufferLength); 796 797 if (PreviousMode != KernelMode) 798 { 799 _SEH2_TRY 800 { 801 ProbeForRead(InputBuffer, InputBufferLength, 1); 802 ProbeForWrite(OutputBuffer, OutputBufferLength, sizeof(ULONG)); 803 } 804 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 805 { 806 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 807 } 808 _SEH2_END; 809 } 810 811 switch (PowerInformationLevel) 812 { 813 case SystemBatteryState: 814 { 815 PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer; 816 817 if (InputBuffer != NULL) 818 return STATUS_INVALID_PARAMETER; 819 if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE)) 820 return STATUS_BUFFER_TOO_SMALL; 821 822 _SEH2_TRY 823 { 824 /* Just zero the struct (and thus set BatteryState->BatteryPresent = FALSE) */ 825 RtlZeroMemory(BatteryState, sizeof(SYSTEM_BATTERY_STATE)); 826 BatteryState->EstimatedTime = MAXULONG; 827 // BatteryState->AcOnLine = TRUE; 828 829 Status = STATUS_SUCCESS; 830 } 831 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 832 { 833 Status = _SEH2_GetExceptionCode(); 834 } 835 _SEH2_END; 836 837 break; 838 } 839 840 case SystemPowerCapabilities: 841 { 842 PSYSTEM_POWER_CAPABILITIES PowerCapabilities = (PSYSTEM_POWER_CAPABILITIES)OutputBuffer; 843 844 if (InputBuffer != NULL) 845 return STATUS_INVALID_PARAMETER; 846 if (OutputBufferLength < sizeof(SYSTEM_POWER_CAPABILITIES)) 847 return STATUS_BUFFER_TOO_SMALL; 848 849 _SEH2_TRY 850 { 851 RtlCopyMemory(PowerCapabilities, 852 &PopCapabilities, 853 sizeof(SYSTEM_POWER_CAPABILITIES)); 854 855 Status = STATUS_SUCCESS; 856 } 857 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 858 { 859 Status = _SEH2_GetExceptionCode(); 860 } 861 _SEH2_END; 862 863 break; 864 } 865 866 case ProcessorInformation: 867 { 868 PPROCESSOR_POWER_INFORMATION PowerInformation = (PPROCESSOR_POWER_INFORMATION)OutputBuffer; 869 870 if (InputBuffer != NULL) 871 return STATUS_INVALID_PARAMETER; 872 if (OutputBufferLength < sizeof(PROCESSOR_POWER_INFORMATION)) 873 return STATUS_BUFFER_TOO_SMALL; 874 875 /* FIXME: return structures for all processors */ 876 877 _SEH2_TRY 878 { 879 /* FIXME: some values are hardcoded */ 880 PowerInformation->Number = 0; 881 PowerInformation->MaxMhz = 1000; 882 PowerInformation->CurrentMhz = KeGetCurrentPrcb()->MHz; 883 PowerInformation->MhzLimit = 1000; 884 PowerInformation->MaxIdleState = 0; 885 PowerInformation->CurrentIdleState = 0; 886 887 Status = STATUS_SUCCESS; 888 } 889 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 890 { 891 Status = _SEH2_GetExceptionCode(); 892 } 893 _SEH2_END; 894 895 break; 896 } 897 898 default: 899 Status = STATUS_NOT_IMPLEMENTED; 900 DPRINT1("PowerInformationLevel 0x%x is UNIMPLEMENTED! Have a nice day.\n", 901 PowerInformationLevel); 902 break; 903 } 904 905 return Status; 906 } 907 908 NTSTATUS 909 NTAPI 910 NtGetDevicePowerState(IN HANDLE Device, 911 IN PDEVICE_POWER_STATE PowerState) 912 { 913 UNIMPLEMENTED; 914 return STATUS_NOT_IMPLEMENTED; 915 } 916 917 BOOLEAN 918 NTAPI 919 NtIsSystemResumeAutomatic(VOID) 920 { 921 UNIMPLEMENTED; 922 return FALSE; 923 } 924 925 NTSTATUS 926 NTAPI 927 NtRequestWakeupLatency(IN LATENCY_TIME Latency) 928 { 929 UNIMPLEMENTED; 930 return STATUS_NOT_IMPLEMENTED; 931 } 932 933 NTSTATUS 934 NTAPI 935 NtSetThreadExecutionState(IN EXECUTION_STATE esFlags, 936 OUT EXECUTION_STATE *PreviousFlags) 937 { 938 PKTHREAD Thread = KeGetCurrentThread(); 939 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 940 EXECUTION_STATE PreviousState; 941 PAGED_CODE(); 942 943 /* Validate flags */ 944 if (esFlags & ~(ES_CONTINUOUS | ES_USER_PRESENT)) 945 { 946 /* Fail the request */ 947 return STATUS_INVALID_PARAMETER; 948 } 949 950 /* Check for user parameters */ 951 if (PreviousMode != KernelMode) 952 { 953 /* Protect the probes */ 954 _SEH2_TRY 955 { 956 /* Check if the pointer is valid */ 957 ProbeForWriteUlong(PreviousFlags); 958 } 959 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 960 { 961 /* It isn't -- fail */ 962 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 963 } 964 _SEH2_END; 965 } 966 967 /* Save the previous state, always masking in the continous flag */ 968 PreviousState = Thread->PowerState | ES_CONTINUOUS; 969 970 /* Check if we need to update the power state */ 971 if (esFlags & ES_CONTINUOUS) Thread->PowerState = (UCHAR)esFlags; 972 973 /* Protect the write back to user mode */ 974 _SEH2_TRY 975 { 976 /* Return the previous flags */ 977 *PreviousFlags = PreviousState; 978 } 979 _SEH2_EXCEPT(ExSystemExceptionFilter()) 980 { 981 /* Something's wrong, fail */ 982 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 983 } 984 _SEH2_END; 985 986 /* All is good */ 987 return STATUS_SUCCESS; 988 } 989 990 NTSTATUS 991 NTAPI 992 NtSetSystemPowerState(IN POWER_ACTION SystemAction, 993 IN SYSTEM_POWER_STATE MinSystemState, 994 IN ULONG Flags) 995 { 996 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); 997 POP_POWER_ACTION Action = {0}; 998 NTSTATUS Status; 999 ULONG Dummy; 1000 1001 /* Check for invalid parameter combinations */ 1002 if ((MinSystemState >= PowerSystemMaximum) || 1003 (MinSystemState <= PowerSystemUnspecified) || 1004 (SystemAction > PowerActionWarmEject) || 1005 (SystemAction < PowerActionReserved) || 1006 (Flags & ~(POWER_ACTION_QUERY_ALLOWED | 1007 POWER_ACTION_UI_ALLOWED | 1008 POWER_ACTION_OVERRIDE_APPS | 1009 POWER_ACTION_LIGHTEST_FIRST | 1010 POWER_ACTION_LOCK_CONSOLE | 1011 POWER_ACTION_DISABLE_WAKES | 1012 POWER_ACTION_CRITICAL))) 1013 { 1014 DPRINT1("NtSetSystemPowerState: Bad parameters!\n"); 1015 DPRINT1(" SystemAction: 0x%x\n", SystemAction); 1016 DPRINT1(" MinSystemState: 0x%x\n", MinSystemState); 1017 DPRINT1(" Flags: 0x%x\n", Flags); 1018 return STATUS_INVALID_PARAMETER; 1019 } 1020 1021 /* Check for user caller */ 1022 if (PreviousMode != KernelMode) 1023 { 1024 /* Check for shutdown permission */ 1025 if (!SeSinglePrivilegeCheck(SeShutdownPrivilege, PreviousMode)) 1026 { 1027 /* Not granted */ 1028 DPRINT1("ERROR: Privilege not held for shutdown\n"); 1029 return STATUS_PRIVILEGE_NOT_HELD; 1030 } 1031 1032 /* Do it as a kernel-mode caller for consistency with system state */ 1033 return ZwSetSystemPowerState(SystemAction, MinSystemState, Flags); 1034 } 1035 1036 /* Read policy settings (partial shutdown vs. full shutdown) */ 1037 if (SystemAction == PowerActionShutdown) PopReadShutdownPolicy(); 1038 1039 /* Disable lazy flushing of registry */ 1040 DPRINT("Stopping lazy flush\n"); 1041 CmSetLazyFlushState(FALSE); 1042 1043 /* Setup the power action */ 1044 Action.Action = SystemAction; 1045 Action.Flags = Flags; 1046 1047 /* Notify callbacks */ 1048 DPRINT("Notifying callbacks\n"); 1049 ExNotifyCallback(PowerStateCallback, (PVOID)3, NULL); 1050 1051 /* Swap in any worker thread stacks */ 1052 DPRINT("Swapping worker threads\n"); 1053 ExSwapinWorkerThreads(FALSE); 1054 1055 /* Make our action global */ 1056 PopAction = Action; 1057 1058 /* Start power loop */ 1059 Status = STATUS_CANCELLED; 1060 while (TRUE) 1061 { 1062 /* Break out if there's nothing to do */ 1063 if (Action.Action == PowerActionNone) break; 1064 1065 /* Check for first-pass or restart */ 1066 if (Status == STATUS_CANCELLED) 1067 { 1068 /* Check for shutdown action */ 1069 if ((PopAction.Action == PowerActionShutdown) || 1070 (PopAction.Action == PowerActionShutdownReset) || 1071 (PopAction.Action == PowerActionShutdownOff)) 1072 { 1073 /* Set the action */ 1074 PopAction.Shutdown = TRUE; 1075 } 1076 1077 /* Now we are good to go */ 1078 Status = STATUS_SUCCESS; 1079 } 1080 1081 /* Check if we're still in an invalid status */ 1082 if (!NT_SUCCESS(Status)) break; 1083 1084 /* Flush all volumes and the registry */ 1085 DPRINT("Flushing volumes\n"); 1086 PopFlushVolumes(PopAction.Shutdown); 1087 1088 #ifndef NEWCC 1089 /* Flush dirty cache pages */ 1090 /* XXX: Is that still mandatory? As now we'll wait on lazy writer to complete? */ 1091 CcRosFlushDirtyPages(MAXULONG, &Dummy, TRUE, FALSE); 1092 DPRINT("Cache flushed %lu pages\n", Dummy); 1093 #else 1094 Dummy = 0; 1095 #endif 1096 1097 /* Set IRP for drivers */ 1098 PopAction.IrpMinor = IRP_MN_SET_POWER; 1099 if (PopAction.Shutdown) 1100 { 1101 DPRINT("Queueing shutdown thread\n"); 1102 /* Check if we are running in the system context */ 1103 if (PsGetCurrentProcess() != PsInitialSystemProcess) 1104 { 1105 /* We're not, so use a worker thread for shutdown */ 1106 ExInitializeWorkItem(&PopShutdownWorkItem, 1107 &PopGracefulShutdown, 1108 NULL); 1109 1110 ExQueueWorkItem(&PopShutdownWorkItem, CriticalWorkQueue); 1111 1112 /* Spend us -- when we wake up, the system is good to go down */ 1113 KeSuspendThread(KeGetCurrentThread()); 1114 Status = STATUS_SYSTEM_SHUTDOWN; 1115 goto Exit; 1116 1117 } 1118 else 1119 { 1120 /* Do the shutdown inline */ 1121 PopGracefulShutdown(NULL); 1122 } 1123 } 1124 1125 /* You should not have made it this far */ 1126 // ASSERTMSG("System is still up and running?!\n", FALSE); 1127 DPRINT1("System is still up and running, you may not have chosen a yet supported power option: %u\n", PopAction.Action); 1128 break; 1129 } 1130 1131 Exit: 1132 /* We're done, return */ 1133 return Status; 1134 } 1135