/******************************************************************************* * * FUNCTION: acpi_enable_gpe * * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1 * gpe_number - GPE level within the GPE block * gpe_type - ACPI_GPE_TYPE_RUNTIME or ACPI_GPE_TYPE_WAKE * or both * * RETURN: Status * * DESCRIPTION: Add a reference to a GPE. On the first reference, the GPE is * hardware-enabled (for runtime GPEs), or the GPE register mask * is updated (for wake GPEs). * ******************************************************************************/ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number, u8 gpe_type) { acpi_status status = AE_OK; struct acpi_gpe_event_info *gpe_event_info; acpi_cpu_flags flags; ACPI_FUNCTION_TRACE(acpi_enable_gpe); /* Parameter validation */ if (!gpe_type || (gpe_type & ~ACPI_GPE_TYPE_WAKE_RUN)) { return_ACPI_STATUS(AE_BAD_PARAMETER); } flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock); /* Ensure that we have a valid GPE number */ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number); if (!gpe_event_info) { status = AE_BAD_PARAMETER; goto unlock_and_exit; } if (gpe_type & ACPI_GPE_TYPE_RUNTIME) { if (gpe_event_info->runtime_count == ACPI_UINT8_MAX) { status = AE_LIMIT; /* Too many references */ goto unlock_and_exit; } gpe_event_info->runtime_count++; if (gpe_event_info->runtime_count == 1) { status = acpi_ev_enable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { gpe_event_info->runtime_count--; goto unlock_and_exit; } } } if (gpe_type & ACPI_GPE_TYPE_WAKE) { /* The GPE must have the ability to wake the system */ if (!(gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) { status = AE_TYPE; goto unlock_and_exit; } if (gpe_event_info->wakeup_count == ACPI_UINT8_MAX) { status = AE_LIMIT; /* Too many references */ goto unlock_and_exit; } /* * Update the enable mask on the first wakeup reference. Wake GPEs * are only hardware-enabled just before sleeping. */ gpe_event_info->wakeup_count++; if (gpe_event_info->wakeup_count == 1) { (void)acpi_ev_update_gpe_enable_masks(gpe_event_info); } } unlock_and_exit: acpi_os_release_lock(acpi_gbl_gpe_lock, flags); return_ACPI_STATUS(status); }
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { struct acpi_gpe_event_info *gpe_event_info = (void *)context; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; struct acpi_evaluate_info *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; } /* Set the GPE flags for return to enabled state */ (void)acpi_ev_enable_gpe(gpe_event_info, FALSE); /* * 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; } /* * Must check for control method type dispatch one more * time to avoid race with ev_gpe_install_handler */ if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { /* Allocate the evaluation information block */ info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { status = AE_NO_MEMORY; } else { /* * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx * control method that corresponds to this GPE */ info->prefix_node = local_gpe_event_info.dispatch.method_node; info->parameters = ACPI_CAST_PTR(union acpi_operand_object *, gpe_event_info); info->parameter_type = ACPI_PARAM_GPE; info->flags = ACPI_IGNORE_RETURN_VALUE; status = acpi_ns_evaluate(info); ACPI_FREE(info); } if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "while evaluating GPE method [%4.4s]", acpi_ut_get_node_name (local_gpe_event_info.dispatch. method_node))); } }
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"); /* * _Lxx and _Exx GPE method support * * 1) 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; /* * 2) Edge/Level determination is based on the 2nd character * of the method name * * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE * if a _PRW object is found that points to this GPE. */ switch (name[1]) { case 'L': type = ACPI_GPE_LEVEL_TRIGGERED; break; case 'E': type = ACPI_GPE_EDGE_TRIGGERED; break; default: /* Unknown method type, just ignore it! */ ACPI_ERROR((AE_INFO, "Unknown GPE method type: %s (name not of form _Lxx or _Exx)", 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_ERROR((AE_INFO, "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)", 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. Default type is RUNTIME, although * this may change when the _PRW methods are executed later. */ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number]; gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD | ACPI_GPE_TYPE_RUNTIME); gpe_event_info->dispatch.method_node = (struct acpi_namespace_node *)obj_handle; /* Update enable mask, but don't enable the HW GPE as of yet */ status = acpi_ev_enable_gpe(gpe_event_info, FALSE); ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", name, gpe_number)); return_ACPI_STATUS(status); }
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) { struct acpi_gpe_event_info *gpe_event_info = (void *)context; acpi_status status; struct acpi_gpe_event_info local_gpe_event_info; struct acpi_evaluate_info *info; ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method); status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); if (ACPI_FAILURE(status)) { return_VOID; } if (!acpi_ev_valid_gpe_event(gpe_event_info)) { status = acpi_ut_release_mutex(ACPI_MTX_EVENTS); return_VOID; } (void)acpi_ev_enable_gpe(gpe_event_info, FALSE); 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.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_evaluate_info)); if (!info) { status = AE_NO_MEMORY; } else { info->prefix_node = local_gpe_event_info.dispatch.method_node; info->flags = ACPI_IGNORE_RETURN_VALUE; status = acpi_ns_evaluate(info); ACPI_FREE(info); } if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "while evaluating GPE method [%4.4s]", acpi_ut_get_node_name (local_gpe_event_info.dispatch. method_node))); } } acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe, gpe_event_info); return_VOID; }
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; struct acpi_parameter_info 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; } /* Set the GPE flags for return to enabled state */ (void) acpi_ev_enable_gpe (gpe_event_info, FALSE); /* * 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; } /* * Must check for control method type dispatch one more * time to avoid race with ev_gpe_install_handler */ if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) { /* * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx * control method that corresponds to this GPE */ info.node = local_gpe_event_info.dispatch.method_node; info.parameters = ACPI_CAST_PTR (union acpi_operand_object *, gpe_event_info); info.parameter_type = ACPI_PARAM_GPE; status = acpi_ns_evaluate_by_handle (&info); if (ACPI_FAILURE (status)) { ACPI_REPORT_ERROR (( "%s while evaluating method [%4.4s] for GPE[%2X]\n", acpi_format_exception (status), acpi_ut_get_node_name (local_gpe_event_info.dispatch.method_node), gpe_number)); } }