]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/commitdiff
ACPICA: Add support for multiple notify handlers
authorBob Moore <robert.moore@intel.com>
Thu, 3 May 2012 03:08:19 +0000 (11:08 +0800)
committerLen Brown <len.brown@intel.com>
Fri, 1 Jun 2012 15:51:50 +0000 (11:51 -0400)
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>
drivers/acpi/acpica/acglobal.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acobject.h
drivers/acpi/acpica/evmisc.c
drivers/acpi/acpica/evxface.c
drivers/acpi/acpica/exdump.c
drivers/acpi/acpica/utdelete.c
drivers/acpi/acpica/utglobal.c
include/acpi/actypes.h

index 4f7d3f57d05cdd24f047ca2af28209abd631e7ae..dec7994d405ce099776cd833f3b62b82939c5a99 100644 (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;
index e3922ca20e7f26e7eafa98ed4c2d23f2edf0435a..28f677834bfdc3252655f9570f5754115fb6015d 100644 (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 */
index c065078ca83bbbb0f3a09a22a609121d0d7785d7..39a2b84120be0ee98a054f6a28b2cd10c93d0bfc 100644 (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 {
index 51ef9f5e002da1048c4e99d2b8939d0c35976633..381fce93a561c73d546cbb2656dec8ec590b51ba 100644 (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);
 
-       /*
-        * 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)
index 44bef5744ebb159f383f6b19515cf6346f656582..90ae6d19364591eeaa64955dbcf5971222b52bdd 100644 (file)
 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) {
+               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;
+                               }
 
-               /* 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;
+                               acpi_gbl_global_notify[i].handler = handler;
+                               acpi_gbl_global_notify[i].context = context;
+                       }
                }
 
-               /* Global notify handler installed */
+               goto unlock_and_exit;   /* Global notify handler installed, all done */
        }
 
        /*
         * All Other Objects:
-        * Caller will only receive notifications specific to the target object.
-        * Note that only certain object types can receive notifications.
+        * Caller will only receive notifications specific to the target
+        * object. Note that only certain object types are allowed to
+        * receive notifications.
         */
-       else {
-               /* Notifies allowed on this object? */
 
-               if (!acpi_ev_is_notify_object(node)) {
-                       status = AE_TYPE;
-                       goto unlock_and_exit;
-               }
+       /* Are Notifies allowed on this object? */
 
-               /* Check for an existing internal object */
+       if (!acpi_ev_is_notify_object(node)) {
+               status = AE_TYPE;
+               goto unlock_and_exit;
+       }
 
-               obj_desc = acpi_ns_get_attached_object(node);
-               if (obj_desc) {
+       /* Check for an existing internal object, might not exist */
 
-                       /* Object exists. */
+       obj_desc = acpi_ns_get_attached_object(node);
+       if (!obj_desc) {
 
-                       /* 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;
-                       }
+               /* Create a new object */
 
-                       /* System notifies may have more handlers installed. */
-                       notify_obj = obj_desc->common_notify.system_notify;
+               obj_desc = acpi_ut_create_internal_object(node->type);
+               if (!obj_desc) {
+                       status = AE_NO_MEMORY;
+                       goto unlock_and_exit;
+               }
 
-                       if ((handler_type & ACPI_SYSTEM_NOTIFY) && notify_obj) {
-                               struct acpi_object_notify_handler *parent_obj;
+               /* Attach new object to the Node, remove local reference */
 
-                               if (handler_type & ACPI_DEVICE_NOTIFY) {
+               status = acpi_ns_attach_object(device, obj_desc, node->type);
+               acpi_ut_remove_reference(obj_desc);
+               if (ACPI_FAILURE(status)) {
+                       goto 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;
                                }
 
-                               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;
+                               handler_obj = handler_obj->notify.next[i];
                        }
                }
+       }
 
-               /* Install the handler */
+       /* Create and populate a new notify handler object */
 
-               notify_obj =
-                   acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
-               if (!notify_obj) {
-                       status = AE_NO_MEMORY;
-                       goto unlock_and_exit;
-               }
+       handler_obj = acpi_ut_create_internal_object(ACPI_TYPE_LOCAL_NOTIFY);
+       if (!handler_obj) {
+               status = AE_NO_MEMORY;
+               goto unlock_and_exit;
+       }
 
-               acpi_populate_handler_object(&notify_obj->notify,
-                                               handler_type,
-                                               handler, context,
-                                               NULL);
+       handler_obj->notify.node = node;
+       handler_obj->notify.handler_type = handler_type;
+       handler_obj->notify.handler = handler;
+       handler_obj->notify.context = context;
 
-               if (handler_type & ACPI_SYSTEM_NOTIFY) {
-                       obj_desc->common_notify.system_notify = notify_obj;
-               }
+       /* Install the handler at the list head(s) */
 
-               if (handler_type & ACPI_DEVICE_NOTIFY) {
-                       obj_desc->common_notify.device_notify = notify_obj;
-               }
+       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];
 
-               if (handler_type == ACPI_ALL_NOTIFY) {
+                       obj_desc->common_notify.notify_list[i] = handler_obj;
+               }
+       }
 
-                       /* Extra ref if installed in both */
+       /* Add an extra reference if handler was installed in both lists */
 
-                       acpi_ut_add_reference(notify_obj);
-               }
+       if (handler_type == ACPI_ALL_NOTIFY) {
+               acpi_ut_add_reference(handler_obj);
        }
 
-      unlock_and_exit:
+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;
-       }
-
-       /* Convert and validate the device handle */
-
-       node = acpi_ns_validate_handle(device);
-       if (!node) {
-               status = AE_BAD_PARAMETER;
-               goto unlock_and_exit;
+               return_ACPI_STATUS(status);
        }
 
-       /* Root Object */
+       /* Root Object. Global handlers are removed here */
 
        if (device == ACPI_ROOT_OBJECT) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Removing notify handler for namespace root object\n"));
+               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;
+                               }
 
-               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;
-               }
+                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                                 "Removing global notify handler\n"));
 
-               if (handler_type & ACPI_SYSTEM_NOTIFY) {
-                       acpi_gbl_system_notify.node = NULL;
-                       acpi_gbl_system_notify.handler = NULL;
-                       acpi_gbl_system_notify.context = NULL;
+                               acpi_gbl_global_notify[i].handler = NULL;
+                               acpi_gbl_global_notify[i].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;
-               }
+               goto unlock_and_exit;
        }
 
-       /* All Other Objects */
-
-       else {
-               /* Notifies allowed on this object? */
+       /* All other objects: Are Notifies allowed on this object? */
 
-               if (!acpi_ev_is_notify_object(node)) {
-                       status = AE_TYPE;
-                       goto unlock_and_exit;
-               }
+       if (!acpi_ev_is_notify_object(node)) {
+               status = AE_TYPE;
+               goto unlock_and_exit;
+       }
 
-               /* Check for an existing internal object */
+       /* Must have an existing internal object */
 
-               obj_desc = acpi_ns_get_attached_object(node);
-               if (!obj_desc) {
-                       status = AE_NOT_EXIST;
-                       goto unlock_and_exit;
-               }
+       obj_desc = acpi_ns_get_attached_object(node);
+       if (!obj_desc) {
+               status = AE_NOT_EXIST;
+               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) {
-                       struct acpi_object_notify_handler *handler_obj;
-                       struct acpi_object_notify_handler *parent_obj;
+       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;
 
-                       notify_obj = obj_desc->common_notify.system_notify;
-                       if (!notify_obj) {
-                               status = AE_NOT_EXIST;
-                               goto unlock_and_exit;
-                       }
+                       /* Attempt to find the handler in the handler list */
 
-                       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;
-                               }
+                       while (handler_obj &&
+                              (handler_obj->notify.handler != handler)) {
+                               previous_handler_obj = handler_obj;
+                               handler_obj = handler_obj->notify.next[i];
                        }
 
-                       if (handler_obj->handler != handler) {
-                               status = AE_BAD_PARAMETER;
+                       if (!handler_obj) {
+                               status = AE_NOT_EXIST;
                                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);
-                       }
-               }
+                       /* Remove the handler object from the list */
 
-               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 (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 */
 
-                       if (notify_obj->notify.handler != handler) {
-                               status = AE_BAD_PARAMETER;
-                               goto unlock_and_exit;
+                               obj_desc->common_notify.notify_list[i] =
+                                   handler_obj->notify.next[i];
                        }
 
-                       /* 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);
 }
 
index 836fe76e65d05882572e8c52f44dcf903e103a15..26c56545804df75281fce557d86c633a694b1fa0 100644 (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 */
index 2a6c3e183697ac68a6c6bca589116c20f8bf4520..0d50f2c6bac2ea25962b7e04d3a48ffd2146628d 100644 (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:
index 90f53b42eca9fcdfe2cda7d88a47cdb076dfc02e..78cf1fe390b3f37e4af672ce4f33ff2ca76052e7 100644 (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;
index e8bcc4742e0e9a1f9563a27907871ab6ce727817..0339a2d93f1d808f853608f1f80348bd243e7efe 100644 (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;