Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux...
[pandora-kernel.git] / drivers / acpi / acpica / evxfevnt.c
index bfbe291..d5a5efc 100644 (file)
@@ -212,21 +212,26 @@ ACPI_EXPORT_SYMBOL(acpi_enable_event)
  *
  * FUNCTION:    acpi_set_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              action          - Enable or disable
- *                                Called from ISR or not
+ *              action          - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Enable or disable an ACPI event (general purpose)
+ * 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.
  *
  ******************************************************************************/
 acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
 {
-       acpi_status status = AE_OK;
-       acpi_cpu_flags flags;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_status status;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_set_gpe);
 
@@ -252,7 +257,6 @@ acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
                break;
 
        default:
-               ACPI_ERROR((AE_INFO, "Invalid action\n"));
                status = AE_BAD_PARAMETER;
                break;
        }
@@ -268,25 +272,31 @@ ACPI_EXPORT_SYMBOL(acpi_set_gpe)
  *
  * FUNCTION:    acpi_enable_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              type            - Purpose the GPE will be used for
+ *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
+ *                                or both
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Take a reference to a GPE and enable it if necessary
+ * 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).
  *
  ******************************************************************************/
-acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
+acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
 {
        acpi_status status = AE_OK;
-       acpi_cpu_flags flags;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_enable_gpe);
 
-       if (type & ~ACPI_GPE_TYPE_WAKE_RUN)
+       /* 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);
 
@@ -298,26 +308,43 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
                goto unlock_and_exit;
        }
 
-       if (type & ACPI_GPE_TYPE_RUNTIME) {
-               if (++gpe_event_info->runtime_count == 1) {
+       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_enable_gpe(gpe_event_info);
-                       if (ACPI_FAILURE(status))
+                       if (ACPI_FAILURE(status)) {
                                gpe_event_info->runtime_count--;
+                               goto unlock_and_exit;
+                       }
                }
        }
 
-       if (type & ACPI_GPE_TYPE_WAKE) {
+       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_BAD_PARAMETER;
+                       status = AE_TYPE;
+                       goto unlock_and_exit;
+               }
+
+               if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) {
+                       status = AE_LIMIT;      /* Too many references */
                        goto unlock_and_exit;
                }
 
                /*
-                * Wake-up GPEs are only enabled right prior to putting the
-                * system into a sleep state.
+                * Update the enable mask on the first wakeup reference. Wake GPEs
+                * are only hardware-enabled just before sleeping.
                 */
-               if (++gpe_event_info->wakeup_count == 1)
-                       acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               gpe_event_info->wakeup_count++;
+               if (gpe_event_info->wakeup_count == 1) {
+                       (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               }
        }
 
 unlock_and_exit:
@@ -330,27 +357,34 @@ ACPI_EXPORT_SYMBOL(acpi_enable_gpe)
  *
  * FUNCTION:    acpi_disable_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              type            - Purpose the GPE won't be used for any more
+ *              gpe_type        - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE
+ *                                or both
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Release a reference to a GPE and disable it if necessary
+ * DESCRIPTION: Remove a reference to a GPE. When the last reference is
+ *              removed, only then is the GPE disabled (for runtime GPEs), or
+ *              the GPE mask bit disabled (for wake GPEs)
  *
  ******************************************************************************/
-acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
+acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type)
 {
        acpi_status status = AE_OK;
-       acpi_cpu_flags flags;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_disable_gpe);
 
-       if (type & ~ACPI_GPE_TYPE_WAKE_RUN)
+       /* 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 */
 
        gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
@@ -359,18 +393,39 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 type)
                goto unlock_and_exit;
        }
 
-       if ((type & ACPI_GPE_TYPE_RUNTIME) && gpe_event_info->runtime_count) {
-               if (--gpe_event_info->runtime_count == 0)
+       /* 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_disable_gpe(gpe_event_info);
+                       if (ACPI_FAILURE(status)) {
+                               gpe_event_info->runtime_count++;
+                               goto unlock_and_exit;
+                       }
+               }
        }
 
-       if ((type & ACPI_GPE_TYPE_WAKE) && gpe_event_info->wakeup_count) {
-               /*
-                * Wake-up GPEs are not enabled after leaving system sleep
-                * states, so we don't need to disable them here.
-                */
-               if (--gpe_event_info->wakeup_count == 0)
-                       acpi_ev_update_gpe_enable_masks(gpe_event_info);
+       /*
+        * 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->wakeup_count--;
+               if (!gpe_event_info->wakeup_count) {
+                       (void)acpi_ev_update_gpe_enable_masks(gpe_event_info);
+               }
        }
 
 unlock_and_exit:
@@ -474,30 +529,23 @@ ACPI_EXPORT_SYMBOL(acpi_clear_event)
  *
  * FUNCTION:    acpi_clear_gpe
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              Flags           - Called from an ISR or not
  *
  * RETURN:      Status
  *
  * DESCRIPTION: Clear an ACPI event (general purpose)
  *
  ******************************************************************************/
-acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
+acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number)
 {
        acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_clear_gpe);
 
-       /* Use semaphore lock if not executing at interrupt level */
-
-       if (flags & ACPI_NOT_ISR) {
-               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 */
 
@@ -510,9 +558,7 @@ acpi_status acpi_clear_gpe(acpi_handle gpe_device, u32 gpe_number, u32 flags)
        status = acpi_hw_clear_gpe(gpe_event_info);
 
       unlock_and_exit:
-       if (flags & ACPI_NOT_ISR) {
-               (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-       }
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
 
@@ -578,9 +624,8 @@ ACPI_EXPORT_SYMBOL(acpi_get_event_status)
  *
  * FUNCTION:    acpi_get_gpe_status
  *
- * PARAMETERS:  gpe_device      - Parent GPE Device
+ * PARAMETERS:  gpe_device      - Parent GPE Device. NULL for GPE0/GPE1
  *              gpe_number      - GPE level within the GPE block
- *              Flags           - Called from an ISR or not
  *              event_status    - Where the current status of the event will
  *                                be returned
  *
@@ -591,21 +636,15 @@ ACPI_EXPORT_SYMBOL(acpi_get_event_status)
  ******************************************************************************/
 acpi_status
 acpi_get_gpe_status(acpi_handle gpe_device,
-                   u32 gpe_number, u32 flags, acpi_event_status * event_status)
+                   u32 gpe_number, acpi_event_status *event_status)
 {
        acpi_status status = AE_OK;
        struct acpi_gpe_event_info *gpe_event_info;
+       acpi_cpu_flags flags;
 
        ACPI_FUNCTION_TRACE(acpi_get_gpe_status);
 
-       /* Use semaphore lock if not executing at interrupt level */
-
-       if (flags & ACPI_NOT_ISR) {
-               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 */
 
@@ -623,9 +662,7 @@ acpi_get_gpe_status(acpi_handle gpe_device,
                *event_status |= ACPI_EVENT_FLAG_HANDLE;
 
       unlock_and_exit:
-       if (flags & ACPI_NOT_ISR) {
-               (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
-       }
+       acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
        return_ACPI_STATUS(status);
 }
 
@@ -682,20 +719,15 @@ acpi_install_gpe_block(acpi_handle gpe_device,
                goto unlock_and_exit;
        }
 
-       /* Run the _PRW methods and enable the GPEs */
-
-       status = acpi_ev_initialize_gpe_block(node, gpe_block);
-       if (ACPI_FAILURE(status)) {
-               goto unlock_and_exit;
-       }
-
-       /* Get the device_object attached to the node */
+       /* Install block in the device_object attached to the node */
 
        obj_desc = acpi_ns_get_attached_object(node);
        if (!obj_desc) {
 
-               /* No object, create a new one */
-
+               /*
+                * No object, create a new one (Device nodes do not always have
+                * an attached object)
+                */
                obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_DEVICE);
                if (!obj_desc) {
                        status = AE_NO_MEMORY;
@@ -714,10 +746,14 @@ acpi_install_gpe_block(acpi_handle gpe_device,
                }
        }
 
-       /* Install the GPE block in the device_object */
+       /* Now install the GPE block in the device_object */
 
        obj_desc->device.gpe_block = gpe_block;
 
+       /* Run the _PRW methods and enable the runtime GPEs in the new block */
+
+       status = acpi_ev_initialize_gpe_block(node, gpe_block);
+
       unlock_and_exit:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
        return_ACPI_STATUS(status);
@@ -848,8 +884,7 @@ acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
 
        /* Increment Index by the number of GPEs in this block */
 
-       info->next_block_base_index +=
-           (gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH);
+       info->next_block_base_index += gpe_block->gpe_count;
 
        if (info->index < info->next_block_base_index) {
                /*