#define EXPORT_ACPI_INTERFACES
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
#include "acevents.h"
#include "acinterp.h"
#define _COMPONENT …
ACPI_MODULE_NAME("evxface")
#if (!ACPI_REDUCED_HARDWARE)
static acpi_status
acpi_ev_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
u32 type,
u8 is_raw_handler,
acpi_gpe_handler address, void *context);
#endif
acpi_status
acpi_install_notify_handler(acpi_handle device,
u32 handler_type,
acpi_notify_handler handler, void *context)
{ … }
ACPI_EXPORT_SYMBOL(…)
acpi_status
acpi_remove_notify_handler(acpi_handle device,
u32 handler_type, acpi_notify_handler handler)
{ … }
ACPI_EXPORT_SYMBOL(…)
#ifdef ACPI_FUTURE_USAGE
acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
{
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (acpi_gbl_exception_handler) {
status = AE_ALREADY_EXISTS;
goto cleanup;
}
acpi_gbl_exception_handler = handler;
cleanup:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
#endif
#if (!ACPI_REDUCED_HARDWARE)
acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context)
{
struct acpi_sci_handler_info *new_sci_handler;
struct acpi_sci_handler_info *sci_handler;
acpi_cpu_flags flags;
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_install_sci_handler);
if (!address) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
new_sci_handler = ACPI_ALLOCATE(sizeof(struct acpi_sci_handler_info));
if (!new_sci_handler) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
new_sci_handler->address = address;
new_sci_handler->context = context;
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
goto exit;
}
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
sci_handler = acpi_gbl_sci_handler_list;
while (sci_handler) {
if (address == sci_handler->address) {
status = AE_ALREADY_EXISTS;
goto unlock_and_exit;
}
sci_handler = sci_handler->next;
}
new_sci_handler->next = acpi_gbl_sci_handler_list;
acpi_gbl_sci_handler_list = new_sci_handler;
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
exit:
if (ACPI_FAILURE(status)) {
ACPI_FREE(new_sci_handler);
}
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_install_sci_handler)
acpi_status acpi_remove_sci_handler(acpi_sci_handler address)
{
struct acpi_sci_handler_info *prev_sci_handler;
struct acpi_sci_handler_info *next_sci_handler;
acpi_cpu_flags flags;
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_remove_sci_handler);
if (!address) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
prev_sci_handler = NULL;
next_sci_handler = acpi_gbl_sci_handler_list;
while (next_sci_handler) {
if (next_sci_handler->address == address) {
if (prev_sci_handler) {
prev_sci_handler->next = next_sci_handler->next;
} else {
acpi_gbl_sci_handler_list =
next_sci_handler->next;
}
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
ACPI_FREE(next_sci_handler);
goto unlock_and_exit;
}
prev_sci_handler = next_sci_handler;
next_sci_handler = next_sci_handler->next;
}
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
status = AE_NOT_EXIST;
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)
acpi_status
acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context)
{
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
if (!handler) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (acpi_gbl_global_event_handler) {
status = AE_ALREADY_EXISTS;
goto cleanup;
}
acpi_gbl_global_event_handler = handler;
acpi_gbl_global_event_handler_context = context;
cleanup:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
acpi_status
acpi_install_fixed_event_handler(u32 event,
acpi_event_handler handler, void *context)
{
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
if (event > ACPI_EVENT_MAX) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
if (acpi_gbl_fixed_event_handlers[event].handler) {
status = AE_ALREADY_EXISTS;
goto cleanup;
}
acpi_gbl_fixed_event_handlers[event].handler = handler;
acpi_gbl_fixed_event_handlers[event].context = context;
status = acpi_clear_event(event);
if (ACPI_SUCCESS(status))
status = acpi_enable_event(event, 0);
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO,
"Could not enable fixed event - %s (%u)",
acpi_ut_get_event_name(event), event));
acpi_gbl_fixed_event_handlers[event].handler = NULL;
acpi_gbl_fixed_event_handlers[event].context = NULL;
} else {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Enabled fixed event %s (%X), Handler=%p\n",
acpi_ut_get_event_name(event), event,
handler));
}
cleanup:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
acpi_status
acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
{
acpi_status status = AE_OK;
ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
if (event > ACPI_EVENT_MAX) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
status = acpi_disable_event(event, 0);
acpi_gbl_fixed_event_handlers[event].handler = NULL;
acpi_gbl_fixed_event_handlers[event].context = NULL;
if (ACPI_FAILURE(status)) {
ACPI_WARNING((AE_INFO,
"Could not disable fixed event - %s (%u)",
acpi_ut_get_event_name(event), event));
} else {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Disabled fixed event - %s (%X)\n",
acpi_ut_get_event_name(event), event));
}
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
static acpi_status
acpi_ev_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
u32 type,
u8 is_raw_handler,
acpi_gpe_handler address, void *context)
{
struct acpi_gpe_event_info *gpe_event_info;
struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
ACPI_FUNCTION_TRACE(ev_install_gpe_handler);
if ((!address) || (type & ~ACPI_GPE_XRUPT_TYPE_MASK)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
if (!handler) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
}
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
if (!gpe_event_info) {
status = AE_BAD_PARAMETER;
goto free_and_exit;
}
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_HANDLER) ||
(ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_RAW_HANDLER)) {
status = AE_ALREADY_EXISTS;
goto free_and_exit;
}
handler->address = address;
handler->context = context;
handler->method_node = gpe_event_info->dispatch.method_node;
handler->original_flags = (u8)(gpe_event_info->flags &
(ACPI_GPE_XRUPT_TYPE_MASK |
ACPI_GPE_DISPATCH_MASK));
if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
ACPI_GPE_DISPATCH_METHOD) ||
(ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) {
handler->originally_enabled = TRUE;
(void)acpi_ev_remove_gpe_reference(gpe_event_info);
if (type !=
(u32)(gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK)) {
ACPI_WARNING((AE_INFO,
"GPE type mismatch (level/edge)"));
}
}
gpe_event_info->dispatch.handler = handler;
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
gpe_event_info->flags |=
(u8)(type |
(is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER :
ACPI_GPE_DISPATCH_HANDLER));
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
free_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
ACPI_FREE(handler);
goto unlock_and_exit;
}
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
u32 type, acpi_gpe_handler address, void *context)
{
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type,
FALSE, address, context);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
acpi_status
acpi_install_gpe_raw_handler(acpi_handle gpe_device,
u32 gpe_number,
u32 type, acpi_gpe_handler address, void *context)
{
acpi_status status;
ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler);
status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type,
TRUE, address, context);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler)
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
u32 gpe_number, acpi_gpe_handler address)
{
struct acpi_gpe_event_info *gpe_event_info;
struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
ACPI_FUNCTION_TRACE(acpi_remove_gpe_handler);
if (!address) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
if (!gpe_event_info) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_HANDLER) &&
(ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_RAW_HANDLER)) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
if (gpe_event_info->dispatch.handler->address != address) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
handler = gpe_event_info->dispatch.handler;
gpe_event_info->dispatch.handler = NULL;
gpe_event_info->dispatch.method_node = handler->method_node;
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
gpe_event_info->flags |= handler->original_flags;
if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
ACPI_GPE_DISPATCH_METHOD) ||
(ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
(void)acpi_ev_add_gpe_reference(gpe_event_info, FALSE);
if (ACPI_GPE_IS_POLLING_NEEDED(gpe_event_info)) {
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
(void)acpi_ev_detect_gpe(gpe_device, gpe_event_info,
gpe_number);
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
}
}
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
acpi_os_wait_events_complete();
ACPI_FREE(handler);
return_ACPI_STATUS(status);
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
(void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
acpi_status acpi_acquire_global_lock(u16 timeout, u32 *handle)
{
acpi_status status;
if (!handle) {
return (AE_BAD_PARAMETER);
}
acpi_ex_enter_interpreter();
status = acpi_ex_acquire_mutex_object(timeout,
acpi_gbl_global_lock_mutex,
acpi_os_get_thread_id());
if (ACPI_SUCCESS(status)) {
*handle = acpi_gbl_global_lock_handle;
}
acpi_ex_exit_interpreter();
return (status);
}
ACPI_EXPORT_SYMBOL(acpi_acquire_global_lock)
acpi_status acpi_release_global_lock(u32 handle)
{
acpi_status status;
if (!handle || (handle != acpi_gbl_global_lock_handle)) {
return (AE_NOT_ACQUIRED);
}
status = acpi_ex_release_mutex_object(acpi_gbl_global_lock_mutex);
return (status);
}
ACPI_EXPORT_SYMBOL(acpi_release_global_lock)
#endif