/* * AcpiPower.hpp * ACPI device power management: _PSx methods, _PRx power resources, * _DSM calls, and finding the namespace node behind a PCI function * Copyright (c) 2026 Daniel Hammer */ #pragma once #include #include namespace Hal { namespace AcpiPower { // ============================================================================ // PCI <-> ACPI // ============================================================================ // The Device node describing PCI function bus:dev.fn, or -1. When // firmware declares more than one node at the same address (a generic // placeholder plus a vendor SSDT's real one is common for GPUs), the // one carrying power-management objects wins. int32_t FindPciDevice(uint8_t bus, uint8_t dev, uint8_t fn); // Forget the PCI address map built by FindPciDevice (bus numbers may // change across a resume). void InvalidatePciMap(); // True when `device` has a child object named `name` ("_PS3"). bool HasObject(int32_t device, const char* name); // ============================================================================ // Power resources // ============================================================================ static constexpr int MaxResources = 8; // The power resources the device lists in _PR0.._PR3 (deduplicated). int CollectResources(int32_t device, int32_t* out, int max); // _STA of a power resource: 1 on, 0 off, -1 unknown. int ResourceState(int32_t resource); // ============================================================================ // Device power transitions // ============================================================================ struct D3ColdReport { bool RanPs3; int ResourcesOff; // resources whose _OFF was run int ResourcesShared; // left on: some other present device needs them int ResourcesStillOn; // _OFF ran but _STA still says on }; // Put an ACPI device into D3cold the way the spec orders it: _PS3, // then every power resource it depends on off, last-listed first. A // resource that a device outside `owners` also depends on is left // on -- `owners` lists the nodes being powered down together (the // functions of one card and the port above them), which may freely // share, as may anything below them in the namespace. The PCI side // (PMCSR to D3hot) is the caller's to do first. void EnterD3Cold(int32_t device, const int32_t* owners, int ownerCount, D3ColdReport& report); // ============================================================================ // _DSM // ============================================================================ // Evaluate _DSM(uuid, revision, function, arg3) on a device. False // when the device has no _DSM or it failed. bool EvaluateDsm(int32_t device, const uint8_t uuid[16], uint64_t revision, uint64_t function, const AML::Object& arg3, AML::Object& result); // The function bitmap _DSM function 0 reports for (uuid, revision), // 0 when unsupported. Bit 0 set means "some functions exist". uint64_t DsmFunctions(int32_t device, const uint8_t uuid[16], uint64_t revision, const AML::Object& arg3); // Helpers for building _DSM / method arguments. AML::Object IntegerArg(uint64_t value); AML::Object BufferArg(const uint8_t* bytes, uint32_t length); AML::Object EmptyPackageArg(); // Integer value of a method result: an integer as is, a buffer read // little-endian (up to 8 bytes). uint64_t ResultInteger(const AML::Object& result); }; };