u32 acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) { acpi_status status; ACPI_FUNCTION_TRACE(ev_gpe_dispatch); acpi_os_gpe_count(gpe_number); /* * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) { status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to clear GPE[0x%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } /* * Dispatch the GPE to either any installed handler or control * method associated with this GPE (_Lxx or _Exx). We invoke * the method first in case it has side effects that would be * interfered with if the handler has already altered hardware * state. If there is neither a handler nor a method, we * disable this GPE to prevent further such pointless events * from firing. */ if (gpe_event_info->flags & ACPI_GPE_DISPATCH_METHOD) { /* * Disable the GPE, so it doesn't keep firing before the method has a * chance to run (it runs asynchronously with interrupts enabled). */ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to disable GPE[0x%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } /* * Execute the method associated with the GPE * NOTE: Level-triggered GPEs are cleared after the method completes. */ status = acpi_os_execute(OSL_GPE_HANDLER, acpi_ev_asynch_execute_gpe_method, gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to queue handler for GPE[0x%2X] - event disabled", gpe_number)); } } if (gpe_event_info->flags & ACPI_GPE_DISPATCH_HANDLER) { /* * Invoke the installed handler (at interrupt level) * Ignore return status for now. * TBD: leave GPE disabled on error? */ (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> dispatch. handler-> context); /* It is now safe to clear level-triggered events. */ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to clear GPE[0x%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } } if (!(gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)) { /* * No handler or method to run! * 03/2010: This case should no longer be possible. We will not allow * a GPE to be enabled if it has no handler or method. */ ACPI_ERROR((AE_INFO, "No handler or method for GPE[0x%2X], disabling event", gpe_number)); /* * Disable the GPE. The GPE will remain disabled a handler * is installed or ACPICA is restarted. */ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to disable GPE[0x%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } return_UINT32(ACPI_INTERRUPT_HANDLED); }
u32 acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) { acpi_status status; ACPI_FUNCTION_TRACE(ev_gpe_dispatch); acpi_os_gpe_count(gpe_number); /* * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) { status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to clear GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } /* * Dispatch the GPE to either an installed handler, or the control method * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke * it and do not attempt to run the method. If there is neither a handler * nor a method, we disable this GPE to prevent further such pointless * events from firing. */ switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_HANDLER: /* * Invoke the installed handler (at interrupt level) * Ignore return status for now. * TBD: leave GPE disabled on error? */ (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> dispatch. handler-> context); /* It is now safe to clear level-triggered events. */ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to clear GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } break; case ACPI_GPE_DISPATCH_METHOD: /* * Disable the GPE, so it doesn't keep firing before the method has a * chance to run (it runs asynchronously with interrupts enabled). */ status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to disable GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } /* * Execute the method associated with the GPE * NOTE: Level-triggered GPEs are cleared after the method completes. */ status = acpi_os_execute(OSL_GPE_HANDLER, acpi_ev_asynch_execute_gpe_method, gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to queue handler for GPE[%2X] - event disabled", gpe_number)); } break; default: /* No handler or method to run! */ ACPI_ERROR((AE_INFO, "No handler or method for GPE[%2X], disabling event", gpe_number)); /* * Disable the GPE. The GPE will remain disabled until the ACPICA * Core Subsystem is restarted, or a handler is installed. */ status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to disable GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } break; } return_UINT32(ACPI_INTERRUPT_HANDLED); }
u32 acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number) { acpi_status status; ACPI_FUNCTION_TRACE(ev_gpe_dispatch); acpi_os_gpe_count(gpe_number); if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) { status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to clear GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) { case ACPI_GPE_DISPATCH_HANDLER: (void)gpe_event_info->dispatch.handler->address(gpe_event_info-> dispatch. handler-> context); if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { status = acpi_hw_clear_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to clear GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } } break; case ACPI_GPE_DISPATCH_METHOD: status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to disable GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } status = acpi_os_execute(OSL_GPE_HANDLER, acpi_ev_asynch_execute_gpe_method, gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to queue handler for GPE[%2X] - event disabled", gpe_number)); } break; default: ACPI_ERROR((AE_INFO, "No handler or method for GPE[%2X], disabling event", gpe_number)); status = acpi_ev_disable_gpe(gpe_event_info); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Unable to disable GPE[%2X]", gpe_number)); return_UINT32(ACPI_INTERRUPT_NOT_HANDLED); } break; } return_UINT32(ACPI_INTERRUPT_HANDLED); }