Merge branch 'acpica' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[linux-2.6.git] / drivers / acpi / acpica / evxfevnt.c
index 18b3f14..0ec900d 100644 (file)
@@ -213,101 +213,71 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_clear_and_enable_gpe
- *
- * PARAMETERS:  gpe_event_info  - GPE to enable
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Clear the given GPE from stale events and enable it.
- *
- ******************************************************************************/
-static acpi_status
-acpi_clear_and_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-       acpi_status status;
-
-       /*
-        * We will only allow a GPE to be enabled if it has either an
-        * associated method (_Lxx/_Exx) or a handler. Otherwise, the
-        * GPE will be immediately disabled by acpi_ev_gpe_dispatch the
-        * first time it fires.
-        */
-       if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) {
-               return_ACPI_STATUS(AE_NO_HANDLER);
-       }
-
-       /* Clear the GPE (of stale events) */
-       status = acpi_hw_clear_gpe(gpe_event_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Enable the requested GPE */
-       status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
-
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_set_gpe
+ * FUNCTION:    acpi_gpe_wakeup
  *
  * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              action          - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
+ *              Action          - Enable or Disable
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
- *              the reference count mechanism used in the acpi_enable_gpe and
- *              acpi_disable_gpe interfaces -- and should be used with care.
- *
- * Note: Typically used to disable a runtime GPE for short period of time,
- * then re-enable it, without disturbing the existing reference counts. This
- * is useful, for example, in the Embedded Controller (EC) driver.
+ * DESCRIPTION: Set or clear the GPE's wakeup enable mask bit.
  *
  ******************************************************************************/
-acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
+acpi_status acpi_gpe_wakeup(acpi_handle gpe_device, u32 gpe_number, u8 action)
 {
+       acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
-       acpi_status status;
+       struct acpi_gpe_register_info *gpe_register_info;
        acpi_cpu_flags flags;
+       u32 register_bit;
 
-       ACPI_FUNCTION_TRACE(acpi_set_gpe);
+       ACPI_FUNCTION_TRACE(acpi_gpe_wakeup);
 
        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) {
+       if (!gpe_event_info || !(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
                status = AE_BAD_PARAMETER;
                goto unlock_and_exit;
        }
 
+       gpe_register_info = gpe_event_info->register_info;
+       if (!gpe_register_info) {
+               status = AE_NOT_EXIST;
+               goto unlock_and_exit;
+       }
+
+       register_bit =
+           acpi_hw_get_gpe_register_bit(gpe_event_info, gpe_register_info);
+
        /* Perform the action */
 
        switch (action) {
        case ACPI_GPE_ENABLE:
-               status = acpi_clear_and_enable_gpe(gpe_event_info);
+               ACPI_SET_BIT(gpe_register_info->enable_for_wake,
+                            (u8)register_bit);
                break;
 
        case ACPI_GPE_DISABLE:
-               status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+               ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake,
+                              (u8)register_bit);
                break;
 
        default:
+               ACPI_ERROR((AE_INFO, "%u, Invalid action", action));
                status = AE_BAD_PARAMETER;
                break;
        }
 
-      unlock_and_exit:
+unlock_and_exit:
        acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_set_gpe)
+ACPI_EXPORT_SYMBOL(acpi_gpe_wakeup)
 
 /*******************************************************************************
  *
@@ -315,17 +285,14 @@ ACPI_EXPORT_SYMBOL(acpi_set_gpe)
  *
  * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
- *                                or both
  *
  * RETURN:      Status
  *
  * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is
- *              hardware-enabled (for runtime GPEs), or the GPE register mask
- *              is updated (for wake GPEs).
+ *              hardware-enabled.
  *
  ******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
 {
        acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
@@ -333,12 +300,6 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
 
        ACPI_FUNCTION_TRACE(acpi_enable_gpe);
 
-       /* Parameter validation */
-
-       if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
        /* Ensure that we have a valid GPE number */
@@ -349,46 +310,19 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
                goto unlock_and_exit;
        }
 
-       if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
-               if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
-                       status = AE_LIMIT;      /* Too many references */
-                       goto unlock_and_exit;
-               }
-
-               gpe_event_info->runtime_count++;
-               if (gpe_event_info->runtime_count == 1) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-                       if (ACPI_SUCCESS(status)) {
-                               status = acpi_clear_and_enable_gpe(gpe_event_info);
-                       }
-
-                       if (ACPI_FAILURE(status)) {
-                               gpe_event_info->runtime_count--;
-                               goto unlock_and_exit;
-                       }
-               }
+       if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) {
+               status = AE_LIMIT;      /* Too many references */
+               goto unlock_and_exit;
        }
 
-       if (gpe_type & ACPI_GPE_TYPE_WAKE) {
-               /* The GPE must have the ability to wake the system */
-
-               if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
-                       status = AE_TYPE;
-                       goto unlock_and_exit;
+       gpe_event_info->runtime_count++;
+       if (gpe_event_info->runtime_count == 1) {
+               status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
+               if (ACPI_SUCCESS(status)) {
+                       status = acpi_ev_enable_gpe(gpe_event_info);
                }
-
-               if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) {
-                       status = AE_LIMIT;      /* Too many references */
-                       goto unlock_and_exit;
-               }
-
-               /*
-                * Update the enable mask on the first wakeup reference. Wake GPEs
-                * are only hardware-enabled just before sleeping.
-                */
-               gpe_event_info->wakeup_count++;
-               if (gpe_event_info->wakeup_count == 1) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               if (ACPI_FAILURE(status)) {
+                       gpe_event_info->runtime_count--;
                }
        }
 
@@ -404,8 +338,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
  *
  * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
- *                                or both
  *
  * RETURN:      Status
  *
@@ -414,7 +346,7 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
  *              the GPE mask bit disabled (for wake GPEs)
  *
  ******************************************************************************/
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
 {
        acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
@@ -422,12 +354,6 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
 
        ACPI_FUNCTION_TRACE(acpi_disable_gpe);
 
-       /* Parameter validation */
-
-       if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
        flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
 
        /* Ensure that we have a valid GPE number */
@@ -440,41 +366,21 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type
 
        /* Hardware-disable a runtime GPE on removal of the last reference */
 
-       if (gpe_type & ACPI_GPE_TYPE_RUNTIME) {
-               if (!gpe_event_info->runtime_count) {
-                       status = AE_LIMIT;      /* There are no references to remove */
-                       goto unlock_and_exit;
-               }
-
-               gpe_event_info->runtime_count--;
-               if (!gpe_event_info->runtime_count) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
-                       if (ACPI_SUCCESS(status)) {
-                               status = acpi_hw_low_set_gpe(gpe_event_info,
-                                                            ACPI_GPE_DISABLE);
-                       }
-
-                       if (ACPI_FAILURE(status)) {
-                               gpe_event_info->runtime_count++;
-                               goto unlock_and_exit;
-                       }
-               }
+       if (!gpe_event_info->runtime_count) {
+               status = AE_LIMIT;      /* There are no references to remove */
+               goto unlock_and_exit;
        }
 
-       /*
-        * Update masks for wake GPE on removal of the last reference.
-        * No need to hardware-disable wake GPEs here, they are not currently
-        * enabled.
-        */
-       if (gpe_type & ACPI_GPE_TYPE_WAKE) {
-               if (!gpe_event_info->wakeup_count) {
-                       status = AE_LIMIT;      /* There are no references to remove */
-                       goto unlock_and_exit;
+       gpe_event_info->runtime_count--;
+       if (!gpe_event_info->runtime_count) {
+               status = acpi_ev_update_gpe_enable_mask(gpe_event_info);
+               if (ACPI_SUCCESS(status)) {
+                       status =
+                           acpi_hw_low_set_gpe(gpe_event_info,
+                                               ACPI_GPE_DISABLE);
                }
-
-               gpe_event_info->wakeup_count--;
-               if (!gpe_event_info->wakeup_count) {
-                       status = acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               if (ACPI_FAILURE(status)) {
+                       gpe_event_info->runtime_count++;
                }
        }
 
@@ -486,6 +392,59 @@ ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
 
 /*******************************************************************************
  *
+ * FUNCTION:    acpi_gpe_can_wake
+ *
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
+ *              gpe_number      - GPE level within the GPE block
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Set the ACPI_GPE_CAN_WAKE flag for the given GPE.  If the GPE
+ *              has a corresponding method and is currently enabled, disable it
+ *              (GPEs with corresponding methods are enabled unconditionally
+ *              during initialization, but GPEs that can wake up are expected
+ *              to be initially disabled).
+ *
+ ******************************************************************************/
+acpi_status acpi_gpe_can_wake(acpi_handle gpe_device, u32 gpe_number)
+{
+       acpi_status status = AE_OK;
+       struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
+       u8 disable = 0;
+
+       ACPI_FUNCTION_TRACE(acpi_gpe_can_wake);
+
+       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;
+       }
+
+       if (gpe_event_info->flags & ACPI_GPE_CAN_WAKE) {
+               goto unlock_and_exit;
+       }
+
+       gpe_event_info->flags |= ACPI_GPE_CAN_WAKE;
+       disable = (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD)
+               && gpe_event_info->runtime_count;
+
+unlock_and_exit:
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+
+       if (disable)
+               status = acpi_disable_gpe(gpe_device, gpe_number);
+
+       return_ACPI_STATUS(status);
+}
+ACPI_EXPORT_SYMBOL(acpi_gpe_can_wake)
+
+/*******************************************************************************
+ *
  * FUNCTION:    acpi_disable_event
  *
  * PARAMETERS:  Event           - The fixed eventto be enabled
@@ -800,7 +759,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
 
        obj_desc->device.gpe_block = gpe_block;
 
-       /* Run the _PRW methods and enable the runtime GPEs in the new block */
+       /* Enable the runtime GPEs in the new block */
 
        status = acpi_ev_initialize_gpe_block(node, gpe_block);