4#include "pedigree/kernel/Atomic.h"
5#include "pedigree/kernel/LockGuard.h"
6#include "pedigree/kernel/Log.h"
7#include "pedigree/kernel/machine/IrqHandler.h"
8#include "pedigree/kernel/machine/IrqManager.h"
9#include "pedigree/kernel/machine/Machine.h"
10#include "pedigree/kernel/process/ConditionVariable.h"
11#include "pedigree/kernel/process/CpuAffinity.h"
12#include "pedigree/kernel/process/Mutex.h"
13#include "pedigree/kernel/utilities/RequestQueue.h"
14#include "pedigree/kernel/utilities/new"
16#include <uacpi/kernel_api.h>
19static_assert(
sizeof(uacpi_work_handler) <=
sizeof(uint64_t));
20static_assert(
sizeof(uacpi_handle) <=
sizeof(uint64_t));
24 AcpiWorkQueue() :
RequestQueue(MakeConstantString(
"uACPI events")) {}
26 ~AcpiWorkQueue()
override {
33 placement.allowed.set(0);
37 uint64_t
executeRequest(uint64_t p1, uint64_t p2, uint64_t, uint64_t, uint64_t, uint64_t,
38 uint64_t, uint64_t)
override {
39 auto handler =
reinterpret_cast<uacpi_work_handler
>(
static_cast<uintptr_t
>(p1));
40 auto context =
reinterpret_cast<uacpi_handle
>(
static_cast<uintptr_t
>(p2));
48struct AcpiEventsState {
51 AcpiIrqHandler* handlers =
nullptr;
52 size_t activeCallbacks = 0;
57AcpiEventsState g_Events;
61 AcpiIrqHandler(uacpi_interrupt_handler callback, uacpi_handle context)
62 : callback(callback), context(context) {}
64 ~AcpiIrqHandler()
override =
default;
69 ++g_Events.activeCallbacks;
72 const uacpi_interrupt_ret result = callback(context);
76 --g_Events.activeCallbacks;
77 if (!g_Events.activeCallbacks) {
78 g_Events.callbackDone.broadcast();
82 return result & UACPI_INTERRUPT_HANDLED ? IrqDisposition::Handled : IrqDisposition::NotHandled;
85 uacpi_interrupt_handler callback;
88 AcpiIrqHandler* next =
nullptr;
89 bool removing =
false;
93bool initialiseAcpiEvents() {
94 if (g_Events.ready.value()) {
98 g_Events.work.initialise();
99 if (g_Events.work.getLifecycleState() != RequestQueue::LifecycleState::Accepting) {
107extern "C" uacpi_status uacpi_kernel_install_interrupt_handler(uacpi_u32 irq,
108 uacpi_interrupt_handler callback,
109 uacpi_handle context,
110 uacpi_handle* out_irq_handle) {
111 if (!callback || !out_irq_handle) {
112 return UACPI_STATUS_INVALID_ARGUMENT;
114 *out_irq_handle =
nullptr;
118 ERROR(
"uACPI: unsupported interrupt GSI " <<
Dec << irq);
119 return UACPI_STATUS_UNIMPLEMENTED;
122 if (!g_Events.ready.value()) {
123 return UACPI_STATUS_INIT_LEVEL_MISMATCH;
126 IrqManager* manager = Machine::instance().getIrqManager();
128 return UACPI_STATUS_UNIMPLEMENTED;
131 auto* handler =
new AcpiIrqHandler(callback, context);
133 return UACPI_STATUS_OUT_OF_MEMORY;
138 handler->next = g_Events.handlers;
139 g_Events.handlers = handler;
143 IrqPolicy::levelThreaded());
146 AcpiIrqHandler** link = &g_Events.handlers;
147 while (*link != handler) {
148 link = &(*link)->next;
150 *link = handler->next;
152 return UACPI_STATUS_INTERNAL_ERROR;
155 *out_irq_handle = handler;
156 return UACPI_STATUS_OK;
159extern "C" uacpi_status uacpi_kernel_uninstall_interrupt_handler(uacpi_interrupt_handler callback,
160 uacpi_handle irq_handle) {
161 AcpiIrqHandler* handler =
nullptr;
164 for (AcpiIrqHandler* current = g_Events.handlers; current; current = current->next) {
165 if (current == irq_handle) {
166 if (current->callback != callback || current->removing || !current->id) {
167 return UACPI_STATUS_INVALID_ARGUMENT;
169 current->removing =
true;
176 return UACPI_STATUS_INVALID_ARGUMENT;
179 IrqManager* manager = Machine::instance().getIrqManager();
182 handler->removing =
false;
183 return UACPI_STATUS_INTERNAL_ERROR;
188 AcpiIrqHandler** link = &g_Events.handlers;
189 while (*link != handler) {
190 link = &(*link)->next;
192 *link = handler->next;
195 return UACPI_STATUS_OK;
198extern "C" uacpi_status uacpi_kernel_schedule_work(uacpi_work_type type, uacpi_work_handler handler,
199 uacpi_handle context) {
200 if ((type != UACPI_WORK_GPE_EXECUTION && type != UACPI_WORK_NOTIFICATION) || !handler) {
201 return UACPI_STATUS_INVALID_ARGUMENT;
203 if (!g_Events.ready.value()) {
204 return UACPI_STATUS_INIT_LEVEL_MISMATCH;
208 return g_Events.work.publishAsyncRequest(0,
reinterpret_cast<uintptr_t
>(handler),
209 reinterpret_cast<uintptr_t
>(context))
211 : UACPI_STATUS_INTERNAL_ERROR;
214extern "C" uacpi_status uacpi_kernel_wait_for_work_completion() {
215 if (!g_Events.ready.value()) {
216 return UACPI_STATUS_INIT_LEVEL_MISMATCH;
218 if (!g_Events.work.canWaitForCompletion()) {
219 return UACPI_STATUS_INVALID_ARGUMENT;
224 while (g_Events.activeCallbacks) {
225 g_Events.callbackDone.waitForCompletion(g_Events.mutex);
229 return g_Events.work.drain() ? UACPI_STATUS_OK : UACPI_STATUS_INTERNAL_ERROR;
232bool shutdownAcpiEvents() {
233 if (!g_Events.ready.value()) {
240 AcpiIrqHandler* handler;
243 handler = g_Events.handlers;
248 if (uacpi_kernel_uninstall_interrupt_handler(handler->callback, handler) != UACPI_STATUS_OK) {
252 if (!g_Events.work.drain()) {
256 g_Events.work.destroy();
virtual IrqDisposition irq(irq_id_t number)=0
virtual irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, const IrqPolicy &policy)=0
virtual bool unregisterHandler(irq_id_t Id, IrqHandlerBase *handler)=0
virtual uint64_t executeRequest(uint64_t p1, uint64_t p2, uint64_t p3, uint64_t p4, uint64_t p5, uint64_t p6, uint64_t p7, uint64_t p8)=0