| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /****************************************************************************** | 
|  | 2 | * | 
|  | 3 | * Module Name: evgpe - General Purpose Event handling and dispatch | 
|  | 4 | * | 
|  | 5 | *****************************************************************************/ | 
|  | 6 |  | 
|  | 7 | /* | 
| Bob Moore | 4a90c7e | 2006-01-13 16:22:00 -0500 | [diff] [blame] | 8 | * Copyright (C) 2000 - 2006, R. Byron Moore | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 9 | * All rights reserved. | 
|  | 10 | * | 
|  | 11 | * Redistribution and use in source and binary forms, with or without | 
|  | 12 | * modification, are permitted provided that the following conditions | 
|  | 13 | * are met: | 
|  | 14 | * 1. Redistributions of source code must retain the above copyright | 
|  | 15 | *    notice, this list of conditions, and the following disclaimer, | 
|  | 16 | *    without modification. | 
|  | 17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | 
|  | 18 | *    substantially similar to the "NO WARRANTY" disclaimer below | 
|  | 19 | *    ("Disclaimer") and any redistribution must be conditioned upon | 
|  | 20 | *    including a substantially similar Disclaimer requirement for further | 
|  | 21 | *    binary redistribution. | 
|  | 22 | * 3. Neither the names of the above-listed copyright holders nor the names | 
|  | 23 | *    of any contributors may be used to endorse or promote products derived | 
|  | 24 | *    from this software without specific prior written permission. | 
|  | 25 | * | 
|  | 26 | * Alternatively, this software may be distributed under the terms of the | 
|  | 27 | * GNU General Public License ("GPL") version 2 as published by the Free | 
|  | 28 | * Software Foundation. | 
|  | 29 | * | 
|  | 30 | * NO WARRANTY | 
|  | 31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | 32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | 33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | 
|  | 34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | 35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
|  | 36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
|  | 37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | 
|  | 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | 
|  | 40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | 
|  | 41 | * POSSIBILITY OF SUCH DAMAGES. | 
|  | 42 | */ | 
|  | 43 |  | 
|  | 44 | #include <acpi/acpi.h> | 
|  | 45 | #include <acpi/acevents.h> | 
|  | 46 | #include <acpi/acnamesp.h> | 
|  | 47 |  | 
|  | 48 | #define _COMPONENT          ACPI_EVENTS | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 49 | ACPI_MODULE_NAME("evgpe") | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 50 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 51 | /* Local prototypes */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 52 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 53 |  | 
|  | 54 | /******************************************************************************* | 
|  | 55 | * | 
|  | 56 | * FUNCTION:    acpi_ev_set_gpe_type | 
|  | 57 | * | 
|  | 58 | * PARAMETERS:  gpe_event_info          - GPE to set | 
|  | 59 | *              Type                    - New type | 
|  | 60 | * | 
|  | 61 | * RETURN:      Status | 
|  | 62 | * | 
|  | 63 | * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run) | 
|  | 64 | * | 
|  | 65 | ******************************************************************************/ | 
|  | 66 |  | 
|  | 67 | acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 68 | acpi_ev_set_gpe_type(struct acpi_gpe_event_info *gpe_event_info, u8 type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 69 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 70 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 72 | ACPI_FUNCTION_TRACE(ev_set_gpe_type); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 73 |  | 
|  | 74 | /* Validate type and update register enable masks */ | 
|  | 75 |  | 
|  | 76 | switch (type) { | 
|  | 77 | case ACPI_GPE_TYPE_WAKE: | 
|  | 78 | case ACPI_GPE_TYPE_RUNTIME: | 
|  | 79 | case ACPI_GPE_TYPE_WAKE_RUN: | 
|  | 80 | break; | 
|  | 81 |  | 
|  | 82 | default: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 83 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 84 | } | 
|  | 85 |  | 
|  | 86 | /* Disable the GPE if currently enabled */ | 
|  | 87 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 88 | status = acpi_ev_disable_gpe(gpe_event_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 89 |  | 
|  | 90 | /* Type was validated above */ | 
|  | 91 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 92 | gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK;	/* Clear type bits */ | 
|  | 93 | gpe_event_info->flags |= type;	/* Insert type */ | 
|  | 94 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 95 | } | 
|  | 96 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 97 | /******************************************************************************* | 
|  | 98 | * | 
|  | 99 | * FUNCTION:    acpi_ev_update_gpe_enable_masks | 
|  | 100 | * | 
|  | 101 | * PARAMETERS:  gpe_event_info          - GPE to update | 
|  | 102 | *              Type                    - What to do: ACPI_GPE_DISABLE or | 
|  | 103 | *                                        ACPI_GPE_ENABLE | 
|  | 104 | * | 
|  | 105 | * RETURN:      Status | 
|  | 106 | * | 
|  | 107 | * DESCRIPTION: Updates GPE register enable masks based on the GPE type | 
|  | 108 | * | 
|  | 109 | ******************************************************************************/ | 
|  | 110 |  | 
|  | 111 | acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 112 | acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info, | 
|  | 113 | u8 type) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 114 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 115 | struct acpi_gpe_register_info *gpe_register_info; | 
|  | 116 | u8 register_bit; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 117 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 118 | ACPI_FUNCTION_TRACE(ev_update_gpe_enable_masks); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 119 |  | 
|  | 120 | gpe_register_info = gpe_event_info->register_info; | 
|  | 121 | if (!gpe_register_info) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 122 | return_ACPI_STATUS(AE_NOT_EXIST); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 123 | } | 
|  | 124 | register_bit = gpe_event_info->register_bit; | 
|  | 125 |  | 
|  | 126 | /* 1) Disable case.  Simply clear all enable bits */ | 
|  | 127 |  | 
|  | 128 | if (type == ACPI_GPE_DISABLE) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 129 | ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, | 
|  | 130 | register_bit); | 
|  | 131 | ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit); | 
|  | 132 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 133 | } | 
|  | 134 |  | 
|  | 135 | /* 2) Enable case.  Set/Clear the appropriate enable bits */ | 
|  | 136 |  | 
|  | 137 | switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { | 
|  | 138 | case ACPI_GPE_TYPE_WAKE: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 139 | ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit); | 
|  | 140 | ACPI_CLEAR_BIT(gpe_register_info->enable_for_run, register_bit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 141 | break; | 
|  | 142 |  | 
|  | 143 | case ACPI_GPE_TYPE_RUNTIME: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 144 | ACPI_CLEAR_BIT(gpe_register_info->enable_for_wake, | 
|  | 145 | register_bit); | 
|  | 146 | ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 147 | break; | 
|  | 148 |  | 
|  | 149 | case ACPI_GPE_TYPE_WAKE_RUN: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 150 | ACPI_SET_BIT(gpe_register_info->enable_for_wake, register_bit); | 
|  | 151 | ACPI_SET_BIT(gpe_register_info->enable_for_run, register_bit); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 152 | break; | 
|  | 153 |  | 
|  | 154 | default: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 155 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 156 | } | 
|  | 157 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 158 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 159 | } | 
|  | 160 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 161 | /******************************************************************************* | 
|  | 162 | * | 
|  | 163 | * FUNCTION:    acpi_ev_enable_gpe | 
|  | 164 | * | 
|  | 165 | * PARAMETERS:  gpe_event_info          - GPE to enable | 
|  | 166 | *              write_to_hardware       - Enable now, or just mark data structs | 
|  | 167 | *                                        (WAKE GPEs should be deferred) | 
|  | 168 | * | 
|  | 169 | * RETURN:      Status | 
|  | 170 | * | 
|  | 171 | * DESCRIPTION: Enable a GPE based on the GPE type | 
|  | 172 | * | 
|  | 173 | ******************************************************************************/ | 
|  | 174 |  | 
|  | 175 | acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 176 | acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info, | 
|  | 177 | u8 write_to_hardware) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 178 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 179 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 180 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 181 | ACPI_FUNCTION_TRACE(ev_enable_gpe); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 182 |  | 
|  | 183 | /* Make sure HW enable masks are updated */ | 
|  | 184 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 185 | status = | 
|  | 186 | acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_ENABLE); | 
|  | 187 | if (ACPI_FAILURE(status)) { | 
|  | 188 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 189 | } | 
|  | 190 |  | 
|  | 191 | /* Mark wake-enabled or HW enable, or both */ | 
|  | 192 |  | 
|  | 193 | switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { | 
|  | 194 | case ACPI_GPE_TYPE_WAKE: | 
|  | 195 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 196 | ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 197 | break; | 
|  | 198 |  | 
|  | 199 | case ACPI_GPE_TYPE_WAKE_RUN: | 
|  | 200 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 201 | ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 202 |  | 
|  | 203 | /*lint -fallthrough */ | 
|  | 204 |  | 
|  | 205 | case ACPI_GPE_TYPE_RUNTIME: | 
|  | 206 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 207 | ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 208 |  | 
|  | 209 | if (write_to_hardware) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 210 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 | /* Clear the GPE (of stale events), then enable it */ | 
|  | 212 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 213 | status = acpi_hw_clear_gpe(gpe_event_info); | 
|  | 214 | if (ACPI_FAILURE(status)) { | 
|  | 215 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 216 | } | 
|  | 217 |  | 
|  | 218 | /* Enable the requested runtime GPE */ | 
|  | 219 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 220 | status = acpi_hw_write_gpe_enable_reg(gpe_event_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | } | 
|  | 222 | break; | 
|  | 223 |  | 
|  | 224 | default: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 225 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 226 | } | 
|  | 227 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 228 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 229 | } | 
|  | 230 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 231 | /******************************************************************************* | 
|  | 232 | * | 
|  | 233 | * FUNCTION:    acpi_ev_disable_gpe | 
|  | 234 | * | 
|  | 235 | * PARAMETERS:  gpe_event_info          - GPE to disable | 
|  | 236 | * | 
|  | 237 | * RETURN:      Status | 
|  | 238 | * | 
|  | 239 | * DESCRIPTION: Disable a GPE based on the GPE type | 
|  | 240 | * | 
|  | 241 | ******************************************************************************/ | 
|  | 242 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 243 | acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 244 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 245 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 246 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 247 | ACPI_FUNCTION_TRACE(ev_disable_gpe); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 248 |  | 
|  | 249 | if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 250 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 251 | } | 
|  | 252 |  | 
|  | 253 | /* Make sure HW enable masks are updated */ | 
|  | 254 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 255 | status = | 
|  | 256 | acpi_ev_update_gpe_enable_masks(gpe_event_info, ACPI_GPE_DISABLE); | 
|  | 257 | if (ACPI_FAILURE(status)) { | 
|  | 258 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 259 | } | 
|  | 260 |  | 
|  | 261 | /* Mark wake-disabled or HW disable, or both */ | 
|  | 262 |  | 
|  | 263 | switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) { | 
|  | 264 | case ACPI_GPE_TYPE_WAKE: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 265 | ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 266 | break; | 
|  | 267 |  | 
|  | 268 | case ACPI_GPE_TYPE_WAKE_RUN: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 269 | ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 270 |  | 
|  | 271 | /*lint -fallthrough */ | 
|  | 272 |  | 
|  | 273 | case ACPI_GPE_TYPE_RUNTIME: | 
|  | 274 |  | 
|  | 275 | /* Disable the requested runtime GPE */ | 
|  | 276 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 277 | ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); | 
|  | 278 | status = acpi_hw_write_gpe_enable_reg(gpe_event_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 279 | break; | 
|  | 280 |  | 
|  | 281 | default: | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 282 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 283 | } | 
|  | 284 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 285 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 286 | } | 
|  | 287 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 288 | /******************************************************************************* | 
|  | 289 | * | 
|  | 290 | * FUNCTION:    acpi_ev_get_gpe_event_info | 
|  | 291 | * | 
|  | 292 | * PARAMETERS:  gpe_device          - Device node.  NULL for GPE0/GPE1 | 
|  | 293 | *              gpe_number          - Raw GPE number | 
|  | 294 | * | 
|  | 295 | * RETURN:      A GPE event_info struct. NULL if not a valid GPE | 
|  | 296 | * | 
|  | 297 | * DESCRIPTION: Returns the event_info struct associated with this GPE. | 
|  | 298 | *              Validates the gpe_block and the gpe_number | 
|  | 299 | * | 
|  | 300 | *              Should be called only when the GPE lists are semaphore locked | 
|  | 301 | *              and not subject to change. | 
|  | 302 | * | 
|  | 303 | ******************************************************************************/ | 
|  | 304 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 305 | struct acpi_gpe_event_info *acpi_ev_get_gpe_event_info(acpi_handle gpe_device, | 
|  | 306 | u32 gpe_number) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 307 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 308 | union acpi_operand_object *obj_desc; | 
|  | 309 | struct acpi_gpe_block_info *gpe_block; | 
|  | 310 | acpi_native_uint i; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 311 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 312 | ACPI_FUNCTION_ENTRY(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 313 |  | 
|  | 314 | /* A NULL gpe_block means use the FADT-defined GPE block(s) */ | 
|  | 315 |  | 
|  | 316 | if (!gpe_device) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 317 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 318 | /* Examine GPE Block 0 and 1 (These blocks are permanent) */ | 
|  | 319 |  | 
|  | 320 | for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) { | 
|  | 321 | gpe_block = acpi_gbl_gpe_fadt_blocks[i]; | 
|  | 322 | if (gpe_block) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 323 | if ((gpe_number >= gpe_block->block_base_number) | 
|  | 324 | && (gpe_number < | 
|  | 325 | gpe_block->block_base_number + | 
|  | 326 | (gpe_block->register_count * 8))) { | 
|  | 327 | return (&gpe_block-> | 
|  | 328 | event_info[gpe_number - | 
|  | 329 | gpe_block-> | 
|  | 330 | block_base_number]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 331 | } | 
|  | 332 | } | 
|  | 333 | } | 
|  | 334 |  | 
|  | 335 | /* The gpe_number was not in the range of either FADT GPE block */ | 
|  | 336 |  | 
|  | 337 | return (NULL); | 
|  | 338 | } | 
|  | 339 |  | 
|  | 340 | /* A Non-NULL gpe_device means this is a GPE Block Device */ | 
|  | 341 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 342 | obj_desc = | 
|  | 343 | acpi_ns_get_attached_object((struct acpi_namespace_node *) | 
|  | 344 | gpe_device); | 
|  | 345 | if (!obj_desc || !obj_desc->device.gpe_block) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 346 | return (NULL); | 
|  | 347 | } | 
|  | 348 |  | 
|  | 349 | gpe_block = obj_desc->device.gpe_block; | 
|  | 350 |  | 
|  | 351 | if ((gpe_number >= gpe_block->block_base_number) && | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 352 | (gpe_number < | 
|  | 353 | gpe_block->block_base_number + (gpe_block->register_count * 8))) { | 
|  | 354 | return (&gpe_block-> | 
|  | 355 | event_info[gpe_number - gpe_block->block_base_number]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 356 | } | 
|  | 357 |  | 
|  | 358 | return (NULL); | 
|  | 359 | } | 
|  | 360 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 361 | /******************************************************************************* | 
|  | 362 | * | 
|  | 363 | * FUNCTION:    acpi_ev_gpe_detect | 
|  | 364 | * | 
|  | 365 | * PARAMETERS:  gpe_xrupt_list      - Interrupt block for this interrupt. | 
|  | 366 | *                                    Can have multiple GPE blocks attached. | 
|  | 367 | * | 
|  | 368 | * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED | 
|  | 369 | * | 
|  | 370 | * DESCRIPTION: Detect if any GP events have occurred.  This function is | 
|  | 371 | *              executed at interrupt level. | 
|  | 372 | * | 
|  | 373 | ******************************************************************************/ | 
|  | 374 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 375 | u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 376 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 377 | acpi_status status; | 
|  | 378 | struct acpi_gpe_block_info *gpe_block; | 
| Bob Moore | 0897831 | 2005-10-21 00:00:00 -0400 | [diff] [blame] | 379 | struct acpi_gpe_register_info *gpe_register_info; | 
|  | 380 | u32 int_status = ACPI_INTERRUPT_NOT_HANDLED; | 
|  | 381 | u8 enabled_status_byte; | 
|  | 382 | u32 status_reg; | 
|  | 383 | u32 enable_reg; | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 384 | acpi_cpu_flags flags; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 385 | acpi_native_uint i; | 
|  | 386 | acpi_native_uint j; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 387 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 388 | ACPI_FUNCTION_NAME(ev_gpe_detect); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 389 |  | 
|  | 390 | /* Check for the case where there are no GPEs */ | 
|  | 391 |  | 
|  | 392 | if (!gpe_xrupt_list) { | 
|  | 393 | return (int_status); | 
|  | 394 | } | 
|  | 395 |  | 
| Bob Moore | 967440e | 2006-06-23 17:04:00 -0400 | [diff] [blame] | 396 | /* | 
|  | 397 | * We need to obtain the GPE lock for both the data structs and registers | 
|  | 398 | * Note: Not necessary to obtain the hardware lock, since the GPE registers | 
|  | 399 | * are owned by the gpe_lock. | 
|  | 400 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 401 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 
| Bob Moore | 4c90ece | 2006-06-08 16:29:00 -0400 | [diff] [blame] | 402 |  | 
|  | 403 | /* Examine all GPE blocks attached to this interrupt level */ | 
|  | 404 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 405 | gpe_block = gpe_xrupt_list->gpe_block_list_head; | 
|  | 406 | while (gpe_block) { | 
|  | 407 | /* | 
|  | 408 | * Read all of the 8-bit GPE status and enable registers | 
|  | 409 | * in this GPE block, saving all of them. | 
|  | 410 | * Find all currently active GP events. | 
|  | 411 | */ | 
|  | 412 | for (i = 0; i < gpe_block->register_count; i++) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 413 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 414 | /* Get the next status/enable pair */ | 
|  | 415 |  | 
|  | 416 | gpe_register_info = &gpe_block->register_info[i]; | 
|  | 417 |  | 
|  | 418 | /* Read the Status Register */ | 
|  | 419 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 420 | status = | 
|  | 421 | acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, | 
|  | 422 | &status_reg, | 
|  | 423 | &gpe_register_info-> | 
|  | 424 | status_address); | 
|  | 425 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 426 | goto unlock_and_exit; | 
|  | 427 | } | 
|  | 428 |  | 
|  | 429 | /* Read the Enable Register */ | 
|  | 430 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 431 | status = | 
|  | 432 | acpi_hw_low_level_read(ACPI_GPE_REGISTER_WIDTH, | 
|  | 433 | &enable_reg, | 
|  | 434 | &gpe_register_info-> | 
|  | 435 | enable_address); | 
|  | 436 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 437 | goto unlock_and_exit; | 
|  | 438 | } | 
|  | 439 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 440 | ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS, | 
|  | 441 | "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n", | 
|  | 442 | gpe_register_info->base_gpe_number, | 
|  | 443 | status_reg, enable_reg)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 444 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 445 | /* Check if there is anything active at all in this register */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 446 |  | 
|  | 447 | enabled_status_byte = (u8) (status_reg & enable_reg); | 
|  | 448 | if (!enabled_status_byte) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 449 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 450 | /* No active GPEs in this register, move on */ | 
|  | 451 |  | 
|  | 452 | continue; | 
|  | 453 | } | 
|  | 454 |  | 
|  | 455 | /* Now look at the individual GPEs in this byte register */ | 
|  | 456 |  | 
|  | 457 | for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 458 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 459 | /* Examine one GPE bit */ | 
|  | 460 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 461 | if (enabled_status_byte & | 
|  | 462 | acpi_gbl_decode_to8bit[j]) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 463 | /* | 
|  | 464 | * Found an active GPE. Dispatch the event to a handler | 
|  | 465 | * or method. | 
|  | 466 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 467 | int_status |= | 
|  | 468 | acpi_ev_gpe_dispatch(&gpe_block-> | 
|  | 469 | event_info[(i * | 
|  | 470 | ACPI_GPE_REGISTER_WIDTH) | 
|  | 471 | + | 
|  | 472 | j], | 
|  | 473 | (u32) j + | 
|  | 474 | gpe_register_info-> | 
|  | 475 | base_gpe_number); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 476 | } | 
|  | 477 | } | 
|  | 478 | } | 
|  | 479 |  | 
|  | 480 | gpe_block = gpe_block->next; | 
|  | 481 | } | 
|  | 482 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 483 | unlock_and_exit: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 484 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 485 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 486 | return (int_status); | 
|  | 487 | } | 
|  | 488 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 489 | /******************************************************************************* | 
|  | 490 | * | 
|  | 491 | * FUNCTION:    acpi_ev_asynch_execute_gpe_method | 
|  | 492 | * | 
|  | 493 | * PARAMETERS:  Context (gpe_event_info) - Info for this GPE | 
|  | 494 | * | 
|  | 495 | * RETURN:      None | 
|  | 496 | * | 
| Bob Moore | 4119532 | 2006-05-26 16:36:00 -0400 | [diff] [blame] | 497 | * DESCRIPTION: Perform the actual execution of a GPE control method. This | 
|  | 498 | *              function is called from an invocation of acpi_os_execute and | 
|  | 499 | *              therefore does NOT execute at interrupt level - so that | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 500 | *              the control method itself is not executed in the context of | 
|  | 501 | *              an interrupt handler. | 
|  | 502 | * | 
|  | 503 | ******************************************************************************/ | 
|  | 504 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 505 | static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 506 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 507 | struct acpi_gpe_event_info *gpe_event_info = (void *)context; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 508 | acpi_status status; | 
|  | 509 | struct acpi_gpe_event_info local_gpe_event_info; | 
| Bob Moore | 4119532 | 2006-05-26 16:36:00 -0400 | [diff] [blame] | 510 | struct acpi_evaluate_info *info; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 511 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 512 | ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 513 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 514 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); | 
|  | 515 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 516 | return_VOID; | 
|  | 517 | } | 
|  | 518 |  | 
|  | 519 | /* Must revalidate the gpe_number/gpe_block */ | 
|  | 520 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 521 | if (!acpi_ev_valid_gpe_event(gpe_event_info)) { | 
|  | 522 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 523 | return_VOID; | 
|  | 524 | } | 
|  | 525 |  | 
|  | 526 | /* Set the GPE flags for return to enabled state */ | 
|  | 527 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 528 | (void)acpi_ev_enable_gpe(gpe_event_info, FALSE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 529 |  | 
|  | 530 | /* | 
|  | 531 | * Take a snapshot of the GPE info for this level - we copy the | 
|  | 532 | * info to prevent a race condition with remove_handler/remove_block. | 
|  | 533 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 534 | ACPI_MEMCPY(&local_gpe_event_info, gpe_event_info, | 
|  | 535 | sizeof(struct acpi_gpe_event_info)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 536 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 537 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); | 
|  | 538 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 539 | return_VOID; | 
|  | 540 | } | 
|  | 541 |  | 
|  | 542 | /* | 
|  | 543 | * Must check for control method type dispatch one more | 
|  | 544 | * time to avoid race with ev_gpe_install_handler | 
|  | 545 | */ | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 546 | if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 547 | ACPI_GPE_DISPATCH_METHOD) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 548 |  | 
| Bob Moore | 4119532 | 2006-05-26 16:36:00 -0400 | [diff] [blame] | 549 | /* Allocate the evaluation information block */ | 
|  | 550 |  | 
|  | 551 | info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); | 
|  | 552 | if (!info) { | 
|  | 553 | status = AE_NO_MEMORY; | 
|  | 554 | } else { | 
|  | 555 | /* | 
|  | 556 | * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx | 
|  | 557 | * control method that corresponds to this GPE | 
|  | 558 | */ | 
|  | 559 | info->prefix_node = | 
|  | 560 | local_gpe_event_info.dispatch.method_node; | 
|  | 561 | info->parameters = | 
|  | 562 | ACPI_CAST_PTR(union acpi_operand_object *, | 
|  | 563 | gpe_event_info); | 
|  | 564 | info->parameter_type = ACPI_PARAM_GPE; | 
|  | 565 | info->flags = ACPI_IGNORE_RETURN_VALUE; | 
|  | 566 |  | 
|  | 567 | status = acpi_ns_evaluate(info); | 
|  | 568 | ACPI_FREE(info); | 
|  | 569 | } | 
|  | 570 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 571 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 572 | ACPI_EXCEPTION((AE_INFO, status, | 
| Bob Moore | 4c90ece | 2006-06-08 16:29:00 -0400 | [diff] [blame] | 573 | "While evaluating GPE method [%4.4s]", | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 574 | acpi_ut_get_node_name | 
|  | 575 | (local_gpe_event_info.dispatch. | 
| Bob Moore | 4c90ece | 2006-06-08 16:29:00 -0400 | [diff] [blame] | 576 | method_node))); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 577 | } | 
|  | 578 | } | 
|  | 579 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 580 | if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 581 | ACPI_GPE_LEVEL_TRIGGERED) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 582 | /* | 
|  | 583 | * GPE is level-triggered, we clear the GPE status bit after | 
|  | 584 | * handling the event. | 
|  | 585 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 586 | status = acpi_hw_clear_gpe(&local_gpe_event_info); | 
|  | 587 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 588 | return_VOID; | 
|  | 589 | } | 
|  | 590 | } | 
|  | 591 |  | 
|  | 592 | /* Enable this GPE */ | 
|  | 593 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 594 | (void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 595 | return_VOID; | 
|  | 596 | } | 
|  | 597 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 598 | /******************************************************************************* | 
|  | 599 | * | 
|  | 600 | * FUNCTION:    acpi_ev_gpe_dispatch | 
|  | 601 | * | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 602 | * PARAMETERS:  gpe_event_info  - Info for this GPE | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 603 | *              gpe_number      - Number relative to the parent GPE block | 
|  | 604 | * | 
|  | 605 | * RETURN:      INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED | 
|  | 606 | * | 
|  | 607 | * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC) | 
|  | 608 | *              or method (e.g. _Lxx/_Exx) handler. | 
|  | 609 | * | 
|  | 610 | *              This function executes at interrupt level. | 
|  | 611 | * | 
|  | 612 | ******************************************************************************/ | 
|  | 613 |  | 
|  | 614 | u32 | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 615 | acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 616 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 617 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 618 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 619 | ACPI_FUNCTION_TRACE(ev_gpe_dispatch); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 620 |  | 
|  | 621 | /* | 
|  | 622 | * If edge-triggered, clear the GPE status bit now.  Note that | 
|  | 623 | * level-triggered events are cleared after the GPE is serviced. | 
|  | 624 | */ | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 625 | if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 626 | ACPI_GPE_EDGE_TRIGGERED) { | 
|  | 627 | status = acpi_hw_clear_gpe(gpe_event_info); | 
|  | 628 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 629 | ACPI_EXCEPTION((AE_INFO, status, | 
|  | 630 | "Unable to clear GPE[%2X]", | 
|  | 631 | gpe_number)); | 
| Bob Moore | 50eca3e | 2005-09-30 19:03:00 -0400 | [diff] [blame] | 632 | return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 633 | } | 
|  | 634 | } | 
|  | 635 |  | 
|  | 636 | /* Save current system state */ | 
|  | 637 |  | 
|  | 638 | if (acpi_gbl_system_awake_and_running) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 639 | ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); | 
|  | 640 | } else { | 
|  | 641 | ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 642 | } | 
|  | 643 |  | 
|  | 644 | /* | 
|  | 645 | * Dispatch the GPE to either an installed handler, or the control | 
|  | 646 | * method associated with this GPE (_Lxx or _Exx). | 
|  | 647 | * If a handler exists, we invoke it and do not attempt to run the method. | 
|  | 648 | * If there is neither a handler nor a method, we disable the level to | 
|  | 649 | * prevent further events from coming in here. | 
|  | 650 | */ | 
|  | 651 | switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { | 
|  | 652 | case ACPI_GPE_DISPATCH_HANDLER: | 
|  | 653 |  | 
|  | 654 | /* | 
|  | 655 | * Invoke the installed handler (at interrupt level) | 
|  | 656 | * Ignore return status for now.  TBD: leave GPE disabled on error? | 
|  | 657 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 658 | (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> | 
|  | 659 | dispatch. | 
|  | 660 | handler-> | 
|  | 661 | context); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 662 |  | 
|  | 663 | /* It is now safe to clear level-triggered events. */ | 
|  | 664 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 665 | if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 666 | ACPI_GPE_LEVEL_TRIGGERED) { | 
|  | 667 | status = acpi_hw_clear_gpe(gpe_event_info); | 
|  | 668 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 669 | ACPI_EXCEPTION((AE_INFO, status, | 
|  | 670 | "Unable to clear GPE[%2X]", | 
|  | 671 | gpe_number)); | 
| Bob Moore | 50eca3e | 2005-09-30 19:03:00 -0400 | [diff] [blame] | 672 | return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 673 | } | 
|  | 674 | } | 
|  | 675 | break; | 
|  | 676 |  | 
|  | 677 | case ACPI_GPE_DISPATCH_METHOD: | 
|  | 678 |  | 
|  | 679 | /* | 
|  | 680 | * Disable GPE, so it doesn't keep firing before the method has a | 
|  | 681 | * chance to run. | 
|  | 682 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 683 | status = acpi_ev_disable_gpe(gpe_event_info); | 
|  | 684 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 685 | ACPI_EXCEPTION((AE_INFO, status, | 
|  | 686 | "Unable to disable GPE[%2X]", | 
|  | 687 | gpe_number)); | 
| Bob Moore | 50eca3e | 2005-09-30 19:03:00 -0400 | [diff] [blame] | 688 | return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 689 | } | 
|  | 690 |  | 
|  | 691 | /* | 
|  | 692 | * Execute the method associated with the GPE | 
|  | 693 | * NOTE: Level-triggered GPEs are cleared after the method completes. | 
|  | 694 | */ | 
| Bob Moore | 958dd24 | 2006-05-12 17:12:00 -0400 | [diff] [blame] | 695 | status = acpi_os_execute(OSL_GPE_HANDLER, | 
|  | 696 | acpi_ev_asynch_execute_gpe_method, | 
|  | 697 | gpe_event_info); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 698 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 699 | ACPI_EXCEPTION((AE_INFO, status, | 
|  | 700 | "Unable to queue handler for GPE[%2X] - event disabled", | 
|  | 701 | gpe_number)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 702 | } | 
|  | 703 | break; | 
|  | 704 |  | 
|  | 705 | default: | 
|  | 706 |  | 
|  | 707 | /* No handler or method to run! */ | 
|  | 708 |  | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 709 | ACPI_ERROR((AE_INFO, | 
|  | 710 | "No handler or method for GPE[%2X], disabling event", | 
|  | 711 | gpe_number)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 712 |  | 
|  | 713 | /* | 
|  | 714 | * Disable the GPE.  The GPE will remain disabled until the ACPI | 
|  | 715 | * Core Subsystem is restarted, or a handler is installed. | 
|  | 716 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 717 | status = acpi_ev_disable_gpe(gpe_event_info); | 
|  | 718 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 719 | ACPI_EXCEPTION((AE_INFO, status, | 
|  | 720 | "Unable to disable GPE[%2X]", | 
|  | 721 | gpe_number)); | 
| Bob Moore | 50eca3e | 2005-09-30 19:03:00 -0400 | [diff] [blame] | 722 | return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 723 | } | 
|  | 724 | break; | 
|  | 725 | } | 
|  | 726 |  | 
| Bob Moore | 50eca3e | 2005-09-30 19:03:00 -0400 | [diff] [blame] | 727 | return_UINT32(ACPI_INTERRUPT_HANDLED); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 728 | } | 
|  | 729 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 730 | #ifdef ACPI_GPE_NOTIFY_CHECK | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 731 | /******************************************************************************* | 
|  | 732 | * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED | 
|  | 733 | * | 
|  | 734 | * FUNCTION:    acpi_ev_check_for_wake_only_gpe | 
|  | 735 | * | 
|  | 736 | * PARAMETERS:  gpe_event_info  - info for this GPE | 
|  | 737 | * | 
|  | 738 | * RETURN:      Status | 
|  | 739 | * | 
|  | 740 | * DESCRIPTION: Determine if a a GPE is "wake-only". | 
|  | 741 | * | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 742 | *              Called from Notify() code in interpreter when a "DeviceWake" | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 743 | *              Notify comes in. | 
|  | 744 | * | 
|  | 745 | ******************************************************************************/ | 
|  | 746 |  | 
|  | 747 | acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 748 | acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 749 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 750 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 751 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 752 | ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 753 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 754 | if ((gpe_event_info) &&	/* Only >0 for _Lxx/_Exx */ | 
|  | 755 | ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) {	/* System state at GPE time */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 756 | /* This must be a wake-only GPE, disable it */ | 
|  | 757 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 758 | status = acpi_ev_disable_gpe(gpe_event_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 759 |  | 
|  | 760 | /* Set GPE to wake-only.  Do not change wake disabled/enabled status */ | 
|  | 761 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 762 | acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 763 |  | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 764 | ACPI_INFO((AE_INFO, | 
|  | 765 | "GPE %p was updated from wake/run to wake-only", | 
|  | 766 | gpe_event_info)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 767 |  | 
|  | 768 | /* This was a wake-only GPE */ | 
|  | 769 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 770 | return_ACPI_STATUS(AE_WAKE_ONLY_GPE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 771 | } | 
|  | 772 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 773 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 774 | } | 
|  | 775 | #endif |