Commit 86ed4bc8 authored by Bob Moore's avatar Bob Moore Committed by Len Brown

ACPICA: Add support for multiple notify handlers

This change adds support to allow multiple notify handlers on
Device, ThermalZone, and Processor objects. Also re-worked
and restructured the entire notify support code for handler
installation, handler removal, notify event queuing, and notify
dispatch to handler.

Extends and updates original commit 3f0be671("ACPI / ACPICA: Multiple
system notify handlers per device") by Rafael Wysocki.
Signed-off-by: default avatarBob Moore <robert.moore@intel.com>
Signed-off-by: default avatarLin Ming <ming.m.lin@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 5134abfc
...@@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache; ...@@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
/* Global handlers */ /* Global handlers */
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify; ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler; ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler; ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler; ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;
......
...@@ -600,13 +600,22 @@ acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state, ...@@ -600,13 +600,22 @@ acpi_status(*acpi_parse_downwards) (struct acpi_walk_state * walk_state,
typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state); typedef acpi_status(*acpi_parse_upwards) (struct acpi_walk_state * walk_state);
/* Global handlers for AML Notifies */
struct acpi_global_notify_handler {
acpi_notify_handler handler;
void *context;
};
/* /*
* Notify info - used to pass info to the deferred notify * Notify info - used to pass info to the deferred notify
* handler/dispatcher. * handler/dispatcher.
*/ */
struct acpi_notify_info { struct acpi_notify_info {
ACPI_STATE_COMMON struct acpi_namespace_node *node; ACPI_STATE_COMMON u8 handler_list_id;
union acpi_operand_object *handler_obj; struct acpi_namespace_node *node;
union acpi_operand_object *handler_list_head;
struct acpi_global_notify_handler *global;
}; };
/* Generic state is union of structs above */ /* Generic state is union of structs above */
......
...@@ -206,8 +206,7 @@ struct acpi_object_method { ...@@ -206,8 +206,7 @@ struct acpi_object_method {
* Common fields for objects that support ASL notifications * Common fields for objects that support ASL notifications
*/ */
#define ACPI_COMMON_NOTIFY_INFO \ #define ACPI_COMMON_NOTIFY_INFO \
union acpi_operand_object *system_notify; /* Handler for system notifies */\ union acpi_operand_object *notify_list[2]; /* Handlers for system/device notifies */\
union acpi_operand_object *device_notify; /* Handler for driver notifies */\
union acpi_operand_object *handler; /* Handler for Address space */ union acpi_operand_object *handler; /* Handler for Address space */
struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */ struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
...@@ -296,10 +295,10 @@ struct acpi_object_buffer_field { ...@@ -296,10 +295,10 @@ struct acpi_object_buffer_field {
struct acpi_object_notify_handler { struct acpi_object_notify_handler {
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */ ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */
u32 handler_type; u32 handler_type; /* Type: Device/System/Both */
acpi_notify_handler handler; acpi_notify_handler handler; /* Handler address */
void *context; void *context;
struct acpi_object_notify_handler *next; union acpi_operand_object *next[2]; /* Device and System handler lists */
}; };
struct acpi_object_addr_handler { struct acpi_object_addr_handler {
......
...@@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, ...@@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
u32 notify_value) u32 notify_value)
{ {
union acpi_operand_object *obj_desc; union acpi_operand_object *obj_desc;
union acpi_operand_object *handler_obj = NULL; union acpi_operand_object *handler_list_head = NULL;
union acpi_generic_state *notify_info; union acpi_generic_state *info;
u8 handler_list_id = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;
ACPI_FUNCTION_NAME(ev_queue_notify_request); ACPI_FUNCTION_NAME(ev_queue_notify_request);
/* /* Are Notifies allowed on this object? */
* For value 0x03 (Ejection Request), may need to run a device method.
* For value 0x02 (Device Wake), if _PRW exists, may need to run
* the _PS0 method.
* For value 0x80 (Status Change) on the power button or sleep button,
* initiate soft-off or sleep operation.
*
* For all cases, simply dispatch the notify to the handler.
*/
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node),
acpi_ut_get_type_name(node->type), notify_value,
acpi_ut_get_notify_name(notify_value), node));
/* Get the notify object attached to the NS Node */
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
/* We have the notify object, Get the correct handler */
switch (node->type) {
/* Notify is allowed only on these types */ if (!acpi_ev_is_notify_object(node)) {
return (AE_TYPE);
}
case ACPI_TYPE_DEVICE: /* Get the correct notify list type (System or Device) */
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_PROCESSOR:
if (notify_value <= ACPI_MAX_SYS_NOTIFY) { if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_obj = handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
obj_desc->common_notify.system_notify;
} else { } else {
handler_obj = handler_list_id = ACPI_DEVICE_HANDLER_LIST;
obj_desc->common_notify.device_notify;
} }
break;
default: /* Get the notify object attached to the namespace Node */
/* All other types are not supported */ obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
return (AE_TYPE); /* We have an attached object, Get the correct handler list */
}
handler_list_head =
obj_desc->common_notify.notify_list[handler_list_id];
} }
/* /*
* If there is a handler to run, schedule the dispatcher. * If there is no notify handler (Global or Local)
* Check for: * for this object, just ignore the notify
* 1) Global system notify handler
* 2) Global device notify handler
* 3) Per-device notify handler
*/ */
if ((acpi_gbl_system_notify.handler && if (!acpi_gbl_global_notify[handler_list_id].handler
(notify_value <= ACPI_MAX_SYS_NOTIFY)) || && !handler_list_head) {
(acpi_gbl_device_notify.handler &&
(notify_value > ACPI_MAX_SYS_NOTIFY)) || handler_obj) {
notify_info = acpi_ut_create_generic_state();
if (!notify_info) {
return (AE_NO_MEMORY);
}
if (!handler_obj) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Executing system notify handler for Notify (%4.4s, %X) " "No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
"node %p\n", acpi_ut_get_node_name(node), notify_value,
acpi_ut_get_node_name(node), node));
notify_value, node));
return (AE_OK);
} }
notify_info->common.descriptor_type = /* Setup notify info and schedule the notify dispatcher */
ACPI_DESC_TYPE_STATE_NOTIFY;
notify_info->notify.node = node;
notify_info->notify.value = (u16) notify_value;
notify_info->notify.handler_obj = handler_obj;
status = info = acpi_ut_create_generic_state();
acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch, if (!info) {
notify_info); return (AE_NO_MEMORY);
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(notify_info);
} }
} else {
/* There is no notify handler (per-device or system) for this device */ info->common.descriptor_type = ACPI_DESC_TYPE_STATE_NOTIFY;
info->notify.node = node;
info->notify.value = (u16)notify_value;
info->notify.handler_list_id = handler_list_id;
info->notify.handler_list_head = handler_list_head;
info->notify.global = &acpi_gbl_global_notify[handler_list_id];
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify (%4.4s, %X) node %p\n", "Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node), notify_value, acpi_ut_get_node_name(node),
node)); acpi_ut_get_type_name(node->type), notify_value,
acpi_ut_get_notify_name(notify_value), node));
status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
info);
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(info);
} }
return (status); return (status);
...@@ -217,60 +192,34 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node, ...@@ -217,60 +192,34 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context) static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
{ {
union acpi_generic_state *notify_info = union acpi_generic_state *info = (union acpi_generic_state *)context;
(union acpi_generic_state *)context;
acpi_notify_handler global_handler = NULL;
void *global_context = NULL;
union acpi_operand_object *handler_obj; union acpi_operand_object *handler_obj;
ACPI_FUNCTION_ENTRY(); ACPI_FUNCTION_ENTRY();
/* /* Invoke a global notify handler if installed */
* We will invoke a global notify handler if installed. This is done
* _before_ we invoke the per-device handler attached to the device.
*/
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
/* Global system notification handler */
if (acpi_gbl_system_notify.handler) { if (info->notify.global->handler) {
global_handler = acpi_gbl_system_notify.handler; info->notify.global->handler(info->notify.node,
global_context = acpi_gbl_system_notify.context; info->notify.value,
info->notify.global->context);
} }
} else {
/* Global driver notification handler */
if (acpi_gbl_device_notify.handler) { /* Now invoke the local notify handler(s) if any are installed */
global_handler = acpi_gbl_device_notify.handler;
global_context = acpi_gbl_device_notify.context;
}
}
/* Invoke the system handler first, if present */
if (global_handler) {
global_handler(notify_info->notify.node,
notify_info->notify.value, global_context);
}
/* Now invoke the per-device handler, if present */ handler_obj = info->notify.handler_list_head;
while (handler_obj) {
handler_obj->notify.handler(info->notify.node,
info->notify.value,
handler_obj->notify.context);
handler_obj = notify_info->notify.handler_obj; handler_obj =
if (handler_obj) { handler_obj->notify.next[info->notify.handler_list_id];
struct acpi_object_notify_handler *notifier;
notifier = &handler_obj->notify;
while (notifier) {
notifier->handler(notify_info->notify.node,
notify_info->notify.value,
notifier->context);
notifier = notifier->next;
}
} }
/* All done with the info object */ /* All done with the info object */
acpi_ut_delete_generic_state(notify_info); acpi_ut_delete_generic_state(info);
} }
#if (!ACPI_REDUCED_HARDWARE) #if (!ACPI_REDUCED_HARDWARE)
......
...@@ -52,88 +52,27 @@ ...@@ -52,88 +52,27 @@
ACPI_MODULE_NAME("evxface") ACPI_MODULE_NAME("evxface")
/*******************************************************************************
*
* 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;
}
/*******************************************************************************
*
* FUNCTION: acpi_add_handler_object
*
* PARAMETERS: parent_obj - Parent of the new object
* handler - Address of the handler
* context - Value passed to the handler on each GPE
*
* RETURN: Status
*
* DESCRIPTION: Create a new handler object and populate it.
*
******************************************************************************/
static acpi_status
acpi_add_handler_object(struct acpi_object_notify_handler *parent_obj,
acpi_notify_handler handler, void *context)
{
struct acpi_object_notify_handler *handler_obj;
/* The parent must not be a defice notify handler object. */
if (parent_obj->handler_type & ACPI_DEVICE_NOTIFY)
return AE_BAD_PARAMETER;
handler_obj = ACPI_ALLOCATE_ZEROED(sizeof(*handler_obj));
if (!handler_obj)
return AE_NO_MEMORY;
acpi_populate_handler_object(handler_obj,
ACPI_SYSTEM_NOTIFY,
handler, context,
parent_obj->next);
parent_obj->next = handler_obj;
return AE_OK;
}
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_install_notify_handler * FUNCTION: acpi_install_notify_handler
* *
* PARAMETERS: Device - The device for which notifies will be handled * PARAMETERS: Device - The device for which notifies will be handled
* handler_type - The type of handler: * handler_type - The type of handler:
* ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
* ACPI_DEVICE_NOTIFY: driver_handler (80-ff) * ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
* ACPI_ALL_NOTIFY: both system and device * ACPI_ALL_NOTIFY: Both System and Device
* Handler - Address of the handler * Handler - Address of the handler
* Context - Value passed to the handler on each GPE * Context - Value passed to the handler on each GPE
* *
* RETURN: Status * RETURN: Status
* *
* DESCRIPTION: Install a handler for notifies on an ACPI device * 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.
* *
******************************************************************************/ ******************************************************************************/
acpi_status acpi_status
...@@ -141,17 +80,19 @@ acpi_install_notify_handler(acpi_handle device, ...@@ -141,17 +80,19 @@ acpi_install_notify_handler(acpi_handle device,
u32 handler_type, u32 handler_type,
acpi_notify_handler handler, void *context) 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 *obj_desc;
union acpi_operand_object *notify_obj; union acpi_operand_object *handler_obj;
struct acpi_namespace_node *node;
acpi_status status; acpi_status status;
u32 i;
ACPI_FUNCTION_TRACE(acpi_install_notify_handler); ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
/* Parameter validation */ /* Parameter validation */
if ((!device) || if ((!device) || (!handler) || (!handler_type) ||
(!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
return_ACPI_STATUS(AE_BAD_PARAMETER); return_ACPI_STATUS(AE_BAD_PARAMETER);
} }
...@@ -160,92 +101,48 @@ acpi_install_notify_handler(acpi_handle device, ...@@ -160,92 +101,48 @@ acpi_install_notify_handler(acpi_handle device,
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
/* Convert and validate the device handle */
node = acpi_ns_validate_handle(device);
if (!node) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
/* /*
* Root Object: * Root Object:
* Registering a notify handler on the root object indicates that the * Registering a notify handler on the root object indicates that the
* caller wishes to receive notifications for all objects. Note that * caller wishes to receive notifications for all objects. Note that
* only one <external> global handler can be regsitered (per notify type). * only one global handler can be registered per notify type.
* Ensure that a handler is not already installed.
*/ */
if (device == ACPI_ROOT_OBJECT) { if (device == ACPI_ROOT_OBJECT) {
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
/* Make sure the handler is not already installed */ if (handler_type & (i + 1)) {
if (acpi_gbl_global_notify[i].handler) {
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
acpi_gbl_system_notify.handler) ||
((handler_type & ACPI_DEVICE_NOTIFY) &&
acpi_gbl_device_notify.handler)) {
status = AE_ALREADY_EXISTS; status = AE_ALREADY_EXISTS;
goto unlock_and_exit; goto unlock_and_exit;
} }
if (handler_type & ACPI_SYSTEM_NOTIFY) { acpi_gbl_global_notify[i].handler = handler;
acpi_gbl_system_notify.node = node; acpi_gbl_global_notify[i].context = context;
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 */ goto unlock_and_exit; /* Global notify handler installed, all done */
} }
/* /*
* All Other Objects: * All Other Objects:
* Caller will only receive notifications specific to the target object. * Caller will only receive notifications specific to the target
* Note that only certain object types can receive notifications. * object. Note that only certain object types are allowed to
* receive notifications.
*/ */
else {
/* Notifies allowed on this object? */ /* Are Notifies allowed on this object? */
if (!acpi_ev_is_notify_object(node)) { if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE; status = AE_TYPE;
goto unlock_and_exit; goto unlock_and_exit;
} }
/* Check for an existing internal object */ /* Check for an existing internal object, might not exist */
obj_desc = acpi_ns_get_attached_object(node); obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) { if (!obj_desc) {
/* Object exists. */
/* 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;
}
/* System notifies may have more handlers installed. */
notify_obj = obj_desc->common_notify.system_notify;
if ((handler_type & ACPI_SYSTEM_NOTIFY) && notify_obj) {
struct acpi_object_notify_handler *parent_obj;
if (handler_type & ACPI_DEVICE_NOTIFY) {
status = AE_ALREADY_EXISTS;
goto unlock_and_exit;
}
parent_obj = &notify_obj->notify;
status = acpi_add_handler_object(parent_obj,
handler,
context);
goto unlock_and_exit;
}
} else {
/* Create a new object */ /* Create a new object */
obj_desc = acpi_ut_create_internal_object(node->type); obj_desc = acpi_ut_create_internal_object(node->type);
...@@ -254,50 +151,62 @@ acpi_install_notify_handler(acpi_handle device, ...@@ -254,50 +151,62 @@ acpi_install_notify_handler(acpi_handle device,
goto unlock_and_exit; goto unlock_and_exit;
} }
/* Attach new object to the Node */ /* Attach new object to the Node, remove local reference */
status =
acpi_ns_attach_object(device, obj_desc, node->type);
/* Remove local reference to the object */
status = acpi_ns_attach_object(device, obj_desc, node->type);
acpi_ut_remove_reference(obj_desc); acpi_ut_remove_reference(obj_desc);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto unlock_and_exit; goto unlock_and_exit;
} }
} }
/* Install the handler */ /* Ensure that the handler is not already installed in the lists */
notify_obj = for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY); if (handler_type & (i + 1)) {
if (!notify_obj) { handler_obj = obj_desc->common_notify.notify_list[i];
status = AE_NO_MEMORY; while (handler_obj) {
if (handler_obj->notify.handler == handler) {
status = AE_ALREADY_EXISTS;
goto unlock_and_exit; goto unlock_and_exit;
} }
acpi_populate_handler_object(&notify_obj->notify, handler_obj = handler_obj->notify.next[i];
handler_type,
handler, context,
NULL);
if (handler_type & ACPI_SYSTEM_NOTIFY) {
obj_desc->common_notify.system_notify = notify_obj;
} }
}
}
/* Create and populate a new notify handler object */
if (handler_type & ACPI_DEVICE_NOTIFY) { handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
obj_desc->common_notify.device_notify = notify_obj; if (!handler_obj) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
} }
if (handler_type == ACPI_ALL_NOTIFY) { handler_obj->notify.node = node;
handler_obj->notify.handler_type = handler_type;
handler_obj->notify.handler = handler;
handler_obj->notify.context = context;
/* Install the handler at the list head(s) */
/* Extra ref if installed in both */ 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];
acpi_ut_add_reference(notify_obj); obj_desc->common_notify.notify_list[i] = handler_obj;
} }
} }
unlock_and_exit: /* Add an extra reference if handler was installed in both lists */
if (handler_type == ACPI_ALL_NOTIFY) {
acpi_ut_add_reference(handler_obj);
}
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
...@@ -308,11 +217,11 @@ ACPI_EXPORT_SYMBOL(acpi_install_notify_handler) ...@@ -308,11 +217,11 @@ ACPI_EXPORT_SYMBOL(acpi_install_notify_handler)
* *
* FUNCTION: acpi_remove_notify_handler * FUNCTION: acpi_remove_notify_handler
* *
* PARAMETERS: Device - The device for which notifies will be handled * PARAMETERS: Device - The device for which the handler is installed
* handler_type - The type of handler: * handler_type - The type of handler:
* ACPI_SYSTEM_NOTIFY: system_handler (00-7f) * ACPI_SYSTEM_NOTIFY: System Handler (00-7F)
* ACPI_DEVICE_NOTIFY: driver_handler (80-ff) * ACPI_DEVICE_NOTIFY: Device Handler (80-FF)
* ACPI_ALL_NOTIFY: both system and device * ACPI_ALL_NOTIFY: Both System and Device
* Handler - Address of the handler * Handler - Address of the handler
* *
* RETURN: Status * RETURN: Status
...@@ -324,76 +233,62 @@ acpi_status ...@@ -324,76 +233,62 @@ acpi_status
acpi_remove_notify_handler(acpi_handle device, acpi_remove_notify_handler(acpi_handle device,
u32 handler_type, acpi_notify_handler handler) u32 handler_type, acpi_notify_handler handler)
{ {
union acpi_operand_object *notify_obj; struct acpi_namespace_node *node =
ACPI_CAST_PTR(struct acpi_namespace_node, device);
union acpi_operand_object *obj_desc; union acpi_operand_object *obj_desc;
struct acpi_namespace_node *node; union acpi_operand_object *handler_obj;
union acpi_operand_object *previous_handler_obj;
acpi_status status; acpi_status status;
u32 i;
ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
/* Parameter validation */ /* Parameter validation */
if ((!device) || if ((!device) || (!handler) || (!handler_type) ||
(!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) { (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
status = AE_BAD_PARAMETER; return_ACPI_STATUS(AE_BAD_PARAMETER);
goto exit;
} }
/* Make sure all deferred tasks are completed */ /* Make sure all deferred tasks are completed */
acpi_os_wait_events_complete(NULL); acpi_os_wait_events_complete(NULL);
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
goto exit; return_ACPI_STATUS(status);
}
/* Convert and validate the device handle */
node = acpi_ns_validate_handle(device);
if (!node) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
} }
/* Root Object */ /* Root Object. Global handlers are removed here */
if (device == ACPI_ROOT_OBJECT) { if (device == ACPI_ROOT_OBJECT) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
"Removing notify handler for namespace root object\n")); if (handler_type & (i + 1)) {
if (!acpi_gbl_global_notify[i].handler ||
if (((handler_type & ACPI_SYSTEM_NOTIFY) && (acpi_gbl_global_notify[i].handler !=
!acpi_gbl_system_notify.handler) || handler)) {
((handler_type & ACPI_DEVICE_NOTIFY) &&
!acpi_gbl_device_notify.handler)) {
status = AE_NOT_EXIST; status = AE_NOT_EXIST;
goto unlock_and_exit; goto unlock_and_exit;
} }
if (handler_type & ACPI_SYSTEM_NOTIFY) { ACPI_DEBUG_PRINT((ACPI_DB_INFO,
acpi_gbl_system_notify.node = NULL; "Removing global notify handler\n"));
acpi_gbl_system_notify.handler = NULL;
acpi_gbl_system_notify.context = NULL;
}
if (handler_type & ACPI_DEVICE_NOTIFY) { acpi_gbl_global_notify[i].handler = NULL;
acpi_gbl_device_notify.node = NULL; acpi_gbl_global_notify[i].context = NULL;
acpi_gbl_device_notify.handler = NULL;
acpi_gbl_device_notify.context = NULL;
} }
} }
/* All Other Objects */ goto unlock_and_exit;
}
else { /* All other objects: Are Notifies allowed on this object? */
/* Notifies allowed on this object? */
if (!acpi_ev_is_notify_object(node)) { if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE; status = AE_TYPE;
goto unlock_and_exit; goto unlock_and_exit;
} }
/* Check for an existing internal object */ /* Must have an existing internal object */
obj_desc = acpi_ns_get_attached_object(node); obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) { if (!obj_desc) {
...@@ -401,88 +296,43 @@ acpi_remove_notify_handler(acpi_handle device, ...@@ -401,88 +296,43 @@ acpi_remove_notify_handler(acpi_handle device,
goto unlock_and_exit; goto unlock_and_exit;
} }
/* Object exists - make sure there's an existing handler */ /* Internal object exists. Find the handler and remove it */
if (handler_type & ACPI_SYSTEM_NOTIFY) { for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
struct acpi_object_notify_handler *handler_obj; if (handler_type & (i + 1)) {
struct acpi_object_notify_handler *parent_obj; handler_obj = obj_desc->common_notify.notify_list[i];
previous_handler_obj = NULL;
notify_obj = obj_desc->common_notify.system_notify; /* Attempt to find the handler in the handler list */
if (!notify_obj) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
handler_obj = &notify_obj->notify; while (handler_obj &&
parent_obj = NULL; (handler_obj->notify.handler != handler)) {
while (handler_obj->handler != handler) { previous_handler_obj = handler_obj;
if (handler_obj->next) { handler_obj = handler_obj->notify.next[i];
parent_obj = handler_obj;
handler_obj = handler_obj->next;
} else {
break;
}
} }
if (handler_obj->handler != handler) { if (!handler_obj) {
status = AE_BAD_PARAMETER; status = AE_NOT_EXIST;
goto unlock_and_exit; goto unlock_and_exit;
} }
/* /* Remove the handler object from the list */
* 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);
}
}
if (handler_type & ACPI_DEVICE_NOTIFY) { if (previous_handler_obj) { /* Handler is not at the list head */
notify_obj = obj_desc->common_notify.device_notify; previous_handler_obj->notify.next[i] =
if (!notify_obj) { handler_obj->notify.next[i];
status = AE_NOT_EXIST; } else { /* Handler is at the list head */
goto unlock_and_exit;
}
if (notify_obj->notify.handler != handler) { obj_desc->common_notify.notify_list[i] =
status = AE_BAD_PARAMETER; handler_obj->notify.next[i];
goto unlock_and_exit;
} }
/* Remove the handler */ acpi_ut_remove_reference(handler_obj);
obj_desc->common_notify.device_notify = NULL;
acpi_ut_remove_reference(notify_obj);
} }
} }
unlock_and_exit: unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
exit:
if (ACPI_FAILURE(status))
ACPI_EXCEPTION((AE_INFO, status, "Removing notify handler"));
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
......
...@@ -109,9 +109,9 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = { ...@@ -109,9 +109,9 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = {
static struct acpi_exdump_info acpi_ex_dump_device[4] = { static struct acpi_exdump_info acpi_ex_dump_device[4] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL}, {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_device), NULL},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]),
"Device Notify"} "Device Notify"}
}; };
...@@ -158,9 +158,9 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = { ...@@ -158,9 +158,9 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
"System Level"}, "System Level"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.resource_order), {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.resource_order),
"Resource Order"}, "Resource Order"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]),
"Device Notify"} "Device Notify"}
}; };
...@@ -169,18 +169,18 @@ static struct acpi_exdump_info acpi_ex_dump_processor[7] = { ...@@ -169,18 +169,18 @@ static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"}, {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
{ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"}, {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[1]),
"Device Notify"}, "Device Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.handler), "Handler"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.handler), "Handler"}
}; };
static struct acpi_exdump_info acpi_ex_dump_thermal[4] = { static struct acpi_exdump_info acpi_ex_dump_thermal[4] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_thermal), NULL}, {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_thermal), NULL},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.system_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[0]),
"System Notify"}, "System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.device_notify), {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[1]),
"Device Notify"}, "Device Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.handler), "Handler"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.handler), "Handler"}
}; };
...@@ -241,10 +241,15 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = { ...@@ -241,10 +241,15 @@ static struct acpi_exdump_info acpi_ex_dump_address_handler[6] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"} {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(address_space.context), "Context"}
}; };
static struct acpi_exdump_info acpi_ex_dump_notify[3] = { static struct acpi_exdump_info acpi_ex_dump_notify[7] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL}, {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_notify), NULL},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"}, {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.node), "Node"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"} {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(notify.handler_type), "Handler Type"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.handler), "Handler"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.context), "Context"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[0]),
"Next System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(notify.next[1]), "Next Device Notify"}
}; };
/* Miscellaneous tables */ /* Miscellaneous tables */
......
...@@ -152,7 +152,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) ...@@ -152,7 +152,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
case ACPI_TYPE_PROCESSOR: case ACPI_TYPE_PROCESSOR:
case ACPI_TYPE_THERMAL: case ACPI_TYPE_THERMAL:
/* Walk the notify handler list for this object */ /* Walk the address handler list for this object */
handler_desc = object->common_notify.handler; handler_desc = object->common_notify.handler;
while (handler_desc) { while (handler_desc) {
...@@ -480,6 +480,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) ...@@ -480,6 +480,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
acpi_status status = AE_OK; acpi_status status = AE_OK;
union acpi_generic_state *state_list = NULL; union acpi_generic_state *state_list = NULL;
union acpi_operand_object *next_object = NULL; union acpi_operand_object *next_object = NULL;
union acpi_operand_object *prev_object;
union acpi_generic_state *state; union acpi_generic_state *state;
u32 i; u32 i;
...@@ -505,12 +506,21 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action) ...@@ -505,12 +506,21 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
case ACPI_TYPE_POWER: case ACPI_TYPE_POWER:
case ACPI_TYPE_THERMAL: case ACPI_TYPE_THERMAL:
/* Update the notify objects for these types (if present) */ /*
* Update the notify objects for these types (if present)
acpi_ut_update_ref_count(object->common_notify. * Two lists, system and device notify handlers.
system_notify, action); */
acpi_ut_update_ref_count(object->common_notify. for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
device_notify, action); prev_object =
object->common_notify.notify_list[i];
while (prev_object) {
next_object =
prev_object->notify.next[i];
acpi_ut_update_ref_count(prev_object,
action);
prev_object = next_object;
}
}
break; break;
case ACPI_TYPE_PACKAGE: case ACPI_TYPE_PACKAGE:
......
...@@ -304,8 +304,8 @@ acpi_status acpi_ut_init_globals(void) ...@@ -304,8 +304,8 @@ acpi_status acpi_ut_init_globals(void)
/* Global handlers */ /* Global handlers */
acpi_gbl_system_notify.handler = NULL; acpi_gbl_global_notify[0].handler = NULL;
acpi_gbl_device_notify.handler = NULL; acpi_gbl_global_notify[1].handler = NULL;
acpi_gbl_exception_handler = NULL; acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL; acpi_gbl_init_handler = NULL;
acpi_gbl_table_handler = NULL; acpi_gbl_table_handler = NULL;
......
...@@ -706,10 +706,14 @@ typedef u32 acpi_event_status; ...@@ -706,10 +706,14 @@ typedef u32 acpi_event_status;
#define ACPI_DEVICE_NOTIFY 0x2 #define ACPI_DEVICE_NOTIFY 0x2
#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY) #define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 #define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3
#define ACPI_NUM_NOTIFY_TYPES 2
#define ACPI_MAX_SYS_NOTIFY 0x7F #define ACPI_MAX_SYS_NOTIFY 0x7F
#define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF #define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF
#define ACPI_SYSTEM_HANDLER_LIST 0 /* Used as index, must be SYSTEM_NOTIFY -1 */
#define ACPI_DEVICE_HANDLER_LIST 1 /* Used as index, must be DEVICE_NOTIFY -1 */
/* Address Space (Operation Region) Types */ /* Address Space (Operation Region) Types */
typedef u8 acpi_adr_space_type; typedef u8 acpi_adr_space_type;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment