acpi_status acpi_install_gpe_handler ( u32 gpe_number, u32 type, acpi_gpe_handler handler, void *context) { acpi_status status = AE_OK; FUNCTION_TRACE ("Acpi_install_gpe_handler"); /* Parameter validation */ if (!handler || (gpe_number > ACPI_GPE_MAX)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Ensure that we have a valid GPE number */ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); /* Make sure that there isn't a handler there already */ if (acpi_gbl_gpe_info[gpe_number].handler) { status = AE_EXIST; goto cleanup; } /* Install the handler */ acpi_gbl_gpe_info[gpe_number].handler = handler; acpi_gbl_gpe_info[gpe_number].context = context; acpi_gbl_gpe_info[gpe_number].type = (u8) type; /* Clear the GPE (of stale events), the enable it */ acpi_hw_clear_gpe (gpe_number); acpi_hw_enable_gpe (gpe_number); cleanup: acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); }
acpi_status acpi_remove_gpe_handler ( u32 gpe_number, acpi_gpe_handler handler) { acpi_status status = AE_OK; FUNCTION_TRACE ("Acpi_remove_gpe_handler"); /* Parameter validation */ if (!handler || (gpe_number > ACPI_GPE_MAX)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Ensure that we have a valid GPE number */ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { return_ACPI_STATUS (AE_BAD_PARAMETER); } /* Disable the GPE before removing the handler */ acpi_hw_disable_gpe (gpe_number); acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); /* Make sure that the installed handler is the same */ if (acpi_gbl_gpe_info[gpe_number].handler != handler) { acpi_hw_enable_gpe (gpe_number); status = AE_BAD_PARAMETER; goto cleanup; } /* Remove the handler */ acpi_gbl_gpe_info[gpe_number].handler = NULL; acpi_gbl_gpe_info[gpe_number].context = NULL; cleanup: acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_ACPI_STATUS (status); }
static void acpi_ev_asynch_execute_gpe_method ( void *context) { unsigned long gpe_number = (unsigned long) context; acpi_gpe_level_info gpe_info; FUNCTION_TRACE ("Ev_asynch_execute_gpe_method"); /* * Take a snapshot of the GPE info for this level */ acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); gpe_info = acpi_gbl_gpe_info [gpe_number]; acpi_ut_release_mutex (ACPI_MTX_EVENTS); /* * Method Handler (_Lxx, _Exx): * ---------------------------- * Evaluate the _Lxx/_Exx control method that corresponds to this GPE. */ if (gpe_info.method_handle) { acpi_ns_evaluate_by_handle (gpe_info.method_handle, NULL, NULL); } /* * Level-Triggered? * ---------------- * If level-triggered we clear the GPE status bit after handling the event. */ if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) { acpi_hw_clear_gpe (gpe_number); } /* * Enable the GPE. */ acpi_hw_enable_gpe (gpe_number); return_VOID; }
static acpi_status acpi_ev_save_method_info ( acpi_handle obj_handle, u32 level, void *obj_desc, void **return_value) { struct acpi_gpe_block_info *gpe_block = (void *) obj_desc; struct acpi_gpe_event_info *gpe_event_info; u32 gpe_number; char name[ACPI_NAME_SIZE + 1]; u8 type; acpi_status status; ACPI_FUNCTION_TRACE ("ev_save_method_info"); /* Extract the name from the object and convert to a string */ ACPI_MOVE_32_TO_32 (name, &((struct acpi_namespace_node *) obj_handle)->name.integer); name[ACPI_NAME_SIZE] = 0; /* * Edge/Level determination is based on the 2nd character * of the method name */ switch (name[1]) { case 'L': type = ACPI_EVENT_LEVEL_TRIGGERED; break; case 'E': type = ACPI_EVENT_EDGE_TRIGGERED; break; default: /* Unknown method type, just ignore it! */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n", name)); return_ACPI_STATUS (AE_OK); } /* Convert the last two characters of the name to the GPE Number */ gpe_number = ACPI_STRTOUL (&name[2], NULL, 16); if (gpe_number == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not extract GPE number from name: %s (name is not of form _Lnn or _Enn)\n", name)); return_ACPI_STATUS (AE_OK); } /* Ensure that we have a valid GPE number for this GPE block */ if ((gpe_number < gpe_block->block_base_number) || (gpe_number >= (gpe_block->block_base_number + (gpe_block->register_count * 8)))) { /* * Not valid for this GPE block, just ignore it * However, it may be valid for a different GPE block, since GPE0 and GPE1 * methods both appear under \_GPE. */ return_ACPI_STATUS (AE_OK); } /* * Now we can add this information to the gpe_event_info block * for use during dispatch of this GPE. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; gpe_event_info->flags = type; gpe_event_info->method_node = (struct acpi_namespace_node *) obj_handle; /* Enable the GPE (SCIs should be disabled at this point) */ status = acpi_hw_enable_gpe (gpe_event_info); if (ACPI_FAILURE (status)) { return_ACPI_STATUS (status); } ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); return_ACPI_STATUS (AE_OK); }
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method ( void *context) { struct acpi_gpe_event_info *gpe_event_info = (void *) context; u32 gpe_number = 0; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; ACPI_FUNCTION_TRACE ("ev_asynch_execute_gpe_method"); status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_VOID; } /* Must revalidate the gpe_number/gpe_block */ if (!acpi_ev_valid_gpe_event (gpe_event_info)) { status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); return_VOID; } /* * Take a snapshot of the GPE info for this level - we copy the * info to prevent a race condition with remove_handler/remove_block. */ ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, sizeof (struct acpi_gpe_event_info)); status = acpi_ut_release_mutex (ACPI_MTX_EVENTS); if (ACPI_FAILURE (status)) { return_VOID; } if (local_gpe_event_info.method_node) { /* * Invoke the GPE Method (_Lxx, _Exx): * (Evaluate the _Lxx/_Exx control method that corresponds to this GPE.) */ status = acpi_ns_evaluate_by_handle (local_gpe_event_info.method_node, NULL, NULL); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (("%s while evaluating method [%4.4s] for GPE[%2X]\n", acpi_format_exception (status), local_gpe_event_info.method_node->name.ascii, gpe_number)); } } if (local_gpe_event_info.flags & ACPI_EVENT_LEVEL_TRIGGERED) { /* * GPE is level-triggered, we clear the GPE status bit after handling * the event. */ status = acpi_hw_clear_gpe (&local_gpe_event_info); if (ACPI_FAILURE (status)) { return_VOID; } } /* Enable this GPE */ (void) acpi_hw_enable_gpe (&local_gpe_event_info); return_VOID; }
u32 acpi_ev_gpe_dispatch ( u32 gpe_number) { acpi_gpe_level_info gpe_info; FUNCTION_TRACE ("Ev_gpe_dispatch"); /* * Valid GPE number? */ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid GPE bit [%X].\n", gpe_number)); return_VALUE (INTERRUPT_NOT_HANDLED); } /* * Disable the GPE. */ acpi_hw_disable_gpe (gpe_number); gpe_info = acpi_gbl_gpe_info [gpe_number]; /* * Edge-Triggered? * --------------- * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ if (gpe_info.type & ACPI_EVENT_EDGE_TRIGGERED) { acpi_hw_clear_gpe (gpe_number); } /* * Function Handler (e.g. EC)? */ if (gpe_info.handler) { /* Invoke function handler (at interrupt level). */ gpe_info.handler (gpe_info.context); /* Level-Triggered? */ if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) { acpi_hw_clear_gpe (gpe_number); } /* Enable GPE */ acpi_hw_enable_gpe (gpe_number); } /* * Method Handler (e.g. _Exx/_Lxx)? */ else if (gpe_info.method_handle) { if (ACPI_FAILURE(acpi_os_queue_for_execution (OSD_PRIORITY_GPE, acpi_ev_asynch_execute_gpe_method, (void*) (u64)gpe_number))) { /* * Shoudn't occur, but if it does report an error. Note that * the GPE will remain disabled until the ACPI Core Subsystem * is restarted, or the handler is removed/reinstalled. */ REPORT_ERROR (("Acpi_ev_gpe_dispatch: Unable to queue handler for GPE bit [%X]\n", gpe_number)); } } /* * No Handler? Report an error and leave the GPE disabled. */ else { REPORT_ERROR (("Acpi_ev_gpe_dispatch: No installed handler for GPE [%X]\n", gpe_number)); /* Level-Triggered? */ if (gpe_info.type & ACPI_EVENT_LEVEL_TRIGGERED) { acpi_hw_clear_gpe (gpe_number); } } return_VALUE (INTERRUPT_HANDLED); }
static acpi_status acpi_ev_save_method_info ( acpi_handle obj_handle, u32 level, void *obj_desc, void **return_value) { u32 gpe_number; NATIVE_CHAR name[ACPI_NAME_SIZE + 1]; u8 type; PROC_NAME ("Ev_save_method_info"); /* Extract the name from the object and convert to a string */ MOVE_UNALIGNED32_TO_32 (name, &((acpi_namespace_node *) obj_handle)->name); name[ACPI_NAME_SIZE] = 0; /* * Edge/Level determination is based on the 2nd s8 of the method name */ if (name[1] == 'L') { type = ACPI_EVENT_LEVEL_TRIGGERED; } else if (name[1] == 'E') { type = ACPI_EVENT_EDGE_TRIGGERED; } else { /* Unknown method type, just ignore it! */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown GPE method type: %s (name not of form _Lnn or _Enn)\n", name)); return (AE_OK); } /* Convert the last two characters of the name to the Gpe Number */ gpe_number = STRTOUL (&name[2], NULL, 16); if (gpe_number == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not extract GPE number from name: %s (name not of form _Lnn or _Enn)\n", name)); return (AE_OK); } /* Ensure that we have a valid GPE number */ if (acpi_gbl_gpe_valid[gpe_number] == ACPI_GPE_INVALID) { /* Not valid, all we can do here is ignore it */ return (AE_OK); } /* * Now we can add this information to the Gpe_info block * for use during dispatch of this GPE. */ acpi_gbl_gpe_info [gpe_number].type = type; acpi_gbl_gpe_info [gpe_number].method_handle = obj_handle; /* * Enable the GPE (SCIs should be disabled at this point) */ acpi_hw_enable_gpe (gpe_number); ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Registered GPE method %s as GPE number %X\n", name, gpe_number)); return (AE_OK); }