Kernel: Add support for ACPI general purpose events
This commit is contained in:
parent
aefb33efff
commit
687fa44eff
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <BAN/Vector.h>
|
#include <BAN/Vector.h>
|
||||||
|
#include <kernel/ACPI/AML/Method.h>
|
||||||
#include <kernel/ACPI/AML/Namespace.h>
|
#include <kernel/ACPI/AML/Namespace.h>
|
||||||
#include <kernel/ACPI/Headers.h>
|
#include <kernel/ACPI/Headers.h>
|
||||||
#include <kernel/Memory/Types.h>
|
#include <kernel/Memory/Types.h>
|
||||||
|
@ -57,7 +58,8 @@ namespace Kernel::ACPI
|
||||||
|
|
||||||
FADT* m_fadt { nullptr };
|
FADT* m_fadt { nullptr };
|
||||||
|
|
||||||
Semaphore m_acpi_event_semaphore;
|
Semaphore m_event_semaphore;
|
||||||
|
BAN::Array<BAN::RefPtr<AML::Method>, 0xFF> m_gpe_methods;
|
||||||
|
|
||||||
bool m_hardware_reduced { false };
|
bool m_hardware_reduced { false };
|
||||||
BAN::RefPtr<AML::Namespace> m_namespace;
|
BAN::RefPtr<AML::Namespace> m_namespace;
|
||||||
|
|
|
@ -503,6 +503,59 @@ acpi_release_global_lock:
|
||||||
dwarnln("Could not enable ACPI interrupt: {}", ret.error());
|
dwarnln("Could not enable ACPI interrupt: {}", ret.error());
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
auto hex_sv_to_int =
|
||||||
|
[](BAN::StringView sv) -> BAN::Optional<uint32_t>
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
for (char c : sv)
|
||||||
|
{
|
||||||
|
ret <<= 4;
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
ret += c - '0';
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
ret += c - 'A' + 10;
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
ret += c - 'a' + 10;
|
||||||
|
else
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (fadt().gpe0_blk)
|
||||||
|
{
|
||||||
|
// Enable all events in _GPE (_Lxx or _Exx)
|
||||||
|
m_namespace->for_each_child(AML::NameString("\\_GPE"),
|
||||||
|
[&](const auto& path, auto& node)
|
||||||
|
{
|
||||||
|
if (node->type != AML::Node::Type::Method)
|
||||||
|
return;
|
||||||
|
if (path.size() < 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto name = path.sv().substring(path.size() - 4);
|
||||||
|
if (name.substring(0, 2) != "_L"sv && name.substring(0, 2) != "_E"sv)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto index = hex_sv_to_int(name.substring(2));
|
||||||
|
if (!index.has_value())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto byte = index.value() / 8;
|
||||||
|
auto bit = index.value() % 8;
|
||||||
|
auto gpe0_en_port = fadt().gpe0_blk + (fadt().gpe0_blk_len / 2) + byte;
|
||||||
|
IO::outb(gpe0_en_port, IO::inb(gpe0_en_port) | (1 << bit));
|
||||||
|
|
||||||
|
auto* method = static_cast<AML::Method*>(node.ptr());
|
||||||
|
m_gpe_methods[index.value()] = method;
|
||||||
|
|
||||||
|
dprintln("Enabled GPE {}", index.value(), byte, bit);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
set_irq(irq);
|
set_irq(irq);
|
||||||
enable_interrupt();
|
enable_interrupt();
|
||||||
Process::create_kernel([](void*) { get().acpi_event_task(); }, nullptr);
|
Process::create_kernel([](void*) { get().acpi_event_task(); }, nullptr);
|
||||||
|
@ -538,14 +591,38 @@ acpi_release_global_lock:
|
||||||
if (pending = get_fixed_event(sts_port); pending)
|
if (pending = get_fixed_event(sts_port); pending)
|
||||||
goto handle_event;
|
goto handle_event;
|
||||||
|
|
||||||
|
{
|
||||||
|
bool handled_event = false;
|
||||||
|
uint8_t gpe0_bytes = fadt().gpe0_blk_len / 2;
|
||||||
|
for (uint8_t i = 0; i < gpe0_bytes; i++)
|
||||||
|
{
|
||||||
|
uint8_t sts = IO::inb(fadt().gpe0_blk + i);
|
||||||
|
uint8_t en = IO::inb(fadt().gpe0_blk + gpe0_bytes + i);
|
||||||
|
pending = sts & en;
|
||||||
|
if (pending == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto index = i * 8 + (pending & ~(pending - 1));
|
||||||
|
if (m_gpe_methods[index])
|
||||||
|
m_gpe_methods[index]->invoke();
|
||||||
|
|
||||||
|
handled_event = true;
|
||||||
|
IO::outb(fadt().gpe0_blk + i, 1 << index);
|
||||||
|
}
|
||||||
|
if (handled_event)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// FIXME: this can cause missing of event if it happens between
|
// FIXME: this can cause missing of event if it happens between
|
||||||
// reading the status and blocking
|
// reading the status and blocking
|
||||||
m_acpi_event_semaphore.block_with_timeout(100);
|
m_event_semaphore.block_with_timeout(100);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
handle_event:
|
handle_event:
|
||||||
if (pending & PM1_EVN_PWRBTN)
|
if (pending & PM1_EVN_PWRBTN)
|
||||||
{
|
{
|
||||||
|
dprintln("Power button pressed");
|
||||||
if (auto ret = Process::clean_poweroff(POWEROFF_SHUTDOWN); ret.is_error())
|
if (auto ret = Process::clean_poweroff(POWEROFF_SHUTDOWN); ret.is_error())
|
||||||
dwarnln("Failed to poweroff: {}", ret.error());
|
dwarnln("Failed to poweroff: {}", ret.error());
|
||||||
}
|
}
|
||||||
|
@ -560,7 +637,7 @@ handle_event:
|
||||||
|
|
||||||
void ACPI::handle_irq()
|
void ACPI::handle_irq()
|
||||||
{
|
{
|
||||||
m_acpi_event_semaphore.unblock();
|
m_event_semaphore.unblock();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue