| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /****************************************************************************** | 
|  | 2 | * | 
|  | 3 | * Module Name: evgpeblk - GPE block creation and initialization. | 
|  | 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("evgpeblk") | 
| 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 acpi_status | 
|  | 53 | acpi_ev_save_method_info(acpi_handle obj_handle, | 
|  | 54 | u32 level, void *obj_desc, void **return_value); | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 55 |  | 
|  | 56 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 57 | acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, | 
|  | 58 | u32 level, void *info, void **return_value); | 
|  | 59 |  | 
|  | 60 | static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 | 
|  | 61 | interrupt_number); | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 62 |  | 
|  | 63 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 64 | acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt); | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 65 |  | 
|  | 66 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 67 | acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, | 
|  | 68 | u32 interrupt_number); | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 69 |  | 
|  | 70 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 71 | acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 72 |  | 
|  | 73 | /******************************************************************************* | 
|  | 74 | * | 
|  | 75 | * FUNCTION:    acpi_ev_valid_gpe_event | 
|  | 76 | * | 
|  | 77 | * PARAMETERS:  gpe_event_info              - Info for this GPE | 
|  | 78 | * | 
|  | 79 | * RETURN:      TRUE if the gpe_event is valid | 
|  | 80 | * | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 81 | * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 82 | *              Should be called only when the GPE lists are semaphore locked | 
|  | 83 | *              and not subject to change. | 
|  | 84 | * | 
|  | 85 | ******************************************************************************/ | 
|  | 86 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 87 | u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 88 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 89 | struct acpi_gpe_xrupt_info *gpe_xrupt_block; | 
|  | 90 | struct acpi_gpe_block_info *gpe_block; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 91 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 92 | ACPI_FUNCTION_ENTRY(); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 93 |  | 
|  | 94 | /* No need for spin lock since we are not changing any list elements */ | 
|  | 95 |  | 
|  | 96 | /* Walk the GPE interrupt levels */ | 
|  | 97 |  | 
|  | 98 | gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head; | 
|  | 99 | while (gpe_xrupt_block) { | 
|  | 100 | gpe_block = gpe_xrupt_block->gpe_block_list_head; | 
|  | 101 |  | 
|  | 102 | /* Walk the GPE blocks on this interrupt level */ | 
|  | 103 |  | 
|  | 104 | while (gpe_block) { | 
|  | 105 | if ((&gpe_block->event_info[0] <= gpe_event_info) && | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 106 | (&gpe_block-> | 
|  | 107 | event_info[((acpi_size) gpe_block-> | 
|  | 108 | register_count) * 8] > | 
|  | 109 | gpe_event_info)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 110 | return (TRUE); | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | gpe_block = gpe_block->next; | 
|  | 114 | } | 
|  | 115 |  | 
|  | 116 | gpe_xrupt_block = gpe_xrupt_block->next; | 
|  | 117 | } | 
|  | 118 |  | 
|  | 119 | return (FALSE); | 
|  | 120 | } | 
|  | 121 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 122 | /******************************************************************************* | 
|  | 123 | * | 
|  | 124 | * FUNCTION:    acpi_ev_walk_gpe_list | 
|  | 125 | * | 
|  | 126 | * PARAMETERS:  gpe_walk_callback   - Routine called for each GPE block | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | * | 
|  | 128 | * RETURN:      Status | 
|  | 129 | * | 
|  | 130 | * DESCRIPTION: Walk the GPE lists. | 
|  | 131 | * | 
|  | 132 | ******************************************************************************/ | 
|  | 133 |  | 
| Bob Moore | 61686124 | 2006-03-17 16:44:00 -0500 | [diff] [blame] | 134 | acpi_status acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 135 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 136 | struct acpi_gpe_block_info *gpe_block; | 
|  | 137 | struct acpi_gpe_xrupt_info *gpe_xrupt_info; | 
|  | 138 | acpi_status status = AE_OK; | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 139 | acpi_cpu_flags flags; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 140 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 141 | ACPI_FUNCTION_TRACE(ev_walk_gpe_list); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 142 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 143 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 144 |  | 
|  | 145 | /* Walk the interrupt level descriptor list */ | 
|  | 146 |  | 
|  | 147 | gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head; | 
|  | 148 | while (gpe_xrupt_info) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 149 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 150 | /* Walk all Gpe Blocks attached to this interrupt level */ | 
|  | 151 |  | 
|  | 152 | gpe_block = gpe_xrupt_info->gpe_block_list_head; | 
|  | 153 | while (gpe_block) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 154 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 155 | /* One callback per GPE block */ | 
|  | 156 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 157 | status = gpe_walk_callback(gpe_xrupt_info, gpe_block); | 
|  | 158 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 159 | goto unlock_and_exit; | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | gpe_block = gpe_block->next; | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | gpe_xrupt_info = gpe_xrupt_info->next; | 
|  | 166 | } | 
|  | 167 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 168 | unlock_and_exit: | 
|  | 169 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 
|  | 170 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 171 | } | 
|  | 172 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 173 | /******************************************************************************* | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 174 | * | 
|  | 175 | * FUNCTION:    acpi_ev_delete_gpe_handlers | 
|  | 176 | * | 
|  | 177 | * PARAMETERS:  gpe_xrupt_info      - GPE Interrupt info | 
|  | 178 | *              gpe_block           - Gpe Block info | 
|  | 179 | * | 
|  | 180 | * RETURN:      Status | 
|  | 181 | * | 
|  | 182 | * DESCRIPTION: Delete all Handler objects found in the GPE data structs. | 
|  | 183 | *              Used only prior to termination. | 
|  | 184 | * | 
|  | 185 | ******************************************************************************/ | 
|  | 186 |  | 
|  | 187 | acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 188 | acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info, | 
|  | 189 | struct acpi_gpe_block_info *gpe_block) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 190 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 191 | struct acpi_gpe_event_info *gpe_event_info; | 
|  | 192 | acpi_native_uint i; | 
|  | 193 | acpi_native_uint j; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 194 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 195 | ACPI_FUNCTION_TRACE(ev_delete_gpe_handlers); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 196 |  | 
|  | 197 | /* Examine each GPE Register within the block */ | 
|  | 198 |  | 
|  | 199 | for (i = 0; i < gpe_block->register_count; i++) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 200 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 201 | /* Now look at the individual GPEs in this byte register */ | 
|  | 202 |  | 
|  | 203 | for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 204 | gpe_event_info = | 
|  | 205 | &gpe_block-> | 
|  | 206 | event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 207 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 208 | if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 209 | ACPI_GPE_DISPATCH_HANDLER) { | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 210 | ACPI_FREE(gpe_event_info->dispatch.handler); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 211 | gpe_event_info->dispatch.handler = NULL; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 212 | gpe_event_info->flags &= | 
|  | 213 | ~ACPI_GPE_DISPATCH_MASK; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 214 | } | 
|  | 215 | } | 
|  | 216 | } | 
|  | 217 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 218 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 219 | } | 
|  | 220 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 221 | /******************************************************************************* | 
|  | 222 | * | 
|  | 223 | * FUNCTION:    acpi_ev_save_method_info | 
|  | 224 | * | 
|  | 225 | * PARAMETERS:  Callback from walk_namespace | 
|  | 226 | * | 
|  | 227 | * RETURN:      Status | 
|  | 228 | * | 
|  | 229 | * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a | 
|  | 230 | *              control method under the _GPE portion of the namespace. | 
|  | 231 | *              Extract the name and GPE type from the object, saving this | 
|  | 232 | *              information for quick lookup during GPE dispatch | 
|  | 233 | * | 
|  | 234 | *              The name of each GPE control method is of the form: | 
|  | 235 | *              "_Lxx" or "_Exx" | 
|  | 236 | *              Where: | 
|  | 237 | *                  L      - means that the GPE is level triggered | 
|  | 238 | *                  E      - means that the GPE is edge triggered | 
|  | 239 | *                  xx     - is the GPE number [in HEX] | 
|  | 240 | * | 
|  | 241 | ******************************************************************************/ | 
|  | 242 |  | 
|  | 243 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 244 | acpi_ev_save_method_info(acpi_handle obj_handle, | 
|  | 245 | u32 level, void *obj_desc, void **return_value) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 246 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 247 | struct acpi_gpe_block_info *gpe_block = (void *)obj_desc; | 
|  | 248 | struct acpi_gpe_event_info *gpe_event_info; | 
|  | 249 | u32 gpe_number; | 
|  | 250 | char name[ACPI_NAME_SIZE + 1]; | 
|  | 251 | u8 type; | 
|  | 252 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 253 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 254 | ACPI_FUNCTION_TRACE(ev_save_method_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 255 |  | 
|  | 256 | /* | 
|  | 257 | * _Lxx and _Exx GPE method support | 
|  | 258 | * | 
|  | 259 | * 1) Extract the name from the object and convert to a string | 
|  | 260 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 261 | ACPI_MOVE_32_TO_32(name, | 
|  | 262 | &((struct acpi_namespace_node *)obj_handle)->name. | 
|  | 263 | integer); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 264 | name[ACPI_NAME_SIZE] = 0; | 
|  | 265 |  | 
|  | 266 | /* | 
|  | 267 | * 2) Edge/Level determination is based on the 2nd character | 
|  | 268 | *    of the method name | 
|  | 269 | * | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 270 | * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 271 | * if a _PRW object is found that points to this GPE. | 
|  | 272 | */ | 
|  | 273 | switch (name[1]) { | 
|  | 274 | case 'L': | 
|  | 275 | type = ACPI_GPE_LEVEL_TRIGGERED; | 
|  | 276 | break; | 
|  | 277 |  | 
|  | 278 | case 'E': | 
|  | 279 | type = ACPI_GPE_EDGE_TRIGGERED; | 
|  | 280 | break; | 
|  | 281 |  | 
|  | 282 | default: | 
|  | 283 | /* Unknown method type, just ignore it! */ | 
|  | 284 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 285 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, | 
|  | 286 | "Ignoring unknown GPE method type: %s (name not of form _Lxx or _Exx)", | 
|  | 287 | name)); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 288 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 289 | } | 
|  | 290 |  | 
|  | 291 | /* Convert the last two characters of the name to the GPE Number */ | 
|  | 292 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 293 | gpe_number = ACPI_STRTOUL(&name[2], NULL, 16); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 294 | if (gpe_number == ACPI_UINT32_MAX) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 295 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 296 | /* Conversion failed; invalid method, just ignore it */ | 
|  | 297 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 298 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, | 
|  | 299 | "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)", | 
|  | 300 | name)); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 301 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 302 | } | 
|  | 303 |  | 
|  | 304 | /* Ensure that we have a valid GPE number for this GPE block */ | 
|  | 305 |  | 
|  | 306 | if ((gpe_number < gpe_block->block_base_number) || | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 307 | (gpe_number >= | 
|  | 308 | (gpe_block->block_base_number + | 
|  | 309 | (gpe_block->register_count * 8)))) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 310 | /* | 
|  | 311 | * Not valid for this GPE block, just ignore it | 
|  | 312 | * However, it may be valid for a different GPE block, since GPE0 and GPE1 | 
|  | 313 | * methods both appear under \_GPE. | 
|  | 314 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 315 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 316 | } | 
|  | 317 |  | 
|  | 318 | /* | 
|  | 319 | * Now we can add this information to the gpe_event_info block | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 320 | * for use during dispatch of this GPE. Default type is RUNTIME, although | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 321 | * this may change when the _PRW methods are executed later. | 
|  | 322 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 323 | gpe_event_info = | 
|  | 324 | &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 325 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 326 | gpe_event_info->flags = (u8) | 
|  | 327 | (type | ACPI_GPE_DISPATCH_METHOD | ACPI_GPE_TYPE_RUNTIME); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 328 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 329 | gpe_event_info->dispatch.method_node = | 
|  | 330 | (struct acpi_namespace_node *)obj_handle; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 331 |  | 
|  | 332 | /* Update enable mask, but don't enable the HW GPE as of yet */ | 
|  | 333 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 334 | status = acpi_ev_enable_gpe(gpe_event_info, FALSE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 335 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 336 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, | 
|  | 337 | "Registered GPE method %s as GPE number 0x%.2X\n", | 
|  | 338 | name, gpe_number)); | 
|  | 339 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 340 | } | 
|  | 341 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 342 | /******************************************************************************* | 
|  | 343 | * | 
|  | 344 | * FUNCTION:    acpi_ev_match_prw_and_gpe | 
|  | 345 | * | 
|  | 346 | * PARAMETERS:  Callback from walk_namespace | 
|  | 347 | * | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 348 | * RETURN:      Status. NOTE: We ignore errors so that the _PRW walk is | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 349 | *              not aborted on a single _PRW failure. | 
|  | 350 | * | 
|  | 351 | * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 352 | *              Device. Run the _PRW method. If present, extract the GPE | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 353 | *              number and mark the GPE as a WAKE GPE. | 
|  | 354 | * | 
|  | 355 | ******************************************************************************/ | 
|  | 356 |  | 
|  | 357 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 358 | acpi_ev_match_prw_and_gpe(acpi_handle obj_handle, | 
|  | 359 | u32 level, void *info, void **return_value) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 360 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 361 | struct acpi_gpe_walk_info *gpe_info = (void *)info; | 
|  | 362 | struct acpi_namespace_node *gpe_device; | 
|  | 363 | struct acpi_gpe_block_info *gpe_block; | 
|  | 364 | struct acpi_namespace_node *target_gpe_device; | 
|  | 365 | struct acpi_gpe_event_info *gpe_event_info; | 
|  | 366 | union acpi_operand_object *pkg_desc; | 
|  | 367 | union acpi_operand_object *obj_desc; | 
|  | 368 | u32 gpe_number; | 
|  | 369 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 370 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 371 | ACPI_FUNCTION_TRACE(ev_match_prw_and_gpe); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 372 |  | 
|  | 373 | /* Check for a _PRW method under this device */ | 
|  | 374 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 375 | status = acpi_ut_evaluate_object(obj_handle, METHOD_NAME__PRW, | 
|  | 376 | ACPI_BTYPE_PACKAGE, &pkg_desc); | 
|  | 377 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 378 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 379 | /* Ignore all errors from _PRW, we don't want to abort the subsystem */ | 
|  | 380 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 381 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 382 | } | 
|  | 383 |  | 
|  | 384 | /* The returned _PRW package must have at least two elements */ | 
|  | 385 |  | 
|  | 386 | if (pkg_desc->package.count < 2) { | 
|  | 387 | goto cleanup; | 
|  | 388 | } | 
|  | 389 |  | 
|  | 390 | /* Extract pointers from the input context */ | 
|  | 391 |  | 
|  | 392 | gpe_device = gpe_info->gpe_device; | 
|  | 393 | gpe_block = gpe_info->gpe_block; | 
|  | 394 |  | 
|  | 395 | /* | 
|  | 396 | * The _PRW object must return a package, we are only interested | 
|  | 397 | * in the first element | 
|  | 398 | */ | 
|  | 399 | obj_desc = pkg_desc->package.elements[0]; | 
|  | 400 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 401 | if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_INTEGER) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 402 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 403 | /* Use FADT-defined GPE device (from definition of _PRW) */ | 
|  | 404 |  | 
|  | 405 | target_gpe_device = acpi_gbl_fadt_gpe_device; | 
|  | 406 |  | 
|  | 407 | /* Integer is the GPE number in the FADT described GPE blocks */ | 
|  | 408 |  | 
|  | 409 | gpe_number = (u32) obj_desc->integer.value; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 410 | } else if (ACPI_GET_OBJECT_TYPE(obj_desc) == ACPI_TYPE_PACKAGE) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 411 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 412 | /* Package contains a GPE reference and GPE number within a GPE block */ | 
|  | 413 |  | 
|  | 414 | if ((obj_desc->package.count < 2) || | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 415 | (ACPI_GET_OBJECT_TYPE(obj_desc->package.elements[0]) != | 
|  | 416 | ACPI_TYPE_LOCAL_REFERENCE) | 
|  | 417 | || (ACPI_GET_OBJECT_TYPE(obj_desc->package.elements[1]) != | 
|  | 418 | ACPI_TYPE_INTEGER)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 419 | goto cleanup; | 
|  | 420 | } | 
|  | 421 |  | 
|  | 422 | /* Get GPE block reference and decode */ | 
|  | 423 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 424 | target_gpe_device = | 
|  | 425 | obj_desc->package.elements[0]->reference.node; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 426 | gpe_number = (u32) obj_desc->package.elements[1]->integer.value; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 427 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 428 | /* Unknown type, just ignore it */ | 
|  | 429 |  | 
|  | 430 | goto cleanup; | 
|  | 431 | } | 
|  | 432 |  | 
|  | 433 | /* | 
|  | 434 | * Is this GPE within this block? | 
|  | 435 | * | 
|  | 436 | * TRUE iff these conditions are true: | 
|  | 437 | *     1) The GPE devices match. | 
|  | 438 | *     2) The GPE index(number) is within the range of the Gpe Block | 
|  | 439 | *          associated with the GPE device. | 
|  | 440 | */ | 
|  | 441 | if ((gpe_device == target_gpe_device) && | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 442 | (gpe_number >= gpe_block->block_base_number) && | 
|  | 443 | (gpe_number < | 
|  | 444 | gpe_block->block_base_number + (gpe_block->register_count * 8))) { | 
|  | 445 | gpe_event_info = | 
|  | 446 | &gpe_block->event_info[gpe_number - | 
|  | 447 | gpe_block->block_base_number]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 448 |  | 
|  | 449 | /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */ | 
|  | 450 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 451 | gpe_event_info->flags &= | 
|  | 452 | ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED); | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 453 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 454 | status = | 
|  | 455 | acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE); | 
|  | 456 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 457 | goto cleanup; | 
|  | 458 | } | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 459 | status = | 
|  | 460 | acpi_ev_update_gpe_enable_masks(gpe_event_info, | 
|  | 461 | ACPI_GPE_DISABLE); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 462 | } | 
|  | 463 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 464 | cleanup: | 
|  | 465 | acpi_ut_remove_reference(pkg_desc); | 
|  | 466 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 467 | } | 
|  | 468 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 469 | /******************************************************************************* | 
|  | 470 | * | 
|  | 471 | * FUNCTION:    acpi_ev_get_gpe_xrupt_block | 
|  | 472 | * | 
| Robert Moore | 6f42ccf | 2005-05-13 00:00:00 -0400 | [diff] [blame] | 473 | * PARAMETERS:  interrupt_number     - Interrupt for a GPE block | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 474 | * | 
|  | 475 | * RETURN:      A GPE interrupt block | 
|  | 476 | * | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 477 | * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 478 | *              block per unique interrupt level used for GPEs. | 
|  | 479 | *              Should be called only when the GPE lists are semaphore locked | 
|  | 480 | *              and not subject to change. | 
|  | 481 | * | 
|  | 482 | ******************************************************************************/ | 
|  | 483 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 484 | static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32 | 
|  | 485 | interrupt_number) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 486 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 487 | struct acpi_gpe_xrupt_info *next_gpe_xrupt; | 
|  | 488 | struct acpi_gpe_xrupt_info *gpe_xrupt; | 
|  | 489 | acpi_status status; | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 490 | acpi_cpu_flags flags; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 491 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 492 | ACPI_FUNCTION_TRACE(ev_get_gpe_xrupt_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 493 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 494 | /* No need for lock since we are not changing any list elements here */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 495 |  | 
|  | 496 | next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; | 
|  | 497 | while (next_gpe_xrupt) { | 
| Robert Moore | 6f42ccf | 2005-05-13 00:00:00 -0400 | [diff] [blame] | 498 | if (next_gpe_xrupt->interrupt_number == interrupt_number) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 499 | return_PTR(next_gpe_xrupt); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 500 | } | 
|  | 501 |  | 
|  | 502 | next_gpe_xrupt = next_gpe_xrupt->next; | 
|  | 503 | } | 
|  | 504 |  | 
|  | 505 | /* Not found, must allocate a new xrupt descriptor */ | 
|  | 506 |  | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 507 | gpe_xrupt = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_xrupt_info)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 508 | if (!gpe_xrupt) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 509 | return_PTR(NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 510 | } | 
|  | 511 |  | 
| Robert Moore | 6f42ccf | 2005-05-13 00:00:00 -0400 | [diff] [blame] | 512 | gpe_xrupt->interrupt_number = interrupt_number; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 513 |  | 
|  | 514 | /* Install new interrupt descriptor with spin lock */ | 
|  | 515 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 516 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 517 | if (acpi_gbl_gpe_xrupt_list_head) { | 
|  | 518 | next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head; | 
|  | 519 | while (next_gpe_xrupt->next) { | 
|  | 520 | next_gpe_xrupt = next_gpe_xrupt->next; | 
|  | 521 | } | 
|  | 522 |  | 
|  | 523 | next_gpe_xrupt->next = gpe_xrupt; | 
|  | 524 | gpe_xrupt->previous = next_gpe_xrupt; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 525 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 526 | acpi_gbl_gpe_xrupt_list_head = gpe_xrupt; | 
|  | 527 | } | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 528 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 529 |  | 
|  | 530 | /* Install new interrupt handler if not SCI_INT */ | 
|  | 531 |  | 
| Robert Moore | 6f42ccf | 2005-05-13 00:00:00 -0400 | [diff] [blame] | 532 | if (interrupt_number != acpi_gbl_FADT->sci_int) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 533 | status = acpi_os_install_interrupt_handler(interrupt_number, | 
|  | 534 | acpi_ev_gpe_xrupt_handler, | 
|  | 535 | gpe_xrupt); | 
|  | 536 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 537 | ACPI_ERROR((AE_INFO, | 
|  | 538 | "Could not install GPE interrupt handler at level 0x%X", | 
|  | 539 | interrupt_number)); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 540 | return_PTR(NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 541 | } | 
|  | 542 | } | 
|  | 543 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 544 | return_PTR(gpe_xrupt); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 545 | } | 
|  | 546 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 547 | /******************************************************************************* | 
|  | 548 | * | 
|  | 549 | * FUNCTION:    acpi_ev_delete_gpe_xrupt | 
|  | 550 | * | 
|  | 551 | * PARAMETERS:  gpe_xrupt       - A GPE interrupt info block | 
|  | 552 | * | 
|  | 553 | * RETURN:      Status | 
|  | 554 | * | 
|  | 555 | * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated | 
|  | 556 | *              interrupt handler if not the SCI interrupt. | 
|  | 557 | * | 
|  | 558 | ******************************************************************************/ | 
|  | 559 |  | 
|  | 560 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 561 | acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 562 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 563 | acpi_status status; | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 564 | acpi_cpu_flags flags; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 565 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 566 | ACPI_FUNCTION_TRACE(ev_delete_gpe_xrupt); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 567 |  | 
|  | 568 | /* We never want to remove the SCI interrupt handler */ | 
|  | 569 |  | 
| Robert Moore | 6f42ccf | 2005-05-13 00:00:00 -0400 | [diff] [blame] | 570 | if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 571 | gpe_xrupt->gpe_block_list_head = NULL; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 572 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 573 | } | 
|  | 574 |  | 
|  | 575 | /* Disable this interrupt */ | 
|  | 576 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 577 | status = | 
|  | 578 | acpi_os_remove_interrupt_handler(gpe_xrupt->interrupt_number, | 
|  | 579 | acpi_ev_gpe_xrupt_handler); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 580 | if (ACPI_FAILURE(status)) { | 
|  | 581 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 582 | } | 
|  | 583 |  | 
|  | 584 | /* Unlink the interrupt block with lock */ | 
|  | 585 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 586 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 587 | if (gpe_xrupt->previous) { | 
|  | 588 | gpe_xrupt->previous->next = gpe_xrupt->next; | 
|  | 589 | } | 
|  | 590 |  | 
|  | 591 | if (gpe_xrupt->next) { | 
|  | 592 | gpe_xrupt->next->previous = gpe_xrupt->previous; | 
|  | 593 | } | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 594 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 595 |  | 
|  | 596 | /* Free the block */ | 
|  | 597 |  | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 598 | ACPI_FREE(gpe_xrupt); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 599 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 600 | } | 
|  | 601 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 602 | /******************************************************************************* | 
|  | 603 | * | 
|  | 604 | * FUNCTION:    acpi_ev_install_gpe_block | 
|  | 605 | * | 
|  | 606 | * PARAMETERS:  gpe_block       - New GPE block | 
| Robert Moore | 6f42ccf | 2005-05-13 00:00:00 -0400 | [diff] [blame] | 607 | *              interrupt_number - Xrupt to be associated with this GPE block | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 608 | * | 
|  | 609 | * RETURN:      Status | 
|  | 610 | * | 
|  | 611 | * DESCRIPTION: Install new GPE block with mutex support | 
|  | 612 | * | 
|  | 613 | ******************************************************************************/ | 
|  | 614 |  | 
|  | 615 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 616 | acpi_ev_install_gpe_block(struct acpi_gpe_block_info *gpe_block, | 
|  | 617 | u32 interrupt_number) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 618 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 619 | struct acpi_gpe_block_info *next_gpe_block; | 
|  | 620 | struct acpi_gpe_xrupt_info *gpe_xrupt_block; | 
|  | 621 | acpi_status status; | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 622 | acpi_cpu_flags flags; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 623 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 624 | ACPI_FUNCTION_TRACE(ev_install_gpe_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 625 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 626 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); | 
|  | 627 | if (ACPI_FAILURE(status)) { | 
|  | 628 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 629 | } | 
|  | 630 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 631 | gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block(interrupt_number); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 632 | if (!gpe_xrupt_block) { | 
|  | 633 | status = AE_NO_MEMORY; | 
|  | 634 | goto unlock_and_exit; | 
|  | 635 | } | 
|  | 636 |  | 
| Robert Moore | 44f6c01 | 2005-04-18 22:49:35 -0400 | [diff] [blame] | 637 | /* Install the new block at the end of the list with lock */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 638 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 639 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 640 | if (gpe_xrupt_block->gpe_block_list_head) { | 
|  | 641 | next_gpe_block = gpe_xrupt_block->gpe_block_list_head; | 
|  | 642 | while (next_gpe_block->next) { | 
|  | 643 | next_gpe_block = next_gpe_block->next; | 
|  | 644 | } | 
|  | 645 |  | 
|  | 646 | next_gpe_block->next = gpe_block; | 
|  | 647 | gpe_block->previous = next_gpe_block; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 648 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 649 | gpe_xrupt_block->gpe_block_list_head = gpe_block; | 
|  | 650 | } | 
|  | 651 |  | 
|  | 652 | gpe_block->xrupt_block = gpe_xrupt_block; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 653 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 654 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 655 | unlock_and_exit: | 
|  | 656 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); | 
|  | 657 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 658 | } | 
|  | 659 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 660 | /******************************************************************************* | 
|  | 661 | * | 
|  | 662 | * FUNCTION:    acpi_ev_delete_gpe_block | 
|  | 663 | * | 
|  | 664 | * PARAMETERS:  gpe_block       - Existing GPE block | 
|  | 665 | * | 
|  | 666 | * RETURN:      Status | 
|  | 667 | * | 
|  | 668 | * DESCRIPTION: Remove a GPE block | 
|  | 669 | * | 
|  | 670 | ******************************************************************************/ | 
|  | 671 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 672 | acpi_status acpi_ev_delete_gpe_block(struct acpi_gpe_block_info *gpe_block) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 673 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 674 | acpi_status status; | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 675 | acpi_cpu_flags flags; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 676 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 677 | ACPI_FUNCTION_TRACE(ev_install_gpe_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 678 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 679 | status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); | 
|  | 680 | if (ACPI_FAILURE(status)) { | 
|  | 681 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 682 | } | 
|  | 683 |  | 
|  | 684 | /* Disable all GPEs in this block */ | 
|  | 685 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 686 | status = acpi_hw_disable_gpe_block(gpe_block->xrupt_block, gpe_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 687 |  | 
|  | 688 | if (!gpe_block->previous && !gpe_block->next) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 689 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 690 | /* This is the last gpe_block on this interrupt */ | 
|  | 691 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 692 | status = acpi_ev_delete_gpe_xrupt(gpe_block->xrupt_block); | 
|  | 693 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 694 | goto unlock_and_exit; | 
|  | 695 | } | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 696 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 697 | /* Remove the block on this interrupt with lock */ | 
|  | 698 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 699 | flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 700 | if (gpe_block->previous) { | 
|  | 701 | gpe_block->previous->next = gpe_block->next; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 702 | } else { | 
|  | 703 | gpe_block->xrupt_block->gpe_block_list_head = | 
|  | 704 | gpe_block->next; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 705 | } | 
|  | 706 |  | 
|  | 707 | if (gpe_block->next) { | 
|  | 708 | gpe_block->next->previous = gpe_block->previous; | 
|  | 709 | } | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 710 | acpi_os_release_lock(acpi_gbl_gpe_lock, flags); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 711 | } | 
|  | 712 |  | 
|  | 713 | /* Free the gpe_block */ | 
|  | 714 |  | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 715 | ACPI_FREE(gpe_block->register_info); | 
|  | 716 | ACPI_FREE(gpe_block->event_info); | 
|  | 717 | ACPI_FREE(gpe_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 718 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 719 | unlock_and_exit: | 
|  | 720 | status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); | 
|  | 721 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 722 | } | 
|  | 723 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 724 | /******************************************************************************* | 
|  | 725 | * | 
|  | 726 | * FUNCTION:    acpi_ev_create_gpe_info_blocks | 
|  | 727 | * | 
|  | 728 | * PARAMETERS:  gpe_block   - New GPE block | 
|  | 729 | * | 
|  | 730 | * RETURN:      Status | 
|  | 731 | * | 
|  | 732 | * DESCRIPTION: Create the register_info and event_info blocks for this GPE block | 
|  | 733 | * | 
|  | 734 | ******************************************************************************/ | 
|  | 735 |  | 
|  | 736 | static acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 737 | acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 738 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 739 | struct acpi_gpe_register_info *gpe_register_info = NULL; | 
|  | 740 | struct acpi_gpe_event_info *gpe_event_info = NULL; | 
|  | 741 | struct acpi_gpe_event_info *this_event; | 
|  | 742 | struct acpi_gpe_register_info *this_register; | 
|  | 743 | acpi_native_uint i; | 
|  | 744 | acpi_native_uint j; | 
|  | 745 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 746 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 747 | ACPI_FUNCTION_TRACE(ev_create_gpe_info_blocks); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 748 |  | 
|  | 749 | /* Allocate the GPE register information block */ | 
|  | 750 |  | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 751 | gpe_register_info = ACPI_ALLOCATE_ZEROED((acpi_size) gpe_block-> | 
|  | 752 | register_count * | 
|  | 753 | sizeof(struct | 
|  | 754 | acpi_gpe_register_info)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 755 | if (!gpe_register_info) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 756 | ACPI_ERROR((AE_INFO, | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 757 | "Could not allocate the GpeRegisterInfo table")); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 758 | return_ACPI_STATUS(AE_NO_MEMORY); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 759 | } | 
|  | 760 |  | 
|  | 761 | /* | 
|  | 762 | * Allocate the GPE event_info block. There are eight distinct GPEs | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 763 | * per register. Initialization to zeros is sufficient. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 764 | */ | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 765 | gpe_event_info = ACPI_ALLOCATE_ZEROED(((acpi_size) gpe_block-> | 
|  | 766 | register_count * | 
|  | 767 | ACPI_GPE_REGISTER_WIDTH) * | 
|  | 768 | sizeof(struct | 
|  | 769 | acpi_gpe_event_info)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 770 | if (!gpe_event_info) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 771 | ACPI_ERROR((AE_INFO, | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 772 | "Could not allocate the GpeEventInfo table")); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 773 | status = AE_NO_MEMORY; | 
|  | 774 | goto error_exit; | 
|  | 775 | } | 
|  | 776 |  | 
|  | 777 | /* Save the new Info arrays in the GPE block */ | 
|  | 778 |  | 
|  | 779 | gpe_block->register_info = gpe_register_info; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 780 | gpe_block->event_info = gpe_event_info; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 781 |  | 
|  | 782 | /* | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 783 | * Initialize the GPE Register and Event structures. A goal of these | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 784 | * tables is to hide the fact that there are two separate GPE register sets | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 785 | * in a given GPE hardware block, the status registers occupy the first half, | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 786 | * and the enable registers occupy the second half. | 
|  | 787 | */ | 
|  | 788 | this_register = gpe_register_info; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 789 | this_event = gpe_event_info; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 790 |  | 
|  | 791 | for (i = 0; i < gpe_block->register_count; i++) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 792 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 793 | /* Init the register_info for this GPE register (8 GPEs) */ | 
|  | 794 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 795 | this_register->base_gpe_number = | 
|  | 796 | (u8) (gpe_block->block_base_number + | 
|  | 797 | (i * ACPI_GPE_REGISTER_WIDTH)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 798 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 799 | ACPI_STORE_ADDRESS(this_register->status_address.address, | 
|  | 800 | (gpe_block->block_address.address + i)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 801 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 802 | ACPI_STORE_ADDRESS(this_register->enable_address.address, | 
|  | 803 | (gpe_block->block_address.address | 
|  | 804 | + i + gpe_block->register_count)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 805 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 806 | this_register->status_address.address_space_id = | 
|  | 807 | gpe_block->block_address.address_space_id; | 
|  | 808 | this_register->enable_address.address_space_id = | 
|  | 809 | gpe_block->block_address.address_space_id; | 
|  | 810 | this_register->status_address.register_bit_width = | 
|  | 811 | ACPI_GPE_REGISTER_WIDTH; | 
|  | 812 | this_register->enable_address.register_bit_width = | 
|  | 813 | ACPI_GPE_REGISTER_WIDTH; | 
|  | 814 | this_register->status_address.register_bit_offset = | 
|  | 815 | ACPI_GPE_REGISTER_WIDTH; | 
|  | 816 | this_register->enable_address.register_bit_offset = | 
|  | 817 | ACPI_GPE_REGISTER_WIDTH; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 818 |  | 
|  | 819 | /* Init the event_info for each GPE within this register */ | 
|  | 820 |  | 
|  | 821 | for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) { | 
|  | 822 | this_event->register_bit = acpi_gbl_decode_to8bit[j]; | 
|  | 823 | this_event->register_info = this_register; | 
|  | 824 | this_event++; | 
|  | 825 | } | 
|  | 826 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 827 | /* Disable all GPEs within this register */ | 
|  | 828 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 829 | status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0x00, | 
|  | 830 | &this_register-> | 
|  | 831 | enable_address); | 
|  | 832 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 833 | goto error_exit; | 
|  | 834 | } | 
|  | 835 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 836 | /* Clear any pending GPE events within this register */ | 
|  | 837 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 838 | status = acpi_hw_low_level_write(ACPI_GPE_REGISTER_WIDTH, 0xFF, | 
|  | 839 | &this_register-> | 
|  | 840 | status_address); | 
|  | 841 | if (ACPI_FAILURE(status)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 842 | goto error_exit; | 
|  | 843 | } | 
|  | 844 |  | 
|  | 845 | this_register++; | 
|  | 846 | } | 
|  | 847 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 848 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 849 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 850 | error_exit: | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 851 | if (gpe_register_info) { | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 852 | ACPI_FREE(gpe_register_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 853 | } | 
|  | 854 | if (gpe_event_info) { | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 855 | ACPI_FREE(gpe_event_info); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 856 | } | 
|  | 857 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 858 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 859 | } | 
|  | 860 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 861 | /******************************************************************************* | 
|  | 862 | * | 
|  | 863 | * FUNCTION:    acpi_ev_create_gpe_block | 
|  | 864 | * | 
|  | 865 | * PARAMETERS:  gpe_device          - Handle to the parent GPE block | 
|  | 866 | *              gpe_block_address   - Address and space_iD | 
|  | 867 | *              register_count      - Number of GPE register pairs in the block | 
|  | 868 | *              gpe_block_base_number - Starting GPE number for the block | 
| Robert Moore | 6f42ccf | 2005-05-13 00:00:00 -0400 | [diff] [blame] | 869 | *              interrupt_number    - H/W interrupt for the block | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 870 | *              return_gpe_block    - Where the new block descriptor is returned | 
|  | 871 | * | 
|  | 872 | * RETURN:      Status | 
|  | 873 | * | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 874 | * DESCRIPTION: Create and Install a block of GPE registers. All GPEs within | 
|  | 875 | *              the block are disabled at exit. | 
|  | 876 | *              Note: Assumes namespace is locked. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 877 | * | 
|  | 878 | ******************************************************************************/ | 
|  | 879 |  | 
|  | 880 | acpi_status | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 881 | acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device, | 
|  | 882 | struct acpi_generic_address *gpe_block_address, | 
|  | 883 | u32 register_count, | 
|  | 884 | u8 gpe_block_base_number, | 
|  | 885 | u32 interrupt_number, | 
|  | 886 | struct acpi_gpe_block_info **return_gpe_block) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 887 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 888 | acpi_status status; | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 889 | struct acpi_gpe_block_info *gpe_block; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 890 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 891 | ACPI_FUNCTION_TRACE(ev_create_gpe_block); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 892 |  | 
|  | 893 | if (!register_count) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 894 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 895 | } | 
|  | 896 |  | 
|  | 897 | /* Allocate a new GPE block */ | 
|  | 898 |  | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 899 | gpe_block = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_block_info)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 900 | if (!gpe_block) { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 901 | return_ACPI_STATUS(AE_NO_MEMORY); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 902 | } | 
|  | 903 |  | 
|  | 904 | /* Initialize the new GPE block */ | 
|  | 905 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 906 | gpe_block->node = gpe_device; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 907 | gpe_block->register_count = register_count; | 
|  | 908 | gpe_block->block_base_number = gpe_block_base_number; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 909 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 910 | ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address, | 
|  | 911 | sizeof(struct acpi_generic_address)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 912 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 913 | /* | 
|  | 914 | * Create the register_info and event_info sub-structures | 
|  | 915 | * Note: disables and clears all GPEs in the block | 
|  | 916 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 917 | status = acpi_ev_create_gpe_info_blocks(gpe_block); | 
|  | 918 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 919 | ACPI_FREE(gpe_block); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 920 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 921 | } | 
|  | 922 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 923 | /* Install the new block in the global lists */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 924 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 925 | status = acpi_ev_install_gpe_block(gpe_block, interrupt_number); | 
|  | 926 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | 8313524 | 2006-10-03 00:00:00 -0400 | [diff] [blame] | 927 | ACPI_FREE(gpe_block); | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 928 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 929 | } | 
|  | 930 |  | 
|  | 931 | /* Find all GPE methods (_Lxx, _Exx) for this block */ | 
|  | 932 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 933 | status = acpi_ns_walk_namespace(ACPI_TYPE_METHOD, gpe_device, | 
|  | 934 | ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, | 
|  | 935 | acpi_ev_save_method_info, gpe_block, | 
|  | 936 | NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 937 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 938 | /* Return the new block */ | 
|  | 939 |  | 
|  | 940 | if (return_gpe_block) { | 
|  | 941 | (*return_gpe_block) = gpe_block; | 
|  | 942 | } | 
|  | 943 |  | 
|  | 944 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, | 
|  | 945 | "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n", | 
|  | 946 | (u32) gpe_block->block_base_number, | 
|  | 947 | (u32) (gpe_block->block_base_number + | 
|  | 948 | ((gpe_block->register_count * | 
|  | 949 | ACPI_GPE_REGISTER_WIDTH) - 1)), | 
|  | 950 | gpe_device->name.ascii, gpe_block->register_count, | 
|  | 951 | interrupt_number)); | 
|  | 952 |  | 
|  | 953 | return_ACPI_STATUS(AE_OK); | 
|  | 954 | } | 
|  | 955 |  | 
|  | 956 | /******************************************************************************* | 
|  | 957 | * | 
|  | 958 | * FUNCTION:    acpi_ev_initialize_gpe_block | 
|  | 959 | * | 
|  | 960 | * PARAMETERS:  gpe_device          - Handle to the parent GPE block | 
|  | 961 | *              gpe_block           - Gpe Block info | 
|  | 962 | * | 
|  | 963 | * RETURN:      Status | 
|  | 964 | * | 
|  | 965 | * DESCRIPTION: Initialize and enable a GPE block. First find and run any | 
|  | 966 | *              _PRT methods associated with the block, then enable the | 
|  | 967 | *              appropriate GPEs. | 
|  | 968 | *              Note: Assumes namespace is locked. | 
|  | 969 | * | 
|  | 970 | ******************************************************************************/ | 
|  | 971 |  | 
|  | 972 | acpi_status | 
|  | 973 | acpi_ev_initialize_gpe_block(struct acpi_namespace_node *gpe_device, | 
|  | 974 | struct acpi_gpe_block_info *gpe_block) | 
|  | 975 | { | 
|  | 976 | acpi_status status; | 
|  | 977 | struct acpi_gpe_event_info *gpe_event_info; | 
|  | 978 | struct acpi_gpe_walk_info gpe_info; | 
|  | 979 | u32 wake_gpe_count; | 
|  | 980 | u32 gpe_enabled_count; | 
|  | 981 | acpi_native_uint i; | 
|  | 982 | acpi_native_uint j; | 
|  | 983 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 984 | ACPI_FUNCTION_TRACE(ev_initialize_gpe_block); | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 985 |  | 
|  | 986 | /* Ignore a null GPE block (e.g., if no GPE block 1 exists) */ | 
|  | 987 |  | 
|  | 988 | if (!gpe_block) { | 
|  | 989 | return_ACPI_STATUS(AE_OK); | 
|  | 990 | } | 
|  | 991 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 992 | /* | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 993 | * Runtime option: Should wake GPEs be enabled at runtime?  The default | 
|  | 994 | * is no, they should only be enabled just as the machine goes to sleep. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 995 | */ | 
|  | 996 | if (acpi_gbl_leave_wake_gpes_disabled) { | 
|  | 997 | /* | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 998 | * Differentiate runtime vs wake GPEs, via the _PRW control methods. | 
|  | 999 | * Each GPE that has one or more _PRWs that reference it is by | 
|  | 1000 | * definition a wake GPE and will not be enabled while the machine | 
|  | 1001 | * is running. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1002 | */ | 
|  | 1003 | gpe_info.gpe_block = gpe_block; | 
|  | 1004 | gpe_info.gpe_device = gpe_device; | 
|  | 1005 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1006 | status = | 
|  | 1007 | acpi_ns_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 
|  | 1008 | ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, | 
|  | 1009 | acpi_ev_match_prw_and_gpe, &gpe_info, | 
|  | 1010 | NULL); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1011 | } | 
|  | 1012 |  | 
|  | 1013 | /* | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 1014 | * Enable all GPEs in this block that have these attributes: | 
|  | 1015 | * 1) are "runtime" or "run/wake" GPEs, and | 
|  | 1016 | * 2) have a corresponding _Lxx or _Exx method | 
|  | 1017 | * | 
|  | 1018 | * Any other GPEs within this block must be enabled via the acpi_enable_gpe() | 
|  | 1019 | * external interface. | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1020 | */ | 
|  | 1021 | wake_gpe_count = 0; | 
|  | 1022 | gpe_enabled_count = 0; | 
|  | 1023 |  | 
|  | 1024 | for (i = 0; i < gpe_block->register_count; i++) { | 
|  | 1025 | for (j = 0; j < 8; j++) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 1026 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1027 | /* Get the info block for this particular GPE */ | 
|  | 1028 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1029 | gpe_event_info = | 
|  | 1030 | &gpe_block-> | 
|  | 1031 | event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j]; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1032 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1033 | if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == | 
|  | 1034 | ACPI_GPE_DISPATCH_METHOD) | 
|  | 1035 | && (gpe_event_info-> | 
|  | 1036 | flags & ACPI_GPE_TYPE_RUNTIME)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1037 | gpe_enabled_count++; | 
|  | 1038 | } | 
|  | 1039 |  | 
|  | 1040 | if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) { | 
|  | 1041 | wake_gpe_count++; | 
|  | 1042 | } | 
|  | 1043 | } | 
|  | 1044 | } | 
|  | 1045 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1046 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, | 
|  | 1047 | "Found %u Wake, Enabled %u Runtime GPEs in this block\n", | 
|  | 1048 | wake_gpe_count, gpe_enabled_count)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1049 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 1050 | /* Enable all valid runtime GPEs found above */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1051 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 1052 | status = acpi_hw_enable_runtime_gpe_block(NULL, gpe_block); | 
|  | 1053 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 1054 | ACPI_ERROR((AE_INFO, "Could not enable GPEs in GpeBlock %p", | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 1055 | gpe_block)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1056 | } | 
|  | 1057 |  | 
| Bob Moore | 96db255 | 2005-11-02 00:00:00 -0500 | [diff] [blame] | 1058 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1059 | } | 
|  | 1060 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1061 | /******************************************************************************* | 
|  | 1062 | * | 
|  | 1063 | * FUNCTION:    acpi_ev_gpe_initialize | 
|  | 1064 | * | 
|  | 1065 | * PARAMETERS:  None | 
|  | 1066 | * | 
|  | 1067 | * RETURN:      Status | 
|  | 1068 | * | 
|  | 1069 | * DESCRIPTION: Initialize the GPE data structures | 
|  | 1070 | * | 
|  | 1071 | ******************************************************************************/ | 
|  | 1072 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1073 | acpi_status acpi_ev_gpe_initialize(void) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1074 | { | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1075 | u32 register_count0 = 0; | 
|  | 1076 | u32 register_count1 = 0; | 
|  | 1077 | u32 gpe_number_max = 0; | 
|  | 1078 | acpi_status status; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1079 |  | 
| Bob Moore | b229cf9 | 2006-04-21 17:15:00 -0400 | [diff] [blame] | 1080 | ACPI_FUNCTION_TRACE(ev_gpe_initialize); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1081 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1082 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | 
|  | 1083 | if (ACPI_FAILURE(status)) { | 
|  | 1084 | return_ACPI_STATUS(status); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1085 | } | 
|  | 1086 |  | 
|  | 1087 | /* | 
|  | 1088 | * Initialize the GPE Block(s) defined in the FADT | 
|  | 1089 | * | 
|  | 1090 | * Why the GPE register block lengths are divided by 2:  From the ACPI Spec, | 
|  | 1091 | * section "General-Purpose Event Registers", we have: | 
|  | 1092 | * | 
|  | 1093 | * "Each register block contains two registers of equal length | 
|  | 1094 | *  GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the | 
|  | 1095 | *  GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN | 
|  | 1096 | *  The length of the GPE1_STS and GPE1_EN registers is equal to | 
|  | 1097 | *  half the GPE1_LEN. If a generic register block is not supported | 
|  | 1098 | *  then its respective block pointer and block length values in the | 
|  | 1099 | *  FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need | 
|  | 1100 | *  to be the same size." | 
|  | 1101 | */ | 
|  | 1102 |  | 
|  | 1103 | /* | 
|  | 1104 | * Determine the maximum GPE number for this machine. | 
|  | 1105 | * | 
|  | 1106 | * Note: both GPE0 and GPE1 are optional, and either can exist without | 
|  | 1107 | * the other. | 
|  | 1108 | * | 
|  | 1109 | * If EITHER the register length OR the block address are zero, then that | 
|  | 1110 | * particular block is not supported. | 
|  | 1111 | */ | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1112 | if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 1113 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1114 | /* GPE block 0 exists (has both length and address > 0) */ | 
|  | 1115 |  | 
|  | 1116 | register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2); | 
|  | 1117 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1118 | gpe_number_max = | 
|  | 1119 | (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1120 |  | 
|  | 1121 | /* Install GPE Block 0 */ | 
|  | 1122 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1123 | status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, | 
|  | 1124 | &acpi_gbl_FADT->xgpe0_blk, | 
|  | 1125 | register_count0, 0, | 
|  | 1126 | acpi_gbl_FADT->sci_int, | 
|  | 1127 | &acpi_gbl_gpe_fadt_blocks[0]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1128 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1129 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 1130 | ACPI_EXCEPTION((AE_INFO, status, | 
|  | 1131 | "Could not create GPE Block 0")); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1132 | } | 
|  | 1133 | } | 
|  | 1134 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1135 | if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 1136 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1137 | /* GPE block 1 exists (has both length and address > 0) */ | 
|  | 1138 |  | 
|  | 1139 | register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2); | 
|  | 1140 |  | 
|  | 1141 | /* Check for GPE0/GPE1 overlap (if both banks exist) */ | 
|  | 1142 |  | 
|  | 1143 | if ((register_count0) && | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1144 | (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 1145 | ACPI_ERROR((AE_INFO, | 
|  | 1146 | "GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1", | 
|  | 1147 | gpe_number_max, acpi_gbl_FADT->gpe1_base, | 
|  | 1148 | acpi_gbl_FADT->gpe1_base + | 
|  | 1149 | ((register_count1 * | 
|  | 1150 | ACPI_GPE_REGISTER_WIDTH) - 1))); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1151 |  | 
|  | 1152 | /* Ignore GPE1 block by setting the register count to zero */ | 
|  | 1153 |  | 
|  | 1154 | register_count1 = 0; | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1155 | } else { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1156 | /* Install GPE Block 1 */ | 
|  | 1157 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1158 | status = | 
|  | 1159 | acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device, | 
|  | 1160 | &acpi_gbl_FADT->xgpe1_blk, | 
|  | 1161 | register_count1, | 
|  | 1162 | acpi_gbl_FADT->gpe1_base, | 
|  | 1163 | acpi_gbl_FADT->sci_int, | 
|  | 1164 | &acpi_gbl_gpe_fadt_blocks | 
|  | 1165 | [1]); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1166 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1167 | if (ACPI_FAILURE(status)) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 1168 | ACPI_EXCEPTION((AE_INFO, status, | 
|  | 1169 | "Could not create GPE Block 1")); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1170 | } | 
|  | 1171 |  | 
|  | 1172 | /* | 
|  | 1173 | * GPE0 and GPE1 do not have to be contiguous in the GPE number | 
|  | 1174 | * space. However, GPE0 always starts at GPE number zero. | 
|  | 1175 | */ | 
|  | 1176 | gpe_number_max = acpi_gbl_FADT->gpe1_base + | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1177 | ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1178 | } | 
|  | 1179 | } | 
|  | 1180 |  | 
|  | 1181 | /* Exit if there are no GPE registers */ | 
|  | 1182 |  | 
|  | 1183 | if ((register_count0 + register_count1) == 0) { | 
| Bob Moore | 52fc0b0 | 2006-10-02 00:00:00 -0400 | [diff] [blame] | 1184 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1185 | /* GPEs are not required by ACPI, this is OK */ | 
|  | 1186 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1187 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, | 
|  | 1188 | "There are no GPE blocks defined in the FADT\n")); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1189 | status = AE_OK; | 
|  | 1190 | goto cleanup; | 
|  | 1191 | } | 
|  | 1192 |  | 
|  | 1193 | /* Check for Max GPE number out-of-range */ | 
|  | 1194 |  | 
|  | 1195 | if (gpe_number_max > ACPI_GPE_MAX) { | 
| Bob Moore | b8e4d89 | 2006-01-27 16:43:00 -0500 | [diff] [blame] | 1196 | ACPI_ERROR((AE_INFO, | 
|  | 1197 | "Maximum GPE number from FADT is too large: 0x%X", | 
|  | 1198 | gpe_number_max)); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1199 | status = AE_BAD_VALUE; | 
|  | 1200 | goto cleanup; | 
|  | 1201 | } | 
|  | 1202 |  | 
| Len Brown | 4be44fc | 2005-08-05 00:44:28 -0400 | [diff] [blame] | 1203 | cleanup: | 
|  | 1204 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 
|  | 1205 | return_ACPI_STATUS(AE_OK); | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1206 | } |