mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-03 17:40:04 +00:00
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:
parent
5134abfcfb
commit
86ed4bc83a
9 changed files with 294 additions and 469 deletions
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 = ¬ify_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(¬ify_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 = ¬ify_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 = ¬ify_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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue