ACPICA: Add support for host-installed SCI handlers.
[pandora-kernel.git] / drivers / acpi / acpica / evsci.c
index b905acf..b2f0fb2 100644 (file)
@@ -52,6 +52,52 @@ ACPI_MODULE_NAME("evsci")
 /* Local prototypes */
 static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context);
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_sci_dispatch
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status code indicates whether interrupt was handled.
+ *
+ * DESCRIPTION: Dispatch the SCI to all host-installed SCI handlers.
+ *
+ ******************************************************************************/
+
+u32 acpi_ev_sci_dispatch(void)
+{
+       struct acpi_sci_handler_info *sci_handler;
+       acpi_cpu_flags flags;
+       u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
+
+       ACPI_FUNCTION_NAME(ev_sci_dispatch);
+
+       /* Are there any host-installed SCI handlers? */
+
+       if (!acpi_gbl_sci_handler_list) {
+               return (int_status);
+       }
+
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+       /* Invoke all host-installed SCI handlers */
+
+       sci_handler = acpi_gbl_sci_handler_list;
+       while (sci_handler) {
+
+               /* Invoke the installed handler (at interrupt level) */
+
+               int_status |= sci_handler->address((u32)acpi_gbl_FADT.
+                                                  sci_interrupt,
+                                                  sci_handler->context);
+
+               sci_handler = sci_handler->next;
+       }
+
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+       return (int_status);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_sci_xrupt_handler
@@ -89,6 +135,10 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
         */
        interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
 
+       /* Invoke all host-installed SCI handlers */
+
+       interrupt_handled |= acpi_ev_sci_dispatch();
+
        return_UINT32(interrupt_handled);
 }
 
@@ -112,14 +162,13 @@ u32 ACPI_SYSTEM_XFACE acpi_ev_gpe_xrupt_handler(void *context)
        ACPI_FUNCTION_TRACE(ev_gpe_xrupt_handler);
 
        /*
-        * We are guaranteed by the ACPI CA initialization/shutdown code that
+        * We are guaranteed by the ACPICA initialization/shutdown code that
         * if this interrupt handler is installed, ACPI is enabled.
         */
 
        /* GPEs: Check for and dispatch any GPEs that have occurred */
 
        interrupt_handled |= acpi_ev_gpe_detect(gpe_xrupt_list);
-
        return_UINT32(interrupt_handled);
 }
 
@@ -150,15 +199,15 @@ u32 acpi_ev_install_sci_handler(void)
 
 /******************************************************************************
  *
- * FUNCTION:    acpi_ev_remove_sci_handler
+ * FUNCTION:    acpi_ev_remove_all_sci_handlers
  *
  * PARAMETERS:  none
  *
- * RETURN:      E_OK if handler uninstalled OK, E_ERROR if handler was not
+ * RETURN:      AE_OK if handler uninstalled, AE_ERROR if handler was not
  *              installed to begin with
  *
  * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be
- *              taken.
+ *              taken. Remove all host-installed SCI handlers.
  *
  * Note:  It doesn't seem important to disable all events or set the event
  *        enable registers to their original values. The OS should disable
@@ -167,11 +216,13 @@ u32 acpi_ev_install_sci_handler(void)
  *
  ******************************************************************************/
 
-acpi_status acpi_ev_remove_sci_handler(void)
+acpi_status acpi_ev_remove_all_sci_handlers(void)
 {
+       struct acpi_sci_handler_info *sci_handler;
+       acpi_cpu_flags flags;
        acpi_status status;
 
-       ACPI_FUNCTION_TRACE(ev_remove_sci_handler);
+       ACPI_FUNCTION_TRACE(ev_remove_all_sci_handlers);
 
        /* Just let the OS remove the handler and disable the level */
 
@@ -179,6 +230,21 @@ acpi_status acpi_ev_remove_sci_handler(void)
            acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
                                             acpi_ev_sci_xrupt_handler);
 
+       if (!acpi_gbl_sci_handler_list) {
+               return (status);
+       }
+
+       flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+       /* Free all host-installed SCI handlers */
+
+       while (acpi_gbl_sci_handler_list) {
+               sci_handler = acpi_gbl_sci_handler_list;
+               acpi_gbl_sci_handler_list = sci_handler->next;
+               ACPI_FREE(sci_handler);
+       }
+
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }