From patchwork Sun Mar 7 23:35:05 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Rafael Wysocki X-Patchwork-Id: 83985 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o27NZ9JE018903 for ; Sun, 7 Mar 2010 23:35:09 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751063Ab0CGXfI (ORCPT ); Sun, 7 Mar 2010 18:35:08 -0500 Received: from ogre.sisk.pl ([217.79.144.158]:58354 "EHLO ogre.sisk.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751158Ab0CGXfG (ORCPT ); Sun, 7 Mar 2010 18:35:06 -0500 Received: from localhost (localhost.localdomain [127.0.0.1]) by ogre.sisk.pl (Postfix) with ESMTP id 62494147752; Mon, 8 Mar 2010 00:09:46 +0100 (CET) Received: from ogre.sisk.pl ([127.0.0.1]) by localhost (ogre.sisk.pl [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id 19617-02; Mon, 8 Mar 2010 00:09:31 +0100 (CET) Received: from tosh.localnet (220-bem-13.acn.waw.pl [82.210.184.220]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ogre.sisk.pl (Postfix) with ESMTP id D5C3B174971; Mon, 8 Mar 2010 00:09:31 +0100 (CET) From: "Rafael J. Wysocki" To: "Moore, Robert" Subject: [RFC][PATCH 1/3] ACPI / ACPICA: Multiple system notify handlers for the root object Date: Mon, 8 Mar 2010 00:35:05 +0100 User-Agent: KMail/1.12.4 (Linux/2.6.33-git-rjw; KDE/4.3.5; x86_64; ; ) Cc: Len Brown , ACPI Devel Maling List , Matthew Garrett References: <201003080034.11053.rjw@sisk.pl> In-Reply-To: <201003080034.11053.rjw@sisk.pl> MIME-Version: 1.0 Message-Id: <201003080035.06046.rjw@sisk.pl> X-Virus-Scanned: amavisd-new at ogre.sisk.pl using MkS_Vir for Linux Sender: linux-acpi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-acpi@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Sun, 07 Mar 2010 23:35:10 +0000 (UTC) Index: linux-2.6/drivers/acpi/acpica/evxface.c =================================================================== --- linux-2.6.orig/drivers/acpi/acpica/evxface.c +++ linux-2.6/drivers/acpi/acpica/evxface.c @@ -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) { Index: linux-2.6/drivers/acpi/acpica/evmisc.c =================================================================== --- linux-2.6.orig/drivers/acpi/acpica/evmisc.c +++ linux-2.6/drivers/acpi/acpica/evmisc.c @@ -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,