/* * AcpiWmi.cpp * ACPI-WMI mapper (PNP0C14): find a WMI GUID's data block in _WDG and call * its WMxx method * Copyright (c) 2026 Daniel Hammer */ #include "AcpiWmi.hpp" #include "AcpiDevices.hpp" #include #include #include #include using namespace Kt; namespace Hal { namespace AcpiWmi { static constexpr const char* HidWmi = "PNP0C14"; static constexpr uint32_t WdgEntrySize = 20; // GUID, id, count, flags static int HexDigit(char c) { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } bool ParseGuid(const char* text, uint8_t out[16]) { // Bytes in text order, then the first three fields byte-swapped. uint8_t bytes[16]; int count = 0; for (int i = 0; text[i]; i++) { if (text[i] == '-') continue; int hi = HexDigit(text[i]); int lo = text[i + 1] ? HexDigit(text[i + 1]) : -1; if (hi < 0 || lo < 0 || count == 16) return false; bytes[count++] = (uint8_t)(hi << 4 | lo); i++; } if (count != 16) return false; static constexpr int order[16] = {3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15}; for (int i = 0; i < 16; i++) out[i] = bytes[order[i]]; return true; } static bool SearchDevice(int32_t device, const uint8_t guid[16], Block& out) { auto& interp = AML::GetInterpreter(); AML::Object wdg{}; if (!interp.EvaluateChild(device, "_WDG", nullptr, 0, wdg) || wdg.Type != AML::ObjectType::Buffer) return false; // The interpreter caps buffers; a _WDG that fills the cap may have // lost entries past it. if (wdg.Buffer.Length >= (uint32_t)AML::MaxBufferLen) { char path[128]; interp.GetNamespace().GetNodePath(device, path, sizeof(path)); KernelLogStream(WARNING, "WMI") << path << "._WDG may be truncated (" << base::dec << (uint64_t)wdg.Buffer.Length << " bytes read)"; } for (uint32_t off = 0; off + WdgEntrySize <= wdg.Buffer.Length; off += WdgEntrySize) { const uint8_t* entry = wdg.Buffer.Data + off; if (memcmp(entry, guid, 16) != 0) continue; out.Device = device; out.ObjectId[0] = (char)entry[16]; out.ObjectId[1] = (char)entry[17]; out.InstanceCount = entry[18]; out.Flags = entry[19]; return true; } return false; } bool Find(const uint8_t guid[16], Block& out) { auto& interp = AML::GetInterpreter(); if (!interp.IsInitialized()) return false; auto& ns = interp.GetNamespace(); bool found = false; ns.WalkDescendants(ns.RootIndex(), AML::ObjectType::Device, [&](int32_t idx, const AML::NamespaceNode*) { if (found) return; char hid[16]; if (!AcpiDevices::EvaluateHid(idx, hid, sizeof(hid))) return; if (memcmp(hid, HidWmi, sizeof("PNP0C14")) != 0) return; if (!(AcpiDevices::EvaluateSta(idx) & AcpiDevices::STA_PRESENT)) return; found = SearchDevice(idx, guid, out); }); return found; } bool EvaluateMethod(const Block& block, uint8_t instance, uint32_t methodId, const uint8_t* input, uint32_t inputLength, AML::Object& result) { if (!(block.Flags & FlagMethod) || instance >= block.InstanceCount) return false; AML::Object args[3]; args[0].Type = AML::ObjectType::Integer; args[0].Integer = instance; args[1].Type = AML::ObjectType::Integer; args[1].Integer = methodId; if (block.Flags & FlagString) { uint32_t n = inputLength; if (n >= (uint32_t)AML::MaxStringLen) n = AML::MaxStringLen - 1; args[2].Type = AML::ObjectType::String; if (n) memcpy(args[2].String.Data, input, n); args[2].String.Data[n] = '\0'; args[2].String.Length = (uint16_t)n; } else { uint32_t n = inputLength; if (n > (uint32_t)AML::MaxBufferLen) n = AML::MaxBufferLen; args[2].Type = AML::ObjectType::Buffer; if (n) memcpy(args[2].Buffer.Data, input, n); args[2].Buffer.Length = n; } char method[5] = {'W', 'M', block.ObjectId[0], block.ObjectId[1], '\0'}; return AML::GetInterpreter().EvaluateChild(block.Device, method, args, 3, result); } }; };