dect
/
linux-2.6
Archived
13
0
Fork 0

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 3f0be67("ACPI / ACPICA: Multiple
system notify handlers per device") by Rafael Wysocki.

Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
Bob Moore 2012-05-03 11:08:19 +08:00 committed by Len Brown
parent 5134abfcfb
commit 86ed4bc83a
9 changed files with 294 additions and 469 deletions

View File

@ -278,8 +278,7 @@ ACPI_EXTERN acpi_cache_t *acpi_gbl_operand_cache;
/* Global handlers */
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_device_notify;
ACPI_EXTERN struct acpi_object_notify_handler acpi_gbl_system_notify;
ACPI_EXTERN struct acpi_global_notify_handler acpi_gbl_global_notify[2];
ACPI_EXTERN acpi_exception_handler acpi_gbl_exception_handler;
ACPI_EXTERN acpi_init_handler acpi_gbl_init_handler;
ACPI_EXTERN acpi_tbl_handler acpi_gbl_table_handler;

View File

@ -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);
/* 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
* handler/dispatcher.
*/
struct acpi_notify_info {
ACPI_STATE_COMMON struct acpi_namespace_node *node;
union acpi_operand_object *handler_obj;
ACPI_STATE_COMMON u8 handler_list_id;
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 */

View File

@ -206,8 +206,7 @@ struct acpi_object_method {
* Common fields for objects that support ASL notifications
*/
#define ACPI_COMMON_NOTIFY_INFO \
union acpi_operand_object *system_notify; /* Handler for system notifies */\
union acpi_operand_object *device_notify; /* Handler for driver notifies */\
union acpi_operand_object *notify_list[2]; /* Handlers for system/device notifies */\
union acpi_operand_object *handler; /* Handler for Address space */
struct acpi_object_notify_common { /* COMMON NOTIFY for POWER, PROCESSOR, DEVICE, and THERMAL */
@ -296,10 +295,10 @@ struct acpi_object_buffer_field {
struct acpi_object_notify_handler {
ACPI_OBJECT_COMMON_HEADER struct acpi_namespace_node *node; /* Parent device */
u32 handler_type;
acpi_notify_handler handler;
u32 handler_type; /* Type: Device/System/Both */
acpi_notify_handler handler; /* Handler address */
void *context;
struct acpi_object_notify_handler *next;
union acpi_operand_object *next[2]; /* Device and System handler lists */
};
struct acpi_object_addr_handler {

View File

@ -101,102 +101,77 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
u32 notify_value)
{
union acpi_operand_object *obj_desc;
union acpi_operand_object *handler_obj = NULL;
union acpi_generic_state *notify_info;
union acpi_operand_object *handler_list_head = NULL;
union acpi_generic_state *info;
u8 handler_list_id = 0;
acpi_status status = AE_OK;
ACPI_FUNCTION_NAME(ev_queue_notify_request);
/* Are Notifies allowed on this object? */
if (!acpi_ev_is_notify_object(node)) {
return (AE_TYPE);
}
/* Get the correct notify list type (System or Device) */
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
} else {
handler_list_id = ACPI_DEVICE_HANDLER_LIST;
}
/* Get the notify object attached to the namespace Node */
obj_desc = acpi_ns_get_attached_object(node);
if (obj_desc) {
/* We have an attached object, Get the correct handler list */
handler_list_head =
obj_desc->common_notify.notify_list[handler_list_id];
}
/*
* 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.
* If there is no notify handler (Global or Local)
* for this object, just ignore the notify
*/
if (!acpi_gbl_global_notify[handler_list_id].handler
&& !handler_list_head) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify, ignoring (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), notify_value,
node));
return (AE_OK);
}
/* Setup notify info and schedule the notify dispatcher */
info = acpi_ut_create_generic_state();
if (!info) {
return (AE_NO_MEMORY);
}
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,
"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 */
case ACPI_TYPE_DEVICE:
case ACPI_TYPE_THERMAL:
case ACPI_TYPE_PROCESSOR:
if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
handler_obj =
obj_desc->common_notify.system_notify;
} else {
handler_obj =
obj_desc->common_notify.device_notify;
}
break;
default:
/* All other types are not supported */
return (AE_TYPE);
}
}
/*
* If there is a handler to run, schedule the dispatcher.
* Check for:
* 1) Global system notify handler
* 2) Global device notify handler
* 3) Per-device notify handler
*/
if ((acpi_gbl_system_notify.handler &&
(notify_value <= ACPI_MAX_SYS_NOTIFY)) ||
(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,
"Executing system notify handler for Notify (%4.4s, %X) "
"node %p\n",
acpi_ut_get_node_name(node),
notify_value, node));
}
notify_info->common.descriptor_type =
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 =
acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
notify_info);
if (ACPI_FAILURE(status)) {
acpi_ut_delete_generic_state(notify_info);
}
} else {
/* There is no notify handler (per-device or system) for this device */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"No notify handler for Notify (%4.4s, %X) node %p\n",
acpi_ut_get_node_name(node), 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);
@ -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)
{
union acpi_generic_state *notify_info =
(union acpi_generic_state *)context;
acpi_notify_handler global_handler = NULL;
void *global_context = NULL;
union acpi_generic_state *info = (union acpi_generic_state *)context;
union acpi_operand_object *handler_obj;
ACPI_FUNCTION_ENTRY();
/*
* 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) {
/* Invoke a global notify handler if installed */
/* Global system notification handler */
if (acpi_gbl_system_notify.handler) {
global_handler = acpi_gbl_system_notify.handler;
global_context = acpi_gbl_system_notify.context;
}
} else {
/* Global driver notification handler */
if (acpi_gbl_device_notify.handler) {
global_handler = acpi_gbl_device_notify.handler;
global_context = acpi_gbl_device_notify.context;
}
if (info->notify.global->handler) {
info->notify.global->handler(info->notify.node,
info->notify.value,
info->notify.global->context);
}
/* Invoke the system handler first, if present */
/* Now invoke the local notify handler(s) if any are installed */
if (global_handler) {
global_handler(notify_info->notify.node,
notify_info->notify.value, global_context);
}
handler_obj = info->notify.handler_list_head;
while (handler_obj) {
handler_obj->notify.handler(info->notify.node,
info->notify.value,
handler_obj->notify.context);
/* Now invoke the per-device handler, if present */
handler_obj = notify_info->notify.handler_obj;
if (handler_obj) {
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;
}
handler_obj =
handler_obj->notify.next[info->notify.handler_list_id];
}
/* All done with the info object */
acpi_ut_delete_generic_state(notify_info);
acpi_ut_delete_generic_state(info);
}
#if (!ACPI_REDUCED_HARDWARE)

View File

@ -52,88 +52,27 @@
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
*
* 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
* 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: 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
@ -141,17 +80,19 @@ 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 *notify_obj;
struct acpi_namespace_node *node;
union acpi_operand_object *handler_obj;
acpi_status status;
u32 i;
ACPI_FUNCTION_TRACE(acpi_install_notify_handler);
/* Parameter validation */
if ((!device) ||
(!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
if ((!device) || (!handler) || (!handler_type) ||
(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
@ -160,144 +101,112 @@ acpi_install_notify_handler(acpi_handle device,
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:
* 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).
* only one global handler can be registered per notify type.
* Ensure that a handler is not already installed.
*/
if (device == ACPI_ROOT_OBJECT) {
/* Make sure the handler is not already installed */
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;
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 */
}
/*
* 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? */
if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE;
goto unlock_and_exit;
}
/* Check for an existing internal object */
obj_desc = acpi_ns_get_attached_object(node);
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) {
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;
}
parent_obj = &notify_obj->notify;
status = acpi_add_handler_object(parent_obj,
handler,
context);
goto unlock_and_exit;
}
} else {
/* Create a new object */
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 */
status =
acpi_ns_attach_object(device, obj_desc, node->type);
/* Remove local reference to the object */
acpi_ut_remove_reference(obj_desc);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
acpi_gbl_global_notify[i].handler = handler;
acpi_gbl_global_notify[i].context = context;
}
}
/* Install the handler */
goto unlock_and_exit; /* Global notify handler installed, all done */
}
notify_obj =
acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
if (!notify_obj) {
/*
* All Other Objects:
* Caller will only receive notifications specific to the target
* object. Note that only certain object types are allowed to
* receive notifications.
*/
/* Are Notifies allowed on this object? */
if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE;
goto unlock_and_exit;
}
/* Check for an existing internal object, might not exist */
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
/* Create a new object */
obj_desc = acpi_ut_create_internal_object(node->type);
if (!obj_desc) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
}
acpi_populate_handler_object(&notify_obj->notify,
handler_type,
handler, context,
NULL);
/* Attach new object to the Node, remove local reference */
if (handler_type & ACPI_SYSTEM_NOTIFY) {
obj_desc->common_notify.system_notify = notify_obj;
}
if (handler_type & ACPI_DEVICE_NOTIFY) {
obj_desc->common_notify.device_notify = notify_obj;
}
if (handler_type == ACPI_ALL_NOTIFY) {
/* Extra ref if installed in both */
acpi_ut_add_reference(notify_obj);
status = acpi_ns_attach_object(device, obj_desc, node->type);
acpi_ut_remove_reference(obj_desc);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
}
unlock_and_exit:
/* 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];
}
}
}
/* Create and populate a new notify handler object */
handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
if (!handler_obj) {
status = AE_NO_MEMORY;
goto unlock_and_exit;
}
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) */
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];
obj_desc->common_notify.notify_list[i] = handler_obj;
}
}
/* 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);
return_ACPI_STATUS(status);
}
@ -308,11 +217,11 @@ ACPI_EXPORT_SYMBOL(acpi_install_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:
* ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
* ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
* ACPI_ALL_NOTIFY: both system and device
* 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
@ -324,165 +233,106 @@ acpi_status
acpi_remove_notify_handler(acpi_handle device,
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;
struct acpi_namespace_node *node;
union acpi_operand_object *handler_obj;
union acpi_operand_object *previous_handler_obj;
acpi_status status;
u32 i;
ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
/* Parameter validation */
if ((!device) ||
(!handler) || (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
status = AE_BAD_PARAMETER;
goto exit;
if ((!device) || (!handler) || (!handler_type) ||
(handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
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);
if (ACPI_FAILURE(status)) {
goto exit;
return_ACPI_STATUS(status);
}
/* Convert and validate the device handle */
/* 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)) {
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;
}
}
node = acpi_ns_validate_handle(device);
if (!node) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
/* Root Object */
/* All other objects: Are Notifies allowed on this object? */
if (device == ACPI_ROOT_OBJECT) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Removing notify handler for namespace root object\n"));
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;
}
if (handler_type & ACPI_SYSTEM_NOTIFY) {
acpi_gbl_system_notify.node = NULL;
acpi_gbl_system_notify.handler = NULL;
acpi_gbl_system_notify.context = NULL;
}
if (handler_type & ACPI_DEVICE_NOTIFY) {
acpi_gbl_device_notify.node = NULL;
acpi_gbl_device_notify.handler = NULL;
acpi_gbl_device_notify.context = NULL;
}
if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE;
goto unlock_and_exit;
}
/* All Other Objects */
/* Must have an existing internal object */
else {
/* Notifies allowed on this object? */
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
if (!acpi_ev_is_notify_object(node)) {
status = AE_TYPE;
goto unlock_and_exit;
}
/* Internal object exists. Find the handler and remove it */
/* Check for an existing internal object */
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
if (handler_type & (i + 1)) {
handler_obj = obj_desc->common_notify.notify_list[i];
previous_handler_obj = NULL;
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
/* Attempt to find the handler in the handler list */
/* Object exists - make sure there's an existing handler */
while (handler_obj &&
(handler_obj->notify.handler != handler)) {
previous_handler_obj = handler_obj;
handler_obj = handler_obj->notify.next[i];
}
if (handler_type & ACPI_SYSTEM_NOTIFY) {
struct acpi_object_notify_handler *handler_obj;
struct acpi_object_notify_handler *parent_obj;
notify_obj = obj_desc->common_notify.system_notify;
if (!notify_obj) {
if (!handler_obj) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
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;
}
/* 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];
}
if (handler_obj->handler != handler) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
/*
* 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) {
notify_obj = obj_desc->common_notify.device_notify;
if (!notify_obj) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
if (notify_obj->notify.handler != handler) {
status = AE_BAD_PARAMETER;
goto unlock_and_exit;
}
/* Remove the handler */
obj_desc->common_notify.device_notify = NULL;
acpi_ut_remove_reference(notify_obj);
acpi_ut_remove_reference(handler_obj);
}
}
unlock_and_exit:
unlock_and_exit:
(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);
}

View File

@ -109,9 +109,9 @@ static struct acpi_exdump_info acpi_ex_dump_package[5] = {
static struct acpi_exdump_info acpi_ex_dump_device[4] = {
{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.system_notify),
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[0]),
"System Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.device_notify),
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(device.notify_list[1]),
"Device Notify"}
};
@ -158,9 +158,9 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
"System Level"},
{ACPI_EXD_UINT32, ACPI_EXD_OFFSET(power_resource.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"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.device_notify),
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(power_resource.notify_list[1]),
"Device Notify"}
};
@ -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.length), "Length"},
{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"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.device_notify),
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.notify_list[1]),
"Device Notify"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.handler), "Handler"}
};
static struct acpi_exdump_info acpi_ex_dump_thermal[4] = {
{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"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.device_notify),
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(thermal_zone.notify_list[1]),
"Device Notify"},
{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] = {
{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_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 */

View File

@ -152,7 +152,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
case ACPI_TYPE_PROCESSOR:
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;
while (handler_desc) {
@ -480,6 +480,7 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
acpi_status status = AE_OK;
union acpi_generic_state *state_list = NULL;
union acpi_operand_object *next_object = NULL;
union acpi_operand_object *prev_object;
union acpi_generic_state *state;
u32 i;
@ -505,12 +506,21 @@ acpi_ut_update_object_reference(union acpi_operand_object *object, u16 action)
case ACPI_TYPE_POWER:
case ACPI_TYPE_THERMAL:
/* Update the notify objects for these types (if present) */
acpi_ut_update_ref_count(object->common_notify.
system_notify, action);
acpi_ut_update_ref_count(object->common_notify.
device_notify, action);
/*
* Update the notify objects for these types (if present)
* Two lists, system and device notify handlers.
*/
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
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;
case ACPI_TYPE_PACKAGE:

View File

@ -304,8 +304,8 @@ acpi_status acpi_ut_init_globals(void)
/* Global handlers */
acpi_gbl_system_notify.handler = NULL;
acpi_gbl_device_notify.handler = NULL;
acpi_gbl_global_notify[0].handler = NULL;
acpi_gbl_global_notify[1].handler = NULL;
acpi_gbl_exception_handler = NULL;
acpi_gbl_init_handler = NULL;
acpi_gbl_table_handler = NULL;

View File

@ -706,10 +706,14 @@ typedef u32 acpi_event_status;
#define ACPI_DEVICE_NOTIFY 0x2
#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY)
#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3
#define ACPI_NUM_NOTIFY_TYPES 2
#define ACPI_MAX_SYS_NOTIFY 0x7F
#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 */
typedef u8 acpi_adr_space_type;