Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
[pandora-kernel.git] / drivers / acpi / acpica / evxface.c
index 4a531cd..36af222 100644 (file)
@@ -691,12 +691,22 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
                return_ACPI_STATUS(status);
        }
 
+       /* Allocate memory for the handler object */
+
+       handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
+       if (!handler) {
+               status = AE_NO_MEMORY;
+               goto unlock_and_exit;
+       }
+
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
        /* Ensure that we have a valid GPE number */
 
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
        if (!gpe_event_info) {
                status = AE_BAD_PARAMETER;
-               goto unlock_and_exit;
+               goto free_and_exit;
        }
 
        /* Make sure that there isn't a handler there already */
@@ -704,24 +714,31 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
        if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
            ACPI_GPE_DISPATCH_HANDLER) {
                status = AE_ALREADY_EXISTS;
-               goto unlock_and_exit;
+               goto free_and_exit;
        }
 
        /* Allocate and init handler object */
 
-       handler = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_handler_info));
-       if (!handler) {
-               status = AE_NO_MEMORY;
-               goto unlock_and_exit;
-       }
-
        handler->address = address;
        handler->context = context;
        handler->method_node = gpe_event_info->dispatch.method_node;
+       handler->orig_flags = gpe_event_info->flags &
+                       (ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+
+       /*
+        * If the GPE is associated with a method, it might have been enabled
+        * automatically during initialization, in which case it has to be
+        * disabled now to avoid spurious execution of the handler.
+        */
+
+       if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
+           && gpe_event_info->runtime_count) {
+               handler->orig_enabled = 1;
+               (void)acpi_raw_disable_gpe(gpe_event_info);
+       }
 
        /* Install the handler */
 
-       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
        gpe_event_info->dispatch.handler = handler;
 
        /* Setup up dispatch flags to indicate handler (vs. method) */
@@ -735,6 +752,11 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
 unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
        return_ACPI_STATUS(status);
+
+free_and_exit:
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+       ACPI_FREE(handler);
+       goto unlock_and_exit;
 }
 
 ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
@@ -770,11 +792,17 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
                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_EVENTS);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
 
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
        /* Ensure that we have a valid GPE number */
 
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
@@ -798,34 +826,34 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
                goto unlock_and_exit;
        }
 
-       /* Make sure all deferred tasks are completed */
-
-       (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-       acpi_os_wait_events_complete(NULL);
-       status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
        /* Remove the handler */
 
-       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
        handler = gpe_event_info->dispatch.handler;
 
        /* Restore Method node (if any), set dispatch flags */
 
        gpe_event_info->dispatch.method_node = handler->method_node;
-       gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK;       /* Clear bits */
-       if (handler->method_node) {
-               gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD;
-       }
-       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+       gpe_event_info->flags &=
+               ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
+       gpe_event_info->flags |= handler->orig_flags;
+
+       /*
+        * If the GPE was previously associated with a method and it was
+        * enabled, it should be enabled at this point to restore the
+        * post-initialization configuration.
+        */
+
+       if ((handler->orig_flags & ACPI_GPE_DISPATCH_METHOD)
+           && handler->orig_enabled)
+               (void)acpi_raw_enable_gpe(gpe_event_info);
 
        /* Now we can free the handler object */
 
        ACPI_FREE(handler);
 
-      unlock_and_exit:
+unlock_and_exit:
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
        (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
        return_ACPI_STATUS(status);
 }