summaryrefslogtreecommitdiff
path: root/sys/dev/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/acpi')
-rw-r--r--sys/dev/acpi/uacpi.c122
1 files changed, 110 insertions, 12 deletions
diff --git a/sys/dev/acpi/uacpi.c b/sys/dev/acpi/uacpi.c
index b133288..6c2bf50 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>
@@ -53,22 +55,96 @@
#include <vm/vm.h>
#include <string.h>
+#define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__)
+#define pr_error(...) pr_trace(__VA_ARGS__)
+
typedef struct {
uacpi_io_addr base;
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 +354,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
@@ -541,25 +636,25 @@ uacpi_init(void)
ret = uacpi_initialize(0);
if (uacpi_unlikely_error(ret)) {
- kprintf("uacpi init error: %s\n", uacpi_status_to_string(ret));
+ pr_error("uacpi init error: %s\n", uacpi_status_to_string(ret));
return -1;
}
ret = uacpi_namespace_load();
if (uacpi_unlikely_error(ret)) {
- kprintf("uacpi namespace load error: %s\n", uacpi_status_to_string(ret));
+ pr_error("uacpi namespace load error: %s\n", uacpi_status_to_string(ret));
return -1;
}
ret = uacpi_namespace_initialize();
if (uacpi_unlikely_error(ret)) {
- kprintf("uacpi namespace init error: %s\n", uacpi_status_to_string(ret));
+ pr_error("uacpi namespace init error: %s\n", uacpi_status_to_string(ret));
return -1;
}
ret = uacpi_finalize_gpe_initialization();
if (uacpi_unlikely_error(ret)) {
- kprintf("uacpi GPE init error: %s\n", uacpi_status_to_string(ret));
+ pr_error("uacpi GPE init error: %s\n", uacpi_status_to_string(ret));
return -1;
}
@@ -569,11 +664,14 @@ uacpi_init(void)
);
if (uacpi_unlikely_error(ret)) {
- kprintf("failed to install power button event: %s\n",
+ pr_error("failed to install power button event: %s\n",
uacpi_status_to_string(ret)
);
return -1;
}
+ TAILQ_INIT(&acpi_gpe_eventq);
+ TAILQ_INIT(&acpi_notify_eventq);
+ spawn(&g_proc0, uacpi_event_td, NULL, 0, &event_td);
return 0;
}