diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/acpi/uacpi.c | 109 |
1 files changed, 102 insertions, 7 deletions
diff --git a/sys/dev/acpi/uacpi.c b/sys/dev/acpi/uacpi.c index b133288..ffec436 100644 --- a/sys/dev/acpi/uacpi.c +++ b/sys/dev/acpi/uacpi.c @@ -32,6 +32,8 @@ #include <sys/param.h> #include <sys/syslog.h> #include <sys/panic.h> +#include <sys/proc.h> +#include <sys/queue.h> #include <dev/timer.h> #include <uacpi/kernel_api.h> #include <uacpi/platform/arch_helpers.h> @@ -58,17 +60,88 @@ typedef struct { uacpi_size length; } io_range_t; +struct uacpi_work { + uacpi_work_handler hand; + uacpi_handle ctx; + TAILQ_ENTRY(uacpi_work) link; +}; + +uacpi_status +uacpi_kernel_schedule_work(uacpi_work_type type, uacpi_work_handler h, uacpi_handle ctx); + +extern struct proc g_proc0; + +static struct proc *event_td; +static TAILQ_HEAD(, uacpi_work) acpi_gpe_eventq; +static TAILQ_HEAD(, uacpi_work) acpi_notify_eventq; + /* - * TODO: Schedule a system shutdown + * Dispatch ACPI general purpose events from + * hardware. */ -static uacpi_interrupt_ret -power_button_handler(uacpi_handle ctx) +static void +uacpi_gpe_dispatch(void) +{ + struct uacpi_work *work; + + work = TAILQ_FIRST(&acpi_gpe_eventq); + if (work == NULL) { + return; + } + + work->hand(work->ctx); + TAILQ_REMOVE(&acpi_gpe_eventq, work, link); + dynfree(work); +} + +/* + * Dispatch ACPI general notify events. + */ +static void +uacpi_notify_dispatch(void) +{ + struct uacpi_work *work; + + work = TAILQ_FIRST(&acpi_notify_eventq); + if (work == NULL) { + return; + } + + work->hand(work->ctx); + TAILQ_REMOVE(&acpi_gpe_eventq, work, link); + dynfree(work); +} + +static void +uacpi_event_td(void) +{ + for (;;) { + uacpi_gpe_dispatch(); + uacpi_notify_dispatch(); + sched_yield(); + } +} + +static void +shutdown(uacpi_handle ctx) { - md_intoff(); kprintf("power button pressed\n"); kprintf("halting machine...\n"); cpu_halt_all(); - return UACPI_INTERRUPT_HANDLED; +} + +static uacpi_interrupt_ret +power_button_handler(uacpi_handle ctx) +{ + md_intoff(); + uacpi_kernel_schedule_work(UACPI_WORK_GPE_EXECUTION, shutdown, NULL); + md_inton(); + + for (;;) { + md_hlt(); + } + + __builtin_unreachable(); } void * @@ -278,9 +351,28 @@ uacpi_kernel_uninstall_interrupt_handler([[maybe_unused]] uacpi_interrupt_handle } uacpi_status -uacpi_kernel_schedule_work(uacpi_work_type, uacpi_work_handler, uacpi_handle ctx) +uacpi_kernel_schedule_work(uacpi_work_type type, uacpi_work_handler h, uacpi_handle ctx) { - return UACPI_STATUS_UNIMPLEMENTED; + struct uacpi_work *work; + + work = dynalloc(sizeof(*work)); + if (work == NULL) { + return UACPI_STATUS_OUT_OF_MEMORY; + } + + work->hand = h; + work->ctx = ctx; + + switch (type) { + case UACPI_WORK_GPE_EXECUTION: + TAILQ_INSERT_TAIL(&acpi_gpe_eventq, work, link); + break; + case UACPI_WORK_NOTIFICATION: + TAILQ_INSERT_TAIL(&acpi_notify_eventq, work, link); + break; + } + + return 0; } uacpi_status @@ -575,5 +667,8 @@ uacpi_init(void) return -1; } + TAILQ_INIT(&acpi_gpe_eventq); + TAILQ_INIT(&acpi_notify_eventq); + spawn(&g_proc0, uacpi_event_td, NULL, 0, &event_td); return 0; } |