===================================================================
@@ -225,6 +225,7 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_eve
* ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
* ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
* ACPI_ALL_NOTIFY: both system and device
+ * node - Device the notifies will be handled for
* handler - Address of the handler
* context - Value passed to the handler on each GPE
* next - Address of a handler object to link to
@@ -237,10 +238,12 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_eve
static void
acpi_populate_handler_object(struct acpi_object_notify_handler *handler_obj,
u32 handler_type,
+ struct acpi_namespace_node *node,
acpi_notify_handler handler, void *context,
struct acpi_object_notify_handler *next)
{
handler_obj->handler_type = handler_type;
+ handler_obj->node = node;
handler_obj->handler = handler;
handler_obj->context = context;
handler_obj->next = next;
@@ -251,6 +254,7 @@ acpi_populate_handler_object(struct acpi
* FUNCTION: acpi_add_handler_object
*
* PARAMETERS: parent_obj - Parent of the new object
+ * node - Device the notifies will be handled for
* handler - Address of the handler
* context - Value passed to the handler on each GPE
*
@@ -261,6 +265,7 @@ acpi_populate_handler_object(struct acpi
******************************************************************************/
static acpi_status
acpi_add_handler_object(struct acpi_object_notify_handler *parent_obj,
+ struct acpi_namespace_node *node,
acpi_notify_handler handler, void *context)
{
struct acpi_object_notify_handler *handler_obj;
@@ -275,6 +280,7 @@ acpi_add_handler_object(struct acpi_obje
acpi_populate_handler_object(handler_obj,
ACPI_SYSTEM_NOTIFY,
+ node,
handler, context,
parent_obj->next);
parent_obj->next = handler_obj;
@@ -339,28 +345,43 @@ acpi_install_notify_handler(acpi_handle
*/
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)) {
+ /* For a device notify, make sure there's no handler. */
+ if ((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;
- }
+ /* System notifies may have more handlers installed. */
+ if ((handler_type & ACPI_SYSTEM_NOTIFY) &&
+ acpi_gbl_device_notify.handler) {
+ if (handler_type & ACPI_DEVICE_NOTIFY) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
- if (handler_type & ACPI_DEVICE_NOTIFY) {
- acpi_gbl_device_notify.node = node;
- acpi_gbl_device_notify.handler = handler;
- acpi_gbl_device_notify.context = context;
+ status = acpi_add_handler_object(
+ &acpi_gbl_device_notify,
+ node,
+ handler,
+ context);
+ goto unlock_and_exit;
}
+ if (handler_type & ACPI_SYSTEM_NOTIFY)
+ acpi_populate_handler_object(&acpi_gbl_system_notify,
+ handler_type,
+ node,
+ handler, context,
+ NULL);
+
+ if (handler_type & ACPI_DEVICE_NOTIFY)
+ acpi_populate_handler_object(&acpi_gbl_device_notify,
+ handler_type,
+ node,
+ handler, context,
+ NULL);
+
/* Global notify handler installed */
}
@@ -404,6 +425,7 @@ acpi_install_notify_handler(acpi_handle
parent_obj = ¬ify_obj->notify;
status = acpi_add_handler_object(parent_obj,
+ node,
handler,
context);
goto unlock_and_exit;
@@ -441,6 +463,7 @@ acpi_install_notify_handler(acpi_handle
acpi_populate_handler_object(¬ify_obj->notify,
handler_type,
+ node,
handler, context,
NULL);
@@ -534,9 +557,53 @@ acpi_remove_notify_handler(acpi_handle d
}
if (handler_type & ACPI_SYSTEM_NOTIFY) {
- acpi_gbl_system_notify.node = NULL;
- acpi_gbl_system_notify.handler = NULL;
- acpi_gbl_system_notify.context = NULL;
+ struct acpi_object_notify_handler *handler_obj;
+ struct acpi_object_notify_handler *parent_obj;
+
+ handler_obj = &acpi_gbl_system_notify;
+ parent_obj = NULL;
+ while (handler_obj->handler != handler) {
+ if (handler_obj->next) {
+ parent_obj = handler_obj;
+ handler_obj = handler_obj->next;
+ } else {
+ break;
+ }
+ }
+
+ 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 nonstatic object.
+ * Second, we may need to remove the static object's
+ * handler data, while nonstatic objects exist.
+ * Finally, we may need to clear the static object's
+ * fields.
+ */
+ if (parent_obj) {
+ /* Nonstatic object is being removed. */
+ parent_obj->next = handler_obj->next;
+ ACPI_FREE(handler_obj);
+ } else if (acpi_gbl_system_notify.next) {
+ /*
+ * The handler matches the static object, but
+ * there are more handler objects in the list.
+ * Replace the static object's data with the
+ * first next object's data and remove that
+ * object.
+ */
+ handler_obj = acpi_gbl_system_notify.next;
+ acpi_gbl_system_notify = *handler_obj;
+ ACPI_FREE(handler_obj);
+ } else {
+ acpi_gbl_system_notify.node = NULL;
+ acpi_gbl_system_notify.handler = NULL;
+ acpi_gbl_system_notify.context = NULL;
+ }
}
if (handler_type & ACPI_DEVICE_NOTIFY) {
===================================================================
@@ -221,9 +221,8 @@ static void ACPI_SYSTEM_XFACE acpi_ev_no
{
union acpi_generic_state *notify_info =
(union acpi_generic_state *)context;
- acpi_notify_handler global_handler = NULL;
- void *global_context = NULL;
union acpi_operand_object *handler_obj;
+ struct acpi_object_notify_handler *notifier = NULL;
ACPI_FUNCTION_ENTRY();
@@ -233,34 +232,30 @@ static void ACPI_SYSTEM_XFACE acpi_ev_no
*/
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
- /* Global system notification handler */
+ /* Global system notification */
- if (acpi_gbl_system_notify.handler) {
- global_handler = acpi_gbl_system_notify.handler;
- global_context = acpi_gbl_system_notify.context;
- }
+ if (acpi_gbl_system_notify.handler)
+ notifier = &acpi_gbl_system_notify;
} else {
- /* Global driver notification handler */
+ /* Global driver notification */
- if (acpi_gbl_device_notify.handler) {
- global_handler = acpi_gbl_device_notify.handler;
- global_context = acpi_gbl_device_notify.context;
- }
+ if (acpi_gbl_device_notify.handler)
+ notifier = &acpi_gbl_device_notify;
}
- /* Invoke the system handler first, if present */
+ /* Invoke the system handlers first, if present */
- if (global_handler) {
- global_handler(notify_info->notify.node,
- notify_info->notify.value, global_context);
+ while (notifier) {
+ notifier->handler(notify_info->notify.node,
+ notify_info->notify.value,
+ notifier->context);
+ notifier = notifier->next;
}
/* 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,