summaryrefslogtreecommitdiff
path: root/drivers/acpi/acpica/evmisc.c
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2012-05-03 07:08:19 +0400
committerLen Brown <len.brown@intel.com>2012-06-01 19:51:50 +0400
commit86ed4bc83abf530cf2019044b74f89a39dfd6425 (patch)
tree7cd21414f6121486079be2ca9cb9ff0a7722e01b /drivers/acpi/acpica/evmisc.c
parent5134abfcfb4a8a9ef42c82dabad05762fbf04376 (diff)
downloadlinux-86ed4bc83abf530cf2019044b74f89a39dfd6425.tar.xz
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>
Diffstat (limited to 'drivers/acpi/acpica/evmisc.c')
-rw-r--r--drivers/acpi/acpica/evmisc.c185
1 files changed, 67 insertions, 118 deletions
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 51ef9f5e002d..381fce93a561 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -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);
- /*
- * 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));
+ /* Are Notifies allowed on this object? */
- /* 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) {
+ if (!acpi_ev_is_notify_object(node)) {
+ return (AE_TYPE);
+ }
- /* Notify is allowed only on these types */
+ /* Get the correct notify list type (System or Device) */
- case ACPI_TYPE_DEVICE:
- case ACPI_TYPE_THERMAL:
- case ACPI_TYPE_PROCESSOR:
+ if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+ handler_list_id = ACPI_SYSTEM_HANDLER_LIST;
+ } else {
+ handler_list_id = ACPI_DEVICE_HANDLER_LIST;
+ }
- 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;
+ /* Get the notify object attached to the namespace Node */
- default:
+ obj_desc = acpi_ns_get_attached_object(node);
+ if (obj_desc) {
- /* All other types are not supported */
+ /* We have an attached object, Get the correct handler list */
- return (AE_TYPE);
- }
+ handler_list_head =
+ obj_desc->common_notify.notify_list[handler_list_id];
}
/*
- * 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 there is no notify handler (Global or Local)
+ * for this object, just ignore the notify
*/
- 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 (!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));
- 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));
- }
+ return (AE_OK);
+ }
- 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;
+ /* Setup notify info and schedule the notify dispatcher */
- 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 */
+ info = acpi_ut_create_generic_state();
+ if (!info) {
+ return (AE_NO_MEMORY);
+ }
- 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));
+ 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));
+
+ 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) {
-
- /* 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;
- }
- }
-
- /* Invoke the system handler first, if present */
+ /* Invoke a global notify handler if installed */
- if (global_handler) {
- global_handler(notify_info->notify.node,
- notify_info->notify.value, global_context);
+ if (info->notify.global->handler) {
+ info->notify.global->handler(info->notify.node,
+ info->notify.value,
+ info->notify.global->context);
}
- /* Now invoke the per-device handler, if present */
+ /* Now invoke the local notify handler(s) if any are installed */
- handler_obj = notify_info->notify.handler_obj;
- if (handler_obj) {
- struct acpi_object_notify_handler *notifier;
+ handler_obj = info->notify.handler_list_head;
+ while (handler_obj) {
+ handler_obj->notify.handler(info->notify.node,
+ info->notify.value,
+ handler_obj->notify.context);
- 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)