Files
my-os-project2/kernel/hal/x86_64/uACPI/source/notify.c
2025-08-17 18:37:57 +02:00

256 lines
6.7 KiB
C

#include <uacpi/internal/notify.h>
#include <uacpi/internal/shareable.h>
#include <uacpi/internal/namespace.h>
#include <uacpi/internal/log.h>
#include <uacpi/internal/mutex.h>
#include <uacpi/internal/utilities.h>
#include <uacpi/internal/stdlib.h>
#include <uacpi/kernel_api.h>
#ifndef UACPI_BAREBONES_MODE
static uacpi_handle notify_mutex;
uacpi_status uacpi_initialize_notify(void)
{
notify_mutex = uacpi_kernel_create_mutex();
if (uacpi_unlikely(notify_mutex == UACPI_NULL))
return UACPI_STATUS_OUT_OF_MEMORY;
return UACPI_STATUS_OK;
}
void uacpi_deinitialize_notify(void)
{
if (notify_mutex != UACPI_NULL)
uacpi_kernel_free_mutex(notify_mutex);
notify_mutex = UACPI_NULL;
}
struct notification_ctx {
uacpi_namespace_node *node;
uacpi_u64 value;
uacpi_object *node_object;
};
static void free_notification_ctx(struct notification_ctx *ctx)
{
uacpi_namespace_node_release_object(ctx->node_object);
uacpi_namespace_node_unref(ctx->node);
uacpi_free(ctx, sizeof(*ctx));
}
static void do_notify(uacpi_handle opaque)
{
struct notification_ctx *ctx = opaque;
uacpi_device_notify_handler *handler;
uacpi_bool did_notify_root = UACPI_FALSE;
handler = ctx->node_object->handlers->notify_head;
for (;;) {
if (handler == UACPI_NULL) {
if (did_notify_root) {
free_notification_ctx(ctx);
return;
}
handler = g_uacpi_rt_ctx.root_object->handlers->notify_head;
did_notify_root = UACPI_TRUE;
continue;
}
handler->callback(handler->user_context, ctx->node, ctx->value);
handler = handler->next;
}
}
uacpi_status uacpi_notify_all(uacpi_namespace_node *node, uacpi_u64 value)
{
uacpi_status ret;
struct notification_ctx *ctx;
uacpi_object *node_object;
node_object = uacpi_namespace_node_get_object_typed(
node, UACPI_OBJECT_DEVICE_BIT | UACPI_OBJECT_THERMAL_ZONE_BIT |
UACPI_OBJECT_PROCESSOR_BIT
);
if (uacpi_unlikely(node_object == UACPI_NULL))
return UACPI_STATUS_INVALID_ARGUMENT;
ret = uacpi_acquire_native_mutex(notify_mutex);
if (uacpi_unlikely_error(ret))
return ret;
if (node_object->handlers->notify_head == UACPI_NULL &&
g_uacpi_rt_ctx.root_object->handlers->notify_head == UACPI_NULL) {
ret = UACPI_STATUS_NO_HANDLER;
goto out;
}
ctx = uacpi_kernel_alloc(sizeof(*ctx));
if (uacpi_unlikely(ctx == UACPI_NULL)) {
ret = UACPI_STATUS_OUT_OF_MEMORY;
goto out;
}
ctx->node = node;
// In case this node goes out of scope
uacpi_shareable_ref(node);
ctx->value = value;
ctx->node_object = uacpi_namespace_node_get_object(node);
uacpi_object_ref(ctx->node_object);
ret = uacpi_kernel_schedule_work(UACPI_WORK_NOTIFICATION, do_notify, ctx);
if (uacpi_unlikely_error(ret)) {
uacpi_warn("unable to schedule notification work: %s\n",
uacpi_status_to_string(ret));
free_notification_ctx(ctx);
}
out:
uacpi_release_native_mutex(notify_mutex);
return ret;
}
static uacpi_device_notify_handler *handler_container(
uacpi_handlers *handlers, uacpi_notify_handler target_handler
)
{
uacpi_device_notify_handler *handler = handlers->notify_head;
while (handler) {
if (handler->callback == target_handler)
return handler;
handler = handler->next;
}
return UACPI_NULL;
}
uacpi_status uacpi_install_notify_handler(
uacpi_namespace_node *node, uacpi_notify_handler handler,
uacpi_handle handler_context
)
{
uacpi_status ret;
uacpi_object *obj;
uacpi_handlers *handlers;
uacpi_device_notify_handler *new_handler;
UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED);
if (node == uacpi_namespace_root()) {
obj = g_uacpi_rt_ctx.root_object;
} else {
ret = uacpi_namespace_node_acquire_object_typed(
node, UACPI_OBJECT_DEVICE_BIT | UACPI_OBJECT_THERMAL_ZONE_BIT |
UACPI_OBJECT_PROCESSOR_BIT, &obj
);
if (uacpi_unlikely_error(ret))
return ret;
}
ret = uacpi_acquire_native_mutex(notify_mutex);
if (uacpi_unlikely_error(ret))
goto out_no_mutex;
uacpi_kernel_wait_for_work_completion();
handlers = obj->handlers;
if (handler_container(handlers, handler) != UACPI_NULL) {
ret = UACPI_STATUS_ALREADY_EXISTS;
goto out;
}
new_handler = uacpi_kernel_alloc_zeroed(sizeof(*new_handler));
if (uacpi_unlikely(new_handler == UACPI_NULL))
return UACPI_STATUS_OUT_OF_MEMORY;
new_handler->callback = handler;
new_handler->user_context = handler_context;
new_handler->next = handlers->notify_head;
handlers->notify_head = new_handler;
out:
uacpi_release_native_mutex(notify_mutex);
out_no_mutex:
if (node != uacpi_namespace_root())
uacpi_object_unref(obj);
return ret;
}
uacpi_status uacpi_uninstall_notify_handler(
uacpi_namespace_node *node, uacpi_notify_handler handler
)
{
uacpi_status ret;
uacpi_object *obj;
uacpi_handlers *handlers;
uacpi_device_notify_handler *prev_handler, *containing = UACPI_NULL;
UACPI_ENSURE_INIT_LEVEL_AT_LEAST(UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED);
if (node == uacpi_namespace_root()) {
obj = g_uacpi_rt_ctx.root_object;
} else {
ret = uacpi_namespace_node_acquire_object_typed(
node, UACPI_OBJECT_DEVICE_BIT | UACPI_OBJECT_THERMAL_ZONE_BIT |
UACPI_OBJECT_PROCESSOR_BIT, &obj
);
if (uacpi_unlikely_error(ret))
return ret;
}
ret = uacpi_acquire_native_mutex(notify_mutex);
if (uacpi_unlikely_error(ret))
goto out_no_mutex;
uacpi_kernel_wait_for_work_completion();
handlers = obj->handlers;
containing = handler_container(handlers, handler);
if (containing == UACPI_NULL) {
ret = UACPI_STATUS_NOT_FOUND;
goto out;
}
prev_handler = handlers->notify_head;
// Are we the last linked handler?
if (prev_handler == containing) {
handlers->notify_head = containing->next;
goto out;
}
// Nope, we're somewhere in the middle. Do a search.
while (prev_handler) {
if (prev_handler->next == containing) {
prev_handler->next = containing->next;
goto out;
}
prev_handler = prev_handler->next;
}
out:
uacpi_release_native_mutex(notify_mutex);
out_no_mutex:
if (node != uacpi_namespace_root())
uacpi_object_unref(obj);
if (uacpi_likely_success(ret))
uacpi_free(containing, sizeof(*containing));
return ret;
}
#endif // !UACPI_BAREBONES_MODE