Kernel: Fix ACPI _GPE calling
This adds patch adds support for extended GPEs and the second GPE register block.
This commit is contained in:
parent
de7c3d3d29
commit
3aa20a3a32
|
@ -927,42 +927,79 @@ acpi_release_global_lock:
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FIND_GPE(idx) \
|
||||||
|
BAN::Optional<GAS> gpe##idx; \
|
||||||
|
{ \
|
||||||
|
const uint8_t null[sizeof(GAS)] {}; \
|
||||||
|
if (fadt().length > offsetof(FADT, x_gpe##idx##_blk) \
|
||||||
|
&& memcmp(fadt().x_gpe##idx##_blk, null, sizeof(GAS)) == 0) { \
|
||||||
|
auto gas = *reinterpret_cast<GAS*>(fadt().x_gpe##idx##_blk); \
|
||||||
|
if (!gas.read().is_error()) \
|
||||||
|
gpe0 = gas; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
if (!gpe##idx.has_value() && fadt().gpe##idx##_blk) { \
|
||||||
|
gpe##idx = GAS { \
|
||||||
|
.address_space_id = GAS::AddressSpaceID::SystemIO, \
|
||||||
|
.register_bit_width = 8, \
|
||||||
|
.register_bit_offset = 0, \
|
||||||
|
.access_size = 1, \
|
||||||
|
.address = fadt().gpe##idx##_blk, \
|
||||||
|
}; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
FIND_GPE(0);
|
||||||
|
FIND_GPE(1);
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
uint16_t sts_port;
|
uint16_t sts_port;
|
||||||
uint16_t pending;
|
uint16_t pending;
|
||||||
|
|
||||||
sts_port = fadt().pm1a_evt_blk;
|
const auto read_gpe = [this](GAS gpe, uint8_t gpe_blk_len, uint32_t base) -> bool {
|
||||||
if (pending = get_fixed_event(sts_port); pending)
|
for (uint8_t i = 0; i < gpe_blk_len / 2; i++)
|
||||||
goto handle_event;
|
|
||||||
|
|
||||||
sts_port = fadt().pm1b_evt_blk;
|
|
||||||
if (pending = get_fixed_event(sts_port); pending)
|
|
||||||
goto handle_event;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
bool handled_event = false;
|
auto status = ({ auto tmp = gpe; tmp.address += i; tmp; });
|
||||||
uint8_t gpe0_bytes = fadt().gpe0_blk_len / 2;
|
auto enabled = ({ auto tmp = gpe; tmp.address += (gpe_blk_len / 2) + i; tmp; });
|
||||||
for (uint8_t i = 0; i < gpe0_bytes; i++)
|
const uint8_t pending = MUST(status.read()) & MUST(enabled.read());
|
||||||
{
|
|
||||||
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)
|
if (pending == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto index = i * 8 + (pending & ~(pending - 1));
|
for (size_t bit = 0; bit < 8; bit++)
|
||||||
if (m_gpe_methods[index])
|
{
|
||||||
if (auto ret = AML::method_call(m_gpe_scope, m_gpe_methods[index]->node, BAN::Array<AML::Reference*, 7>{}); ret.is_error())
|
if (!(pending & (1 << bit)))
|
||||||
dwarnln("Failed to evaluate _GPE {}: ", index, ret.error());
|
|
||||||
|
|
||||||
handled_event = true;
|
|
||||||
IO::outb(fadt().gpe0_blk + i, 1 << index);
|
|
||||||
}
|
|
||||||
if (handled_event)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
const auto index = base + i * 8 + bit;
|
||||||
|
if (auto* method = m_gpe_methods[index]; method == nullptr)
|
||||||
|
dwarnln("No handler for _GPE {}", index);
|
||||||
|
else if (auto ret = AML::method_call(m_gpe_scope, method->node, BAN::Array<AML::Reference*, 7>{}); ret.is_error())
|
||||||
|
dwarnln("Failed to evaluate _GPE {}: ", index, ret.error());
|
||||||
|
else
|
||||||
|
dprintln("handled _GPE {}", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MUST(status.write(pending));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
sts_port = fadt().pm1a_evt_blk;
|
||||||
|
if ((pending = get_fixed_event(sts_port)))
|
||||||
|
goto handle_event;
|
||||||
|
|
||||||
|
sts_port = fadt().pm1b_evt_blk;
|
||||||
|
if ((pending = get_fixed_event(sts_port)))
|
||||||
|
goto handle_event;
|
||||||
|
|
||||||
|
if (gpe0.has_value() && read_gpe(gpe0.value(), fadt().gpe0_blk_len, 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (gpe1.has_value() && read_gpe(gpe1.value(), fadt().gpe1_blk_len, fadt().gpe1_base))
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in New Issue