aboutsummaryrefslogtreecommitdiff
path: root/drivers/acpi/acpica/evxface.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/evxface.c')
-rw-r--r--drivers/acpi/acpica/evxface.c950
1 files changed, 509 insertions, 441 deletions
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 36af222cac6..11e5803b8b4 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2010, Intel Corp.
+ * Copyright (C) 2000 - 2014, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -41,6 +41,8 @@
* POSSIBILITY OF SUCH DAMAGES.
*/
+#define EXPORT_ACPI_INTERFACES
+
#include <acpi/acpi.h>
#include "accommon.h"
#include "acnamesp.h"
@@ -50,606 +52,668 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxface")
+
/*******************************************************************************
*
- * FUNCTION: acpi_install_exception_handler
+ * FUNCTION: acpi_install_notify_handler
*
- * PARAMETERS: Handler - Pointer to the handler function for the
- * event
+ * PARAMETERS: device - The device for which notifies will be handled
+ * handler_type - The type of handler:
+ * ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
+ * ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
+ * ACPI_ALL_NOTIFY: Both System and Device
+ * handler - Address of the handler
+ * context - Value passed to the handler on each GPE
*
* RETURN: Status
*
- * DESCRIPTION: Saves the pointer to the handler function
+ * DESCRIPTION: Install a handler for notifications on an ACPI Device,
+ * thermal_zone, or Processor object.
+ *
+ * NOTES: The Root namespace object may have only one handler for each
+ * type of notify (System/Device). Device/Thermal/Processor objects
+ * may have one device notify handler, and multiple system notify
+ * handlers.
*
******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
-acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
+acpi_status
+acpi_install_notify_handler(acpi_handle device,
+ u32 handler_type,
+ acpi_notify_handler handler, void *context)
{
+ struct acpi_namespace_node *node =
+ ACPI_CAST_PTR(struct acpi_namespace_node, device);
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj;
acpi_status status;
+ u32 i;
- ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
+ ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ /* Parameter validation */
+
+ if ((!device) || (!handler) || (!handler_type) ||
+ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
- /* Don't allow two handlers. */
+ /*
+ * Root Object:
+ * Registering a notify handler on the root object indicates that the
+ * caller wishes to receive notifications for all objects. Note that
+ * only one global handler can be registered per notify type.
+ * Ensure that a handler is not already installed.
+ */
+ if (device == ACPI_ROOT_OBJECT) {
+ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+ if (handler_type & (i + 1)) {
+ if (acpi_gbl_global_notify[i].handler) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
- if (acpi_gbl_exception_handler) {
- status = AE_ALREADY_EXISTS;
- goto cleanup;
+ acpi_gbl_global_notify[i].handler = handler;
+ acpi_gbl_global_notify[i].context = context;
+ }
+ }
+
+ goto unlock_and_exit; /* Global notify handler installed, all done */
}
- /* Install the handler */
+ /*
+ * All Other Objects:
+ * Caller will only receive notifications specific to the target
+ * object. Note that only certain object types are allowed to
+ * receive notifications.
+ */
- acpi_gbl_exception_handler = handler;
+ /* Are Notifies allowed on this object? */
- cleanup:
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
- return_ACPI_STATUS(status);
-}
+ if (!acpi_ev_is_notify_object(node)) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
-ACPI_EXPORT_SYMBOL(acpi_install_exception_handler)
-#endif /* ACPI_FUTURE_USAGE */
-/*******************************************************************************
- *
- * FUNCTION: acpi_install_fixed_event_handler
- *
- * PARAMETERS: Event - Event type to enable.
- * Handler - Pointer to the handler function for the
- * event
- * Context - Value passed to the handler on each GPE
- *
- * RETURN: Status
- *
- * DESCRIPTION: Saves the pointer to the handler function and then enables the
- * event.
- *
- ******************************************************************************/
-acpi_status
-acpi_install_fixed_event_handler(u32 event,
- acpi_event_handler handler, void *context)
-{
- acpi_status status;
+ /* Check for an existing internal object, might not exist */
- ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
- /* Parameter validation */
+ /* Create a new object */
- if (event > ACPI_EVENT_MAX) {
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ obj_desc = acpi_ut_create_internal_object(node->type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Attach new object to the Node, remove local reference */
+
+ status = acpi_ns_attach_object(device, obj_desc, node->type);
+ acpi_ut_remove_reference(obj_desc);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
}
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Ensure that the handler is not already installed in the lists */
+
+ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+ if (handler_type & (i + 1)) {
+ handler_obj = obj_desc->common_notify.notify_list[i];
+ while (handler_obj) {
+ if (handler_obj->notify.handler == handler) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
+
+ handler_obj = handler_obj->notify.next[i];
+ }
+ }
}
- /* Don't allow two handlers. */
+ /* Create and populate a new notify handler object */
- if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
- status = AE_ALREADY_EXISTS;
- goto cleanup;
+ handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
+ if (!handler_obj) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
}
- /* Install the handler before enabling the event */
+ handler_obj->notify.node = node;
+ handler_obj->notify.handler_type = handler_type;
+ handler_obj->notify.handler = handler;
+ handler_obj->notify.context = context;
- acpi_gbl_fixed_event_handlers[event].handler = handler;
- acpi_gbl_fixed_event_handlers[event].context = context;
+ /* Install the handler at the list head(s) */
- 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 0x%X",
- event));
+ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+ if (handler_type & (i + 1)) {
+ handler_obj->notify.next[i] =
+ obj_desc->common_notify.notify_list[i];
- /* Remove the handler */
+ obj_desc->common_notify.notify_list[i] = handler_obj;
+ }
+ }
- 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 %X, Handler=%p\n", event,
- handler));
+ /* Add an extra reference if handler was installed in both lists */
+
+ if (handler_type == ACPI_ALL_NOTIFY) {
+ acpi_ut_add_reference(handler_obj);
}
- cleanup:
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
+ACPI_EXPORT_SYMBOL(acpi_install_notify_handler)
/*******************************************************************************
*
- * FUNCTION: acpi_remove_fixed_event_handler
+ * FUNCTION: acpi_remove_notify_handler
*
- * PARAMETERS: Event - Event type to disable.
- * Handler - Address of the handler
+ * PARAMETERS: device - The device for which the handler is installed
+ * handler_type - The type of handler:
+ * ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
+ * ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
+ * ACPI_ALL_NOTIFY: Both System and Device
+ * handler - Address of the handler
*
* RETURN: Status
*
- * DESCRIPTION: Disables the event and unregisters the event handler.
+ * DESCRIPTION: Remove a handler for notifies on an ACPI device
*
******************************************************************************/
acpi_status
-acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
+acpi_remove_notify_handler(acpi_handle device,
+ u32 handler_type, acpi_notify_handler handler)
{
+ struct acpi_namespace_node *node =
+ ACPI_CAST_PTR(struct acpi_namespace_node, device);
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj;
+ union acpi_operand_object *previous_handler_obj;
acpi_status status = AE_OK;
+ u32 i;
- ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
+ ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
/* Parameter validation */
- if (event > ACPI_EVENT_MAX) {
+ if ((!device) || (!handler) || (!handler_type) ||
+ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Root Object. Global handlers are removed here */
+
+ if (device == ACPI_ROOT_OBJECT) {
+ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+ if (handler_type & (i + 1)) {
+ status =
+ acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (!acpi_gbl_global_notify[i].handler ||
+ (acpi_gbl_global_notify[i].handler !=
+ handler)) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Removing global notify handler\n"));
+
+ acpi_gbl_global_notify[i].handler = NULL;
+ acpi_gbl_global_notify[i].context = NULL;
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+ /* Make sure all deferred notify tasks are completed */
+
+ acpi_os_wait_events_complete();
+ }
+ }
+
+ return_ACPI_STATUS(AE_OK);
}
- /* Disable the event before removing the handler */
+ /* All other objects: Are Notifies allowed on this object? */
- status = acpi_disable_event(event, 0);
+ if (!acpi_ev_is_notify_object(node)) {
+ return_ACPI_STATUS(AE_TYPE);
+ }
- /* Always Remove the handler */
+ /* Must have an existing internal object */
- acpi_gbl_fixed_event_handlers[event].handler = NULL;
- acpi_gbl_fixed_event_handlers[event].context = NULL;
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (!obj_desc) {
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
- if (ACPI_FAILURE(status)) {
- ACPI_WARNING((AE_INFO,
- "Could not write to fixed event enable register 0x%X",
- event));
- } else {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabled fixed event %X\n",
- event));
+ /* Internal object exists. Find the handler and remove it */
+
+ for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
+ if (handler_type & (i + 1)) {
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ handler_obj = obj_desc->common_notify.notify_list[i];
+ previous_handler_obj = NULL;
+
+ /* Attempt to find the handler in the handler list */
+
+ while (handler_obj &&
+ (handler_obj->notify.handler != handler)) {
+ previous_handler_obj = handler_obj;
+ handler_obj = handler_obj->notify.next[i];
+ }
+
+ if (!handler_obj) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /* Remove the handler object from the list */
+
+ if (previous_handler_obj) { /* Handler is not at the list head */
+ previous_handler_obj->notify.next[i] =
+ handler_obj->notify.next[i];
+ } else { /* Handler is at the list head */
+
+ obj_desc->common_notify.notify_list[i] =
+ handler_obj->notify.next[i];
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+ /* Make sure all deferred notify tasks are completed */
+
+ acpi_os_wait_events_complete();
+ acpi_ut_remove_reference(handler_obj);
+ }
}
- (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
-/*******************************************************************************
- *
- * FUNCTION: acpi_populate_handler_object
- *
- * PARAMETERS: handler_obj - Handler object to populate
- * handler_type - The type of handler:
- * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
- * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
- * ACPI_ALL_NOTIFY: both system and device
- * handler - Address of the handler
- * context - Value passed to the handler on each GPE
- * next - Address of a handler object to link to
- *
- * RETURN: None
- *
- * DESCRIPTION: Populate a handler object.
- *
- ******************************************************************************/
-static void
-acpi_populate_handler_object(struct acpi_object_notify_handler *handler_obj,
- u32 handler_type,
- acpi_notify_handler handler, void *context,
- struct acpi_object_notify_handler *next)
-{
- handler_obj->handler_type = handler_type;
- handler_obj->handler = handler;
- handler_obj->context = context;
- handler_obj->next = next;
+unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
+
/*******************************************************************************
*
- * FUNCTION: acpi_add_handler_object
+ * FUNCTION: acpi_install_exception_handler
*
- * PARAMETERS: parent_obj - Parent of the new object
- * handler - Address of the handler
- * context - Value passed to the handler on each GPE
+ * PARAMETERS: handler - Pointer to the handler function for the
+ * event
*
* RETURN: Status
*
- * DESCRIPTION: Create a new handler object and populate it.
+ * DESCRIPTION: Saves the pointer to the handler function
*
******************************************************************************/
-static acpi_status
-acpi_add_handler_object(struct acpi_object_notify_handler *parent_obj,
- acpi_notify_handler handler, void *context)
+#ifdef ACPI_FUTURE_USAGE
+acpi_status acpi_install_exception_handler(acpi_exception_handler handler)
{
- struct acpi_object_notify_handler *handler_obj;
+ acpi_status status;
- /* The parent must not be a defice notify handler object. */
- if (parent_obj->handler_type & ACPI_DEVICE_NOTIFY)
- return AE_BAD_PARAMETER;
+ ACPI_FUNCTION_TRACE(acpi_install_exception_handler);
- handler_obj = ACPI_ALLOCATE_ZEROED(sizeof(*handler_obj));
- if (!handler_obj)
- return AE_NO_MEMORY;
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Don't allow two handlers. */
+
+ if (acpi_gbl_exception_handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
- acpi_populate_handler_object(handler_obj,
- ACPI_SYSTEM_NOTIFY,
- handler, context,
- parent_obj->next);
- parent_obj->next = handler_obj;
+ /* Install the handler */
- return AE_OK;
+ 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 /* ACPI_FUTURE_USAGE */
+
+#if (!ACPI_REDUCED_HARDWARE)
/*******************************************************************************
*
- * FUNCTION: acpi_install_notify_handler
+ * FUNCTION: acpi_install_sci_handler
*
- * PARAMETERS: Device - The device for which notifies will be handled
- * handler_type - The type of handler:
- * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
- * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
- * ACPI_ALL_NOTIFY: both system and device
- * Handler - Address of the handler
- * Context - Value passed to the handler on each GPE
+ * PARAMETERS: address - Address of the handler
+ * context - Value passed to the handler on each SCI
*
* RETURN: Status
*
- * DESCRIPTION: Install a handler for notifies on an ACPI device
+ * DESCRIPTION: Install a handler for a System Control Interrupt.
*
******************************************************************************/
-acpi_status
-acpi_install_notify_handler(acpi_handle device,
- u32 handler_type,
- acpi_notify_handler handler, void *context)
+acpi_status acpi_install_sci_handler(acpi_sci_handler address, void *context)
{
- union acpi_operand_object *obj_desc;
- union acpi_operand_object *notify_obj;
- struct acpi_namespace_node *node;
+ 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_notify_handler);
-
- /* Parameter validation */
+ ACPI_FUNCTION_TRACE(acpi_install_sci_handler);
- if ((!device) ||
- (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
+ if (!address) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ /* Allocate and init a handler object */
+
+ new_sci_handler = ACPI_ALLOCATE(sizeof(struct acpi_sci_handler_info));
+ if (!new_sci_handler) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
- /* Convert and validate the device handle */
+ new_sci_handler->address = address;
+ new_sci_handler->context = context;
- node = acpi_ns_validate_handle(device);
- if (!node) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ goto exit;
}
- /*
- * Root Object:
- * Registering a notify handler on the root object indicates that the
- * caller wishes to receive notifications for all objects. Note that
- * only one <external> global handler can be regsitered (per notify type).
- */
- if (device == ACPI_ROOT_OBJECT) {
+ /* Lock list during installation */
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+ sci_handler = acpi_gbl_sci_handler_list;
- /* Make sure the handler is not already installed */
+ /* Ensure handler does not already exist */
- if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
- acpi_gbl_system_notify.handler) ||
- ((handler_type & ACPI_DEVICE_NOTIFY) &&
- acpi_gbl_device_notify.handler)) {
+ while (sci_handler) {
+ if (address == sci_handler->address) {
status = AE_ALREADY_EXISTS;
goto unlock_and_exit;
}
- if (handler_type & ACPI_SYSTEM_NOTIFY) {
- acpi_gbl_system_notify.node = node;
- acpi_gbl_system_notify.handler = handler;
- acpi_gbl_system_notify.context = context;
- }
-
- if (handler_type & ACPI_DEVICE_NOTIFY) {
- acpi_gbl_device_notify.node = node;
- acpi_gbl_device_notify.handler = handler;
- acpi_gbl_device_notify.context = context;
- }
-
- /* Global notify handler installed */
+ sci_handler = sci_handler->next;
}
- /*
- * All Other Objects:
- * Caller will only receive notifications specific to the target object.
- * Note that only certain object types can receive notifications.
- */
- else {
- /* Notifies allowed on this object? */
+ /* Install the new handler into the global list (at head) */
- if (!acpi_ev_is_notify_object(node)) {
- status = AE_TYPE;
- goto unlock_and_exit;
- }
+ new_sci_handler->next = acpi_gbl_sci_handler_list;
+ acpi_gbl_sci_handler_list = new_sci_handler;
- /* Check for an existing internal object */
+unlock_and_exit:
- obj_desc = acpi_ns_get_attached_object(node);
- if (obj_desc) {
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
- /* Object exists. */
+exit:
+ if (ACPI_FAILURE(status)) {
+ ACPI_FREE(new_sci_handler);
+ }
+ return_ACPI_STATUS(status);
+}
- /* For a device notify, make sure there's no handler. */
- if ((handler_type & ACPI_DEVICE_NOTIFY) &&
- obj_desc->common_notify.device_notify) {
- status = AE_ALREADY_EXISTS;
- goto unlock_and_exit;
- }
+ACPI_EXPORT_SYMBOL(acpi_install_sci_handler)
- /* System notifies may have more handlers installed. */
- notify_obj = obj_desc->common_notify.system_notify;
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_sci_handler
+ *
+ * PARAMETERS: address - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a handler for a System Control Interrupt.
+ *
+ ******************************************************************************/
+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;
- if ((handler_type & ACPI_SYSTEM_NOTIFY) && notify_obj) {
- struct acpi_object_notify_handler *parent_obj;
+ ACPI_FUNCTION_TRACE(acpi_remove_sci_handler);
- if (handler_type & ACPI_DEVICE_NOTIFY) {
- status = AE_ALREADY_EXISTS;
- goto unlock_and_exit;
- }
+ if (!address) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
- parent_obj = &notify_obj->notify;
- status = acpi_add_handler_object(parent_obj,
- handler,
- context);
- goto unlock_and_exit;
- }
- } else {
- /* Create a new object */
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- obj_desc = acpi_ut_create_internal_object(node->type);
- if (!obj_desc) {
- status = AE_NO_MEMORY;
- goto unlock_and_exit;
- }
+ /* Remove the SCI handler with lock */
- /* Attach new object to the Node */
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
- status =
- acpi_ns_attach_object(device, obj_desc, node->type);
+ prev_sci_handler = NULL;
+ next_sci_handler = acpi_gbl_sci_handler_list;
+ while (next_sci_handler) {
+ if (next_sci_handler->address == address) {
- /* Remove local reference to the object */
+ /* Unlink and free the SCI handler info block */
- acpi_ut_remove_reference(obj_desc);
- if (ACPI_FAILURE(status)) {
- goto unlock_and_exit;
+ if (prev_sci_handler) {
+ prev_sci_handler->next = next_sci_handler->next;
+ } else {
+ acpi_gbl_sci_handler_list =
+ next_sci_handler->next;
}
- }
-
- /* Install the handler */
- notify_obj =
- acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
- if (!notify_obj) {
- status = AE_NO_MEMORY;
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ ACPI_FREE(next_sci_handler);
goto unlock_and_exit;
}
- acpi_populate_handler_object(&notify_obj->notify,
- handler_type,
- handler, context,
- NULL);
+ prev_sci_handler = next_sci_handler;
+ next_sci_handler = next_sci_handler->next;
+ }
- if (handler_type & ACPI_SYSTEM_NOTIFY) {
- obj_desc->common_notify.system_notify = notify_obj;
- }
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ status = AE_NOT_EXIST;
- if (handler_type & ACPI_DEVICE_NOTIFY) {
- obj_desc->common_notify.device_notify = notify_obj;
- }
+unlock_and_exit:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
- if (handler_type == ACPI_ALL_NOTIFY) {
+ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)
- /* Extra ref if installed in both */
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_global_event_handler
+ *
+ * PARAMETERS: handler - Pointer to the global event handler function
+ * context - Value passed to the handler on each event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function. The global handler
+ * is invoked upon each incoming GPE and Fixed Event. It is
+ * invoked at interrupt level at the time of the event dispatch.
+ * Can be used to update event counters, etc.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context)
+{
+ acpi_status status;
- acpi_ut_add_reference(notify_obj);
- }
+ ACPI_FUNCTION_TRACE(acpi_install_global_event_handler);
+
+ /* Parameter validation */
+
+ if (!handler) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ /* Don't allow two handlers. */
+
+ 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_notify_handler)
+ACPI_EXPORT_SYMBOL(acpi_install_global_event_handler)
/*******************************************************************************
*
- * FUNCTION: acpi_remove_notify_handler
+ * FUNCTION: acpi_install_fixed_event_handler
*
- * PARAMETERS: Device - The device for which notifies will be handled
- * handler_type - The type of handler:
- * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
- * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
- * ACPI_ALL_NOTIFY: both system and device
- * Handler - Address of the handler
+ * PARAMETERS: event - Event type to enable.
+ * handler - Pointer to the handler function for the
+ * event
+ * context - Value passed to the handler on each GPE
*
* RETURN: Status
*
- * DESCRIPTION: Remove a handler for notifies on an ACPI device
+ * DESCRIPTION: Saves the pointer to the handler function and then enables the
+ * event.
*
******************************************************************************/
acpi_status
-acpi_remove_notify_handler(acpi_handle device,
- u32 handler_type, acpi_notify_handler handler)
+acpi_install_fixed_event_handler(u32 event,
+ acpi_event_handler handler, void *context)
{
- union acpi_operand_object *notify_obj;
- union acpi_operand_object *obj_desc;
- struct acpi_namespace_node *node;
acpi_status status;
- ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
+ ACPI_FUNCTION_TRACE(acpi_install_fixed_event_handler);
/* Parameter validation */
- if ((!device) ||
- (!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
- status = AE_BAD_PARAMETER;
- goto exit;
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
}
-
- /* Make sure all deferred tasks are completed */
- acpi_os_wait_events_complete(NULL);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
- goto exit;
+ return_ACPI_STATUS(status);
}
- /* Convert and validate the device handle */
+ /* Do not allow multiple handlers */
- node = acpi_ns_validate_handle(device);
- if (!node) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
+ if (acpi_gbl_fixed_event_handlers[event].handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
}
- /* Root Object */
+ /* Install the handler before enabling the event */
- if (device == ACPI_ROOT_OBJECT) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "Removing notify handler for namespace root object\n"));
+ acpi_gbl_fixed_event_handlers[event].handler = handler;
+ acpi_gbl_fixed_event_handlers[event].context = context;
- if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
- !acpi_gbl_system_notify.handler) ||
- ((handler_type & ACPI_DEVICE_NOTIFY) &&
- !acpi_gbl_device_notify.handler)) {
- status = AE_NOT_EXIST;
- goto unlock_and_exit;
- }
+ 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));
- if (handler_type & ACPI_SYSTEM_NOTIFY) {
- acpi_gbl_system_notify.node = NULL;
- acpi_gbl_system_notify.handler = NULL;
- acpi_gbl_system_notify.context = NULL;
- }
+ /* Remove the handler */
- if (handler_type & ACPI_DEVICE_NOTIFY) {
- acpi_gbl_device_notify.node = NULL;
- acpi_gbl_device_notify.handler = NULL;
- acpi_gbl_device_notify.context = NULL;
- }
+ 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));
}
- /* All Other Objects */
-
- else {
- /* Notifies allowed on this object? */
-
- if (!acpi_ev_is_notify_object(node)) {
- status = AE_TYPE;
- goto unlock_and_exit;
- }
+cleanup:
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+ return_ACPI_STATUS(status);
+}
- /* Check for an existing internal object */
+ACPI_EXPORT_SYMBOL(acpi_install_fixed_event_handler)
- obj_desc = acpi_ns_get_attached_object(node);
- if (!obj_desc) {
- status = AE_NOT_EXIST;
- goto unlock_and_exit;
- }
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_fixed_event_handler
+ *
+ * PARAMETERS: event - Event type to disable.
+ * handler - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disables the event and unregisters the event handler.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_remove_fixed_event_handler(u32 event, acpi_event_handler handler)
+{
+ acpi_status status = AE_OK;
- /* Object exists - make sure there's an existing handler */
+ ACPI_FUNCTION_TRACE(acpi_remove_fixed_event_handler);
- if (handler_type & ACPI_SYSTEM_NOTIFY) {
- struct acpi_object_notify_handler *handler_obj;
- struct acpi_object_notify_handler *parent_obj;
+ /* Parameter validation */
- notify_obj = obj_desc->common_notify.system_notify;
- if (!notify_obj) {
- status = AE_NOT_EXIST;
- goto unlock_and_exit;
- }
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
- handler_obj = &notify_obj->notify;
- parent_obj = NULL;
- while (handler_obj->handler != handler) {
- if (handler_obj->next) {
- parent_obj = handler_obj;
- handler_obj = handler_obj->next;
- } else {
- break;
- }
- }
+ status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
- if (handler_obj->handler != handler) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
+ /* Disable the event before removing the handler */
- /*
- * Remove the handler. There are three possible cases.
- * First, we may need to remove a non-embedded object.
- * Second, we may need to remove the embedded object's
- * handler data, while non-embedded objects exist.
- * Finally, we may need to remove the embedded object
- * entirely along with its container.
- */
- if (parent_obj) {
- /* Non-embedded object is being removed. */
- parent_obj->next = handler_obj->next;
- ACPI_FREE(handler_obj);
- } else if (notify_obj->notify.next) {
- /*
- * The handler matches the embedded object, but
- * there are more handler objects in the list.
- * Replace the embedded object's data with the
- * first next object's data and remove that
- * object.
- */
- parent_obj = &notify_obj->notify;
- handler_obj = notify_obj->notify.next;
- *parent_obj = *handler_obj;
- ACPI_FREE(handler_obj);
- } else {
- /* No more handler objects in the list. */
- obj_desc->common_notify.system_notify = NULL;
- acpi_ut_remove_reference(notify_obj);
- }
- }
+ status = acpi_disable_event(event, 0);
- if (handler_type & ACPI_DEVICE_NOTIFY) {
- notify_obj = obj_desc->common_notify.device_notify;
- if (!notify_obj) {
- status = AE_NOT_EXIST;
- goto unlock_and_exit;
- }
+ /* Always Remove the handler */
- if (notify_obj->notify.handler != handler) {
- status = AE_BAD_PARAMETER;
- goto unlock_and_exit;
- }
+ acpi_gbl_fixed_event_handlers[event].handler = NULL;
+ acpi_gbl_fixed_event_handlers[event].context = NULL;
- /* Remove the handler */
- obj_desc->common_notify.device_notify = NULL;
- acpi_ut_remove_reference(notify_obj);
- }
+ 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));
}
- unlock_and_exit:
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- exit:
- if (ACPI_FAILURE(status))
- ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
return_ACPI_STATUS(status);
}
-ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
+ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
/*******************************************************************************
*
@@ -658,10 +722,10 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
* defined GPEs)
* gpe_number - The GPE number within the GPE block
- * Type - Whether this GPE should be treated as an
+ * type - Whether this GPE should be treated as an
* edge- or level-triggered interrupt.
- * Address - Address of the handler
- * Context - Value passed to the handler on each GPE
+ * address - Address of the handler
+ * context - Value passed to the handler on each GPE
*
* RETURN: Status
*
@@ -671,10 +735,10 @@ ACPI_EXPORT_SYMBOL(acpi_remove_notify_handler)
acpi_status
acpi_install_gpe_handler(acpi_handle gpe_device,
u32 gpe_number,
- u32 type, acpi_event_handler address, void *context)
+ u32 type, acpi_gpe_handler address, void *context)
{
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
@@ -691,9 +755,9 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
return_ACPI_STATUS(status);
}
- /* Allocate memory for the handler object */
+ /* Allocate and init handler object (before lock) */
- handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
+ handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_handler_info));
if (!handler) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
@@ -717,31 +781,30 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
goto free_and_exit;
}
- /* Allocate and init handler object */
-
handler->address = address;
handler->context = context;
handler->method_node = gpe_event_info->dispatch.method_node;
- handler->orig_flags = gpe_event_info->flags &
- (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+ handler->original_flags = (u8)(gpe_event_info->flags &
+ (ACPI_GPE_XRUPT_TYPE_MASK |
+ ACPI_GPE_DISPATCH_MASK));
/*
- * If the GPE is associated with a method, it might have been enabled
+ * If the GPE is associated with a method, it may have been enabled
* automatically during initialization, in which case it has to be
* disabled now to avoid spurious execution of the handler.
*/
- if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
+ if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD)
&& gpe_event_info->runtime_count) {
- handler->orig_enabled = 1;
- (void)acpi_raw_disable_gpe(gpe_event_info);
+ handler->originally_enabled = 1;
+ (void)acpi_ev_remove_gpe_reference(gpe_event_info);
}
/* Install the handler */
gpe_event_info->dispatch.handler = handler;
- /* Setup up dispatch flags to indicate handler (vs. method) */
+ /* Setup up dispatch flags to indicate handler (vs. method/notify) */
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
@@ -768,7 +831,7 @@ ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
* defined GPEs)
* gpe_number - The event to remove a handler
- * Address - Address of the handler
+ * address - Address of the handler
*
* RETURN: Status
*
@@ -777,10 +840,10 @@ ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
******************************************************************************/
acpi_status
acpi_remove_gpe_handler(acpi_handle gpe_device,
- u32 gpe_number, acpi_event_handler address)
+ u32 gpe_number, acpi_gpe_handler address)
{
struct acpi_gpe_event_info *gpe_event_info;
- struct acpi_handler_info *handler;
+ struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
@@ -792,10 +855,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Make sure all deferred tasks are completed */
-
- acpi_os_wait_events_complete(NULL);
-
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -835,21 +894,29 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
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->orig_flags;
+ gpe_event_info->flags |= handler->original_flags;
/*
* If the GPE was previously associated with a method and it was
* enabled, it should be enabled at this point to restore the
* post-initialization configuration.
*/
+ if ((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) &&
+ handler->originally_enabled) {
+ (void)acpi_ev_add_gpe_reference(gpe_event_info);
+ }
- if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
- && handler->orig_enabled)
- (void)acpi_raw_enable_gpe(gpe_event_info);
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ /* Make sure all deferred GPE tasks are completed */
+
+ acpi_os_wait_events_complete();
/* Now we can free the handler object */
ACPI_FREE(handler);
+ return_ACPI_STATUS(status);
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
@@ -864,8 +931,8 @@ ACPI_EXPORT_SYMBOL(acpi_remove_gpe_handler)
*
* FUNCTION: acpi_acquire_global_lock
*
- * PARAMETERS: Timeout - How long the caller is willing to wait
- * Handle - Where the handle to the lock is returned
+ * PARAMETERS: timeout - How long the caller is willing to wait
+ * handle - Where the handle to the lock is returned
* (if acquired)
*
* RETURN: Status
@@ -912,7 +979,7 @@ ACPI_EXPORT_SYMBOL(acpi_acquire_global_lock)
*
* FUNCTION: acpi_release_global_lock
*
- * PARAMETERS: Handle - Returned from acpi_acquire_global_lock
+ * PARAMETERS: handle - Returned from acpi_acquire_global_lock
*
* RETURN: Status
*
@@ -932,3 +999,4 @@ acpi_status acpi_release_global_lock(u32 handle)
}
ACPI_EXPORT_SYMBOL(acpi_release_global_lock)
+#endif /* !ACPI_REDUCED_HARDWARE */