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