fix: add backlight modulation support for hybrid graphics laptops

This commit is contained in:
daniel committed 2026-10-02 14:54:00 +02:00
1 parent 7979acc2eb
commit f9e21e0f13
6 files changed
+381 -12

No files matched your search

+127
View File
@@ -0,0 +1,127 @@
/*
* 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 <ACPI/AML/AmlInterpreter.hpp>
#include <Libraries/Memory.hpp>
#include <CppLib/Stream.hpp>
#include <Terminal/Terminal.hpp>
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);
}
};
};