ACPI_STATUS AcpiSetGpe ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber, UINT8 Action) { ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_STATUS Status; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiSetGpe); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Perform the action */ switch (Action) { case ACPI_GPE_ENABLE: Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); GpeEventInfo->DisableForDispatch = FALSE; break; case ACPI_GPE_DISABLE: Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); GpeEventInfo->DisableForDispatch = TRUE; break; default: Status = AE_BAD_PARAMETER; break; } UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiEvMaskGpe ( ACPI_GPE_EVENT_INFO *GpeEventInfo, BOOLEAN IsMasked) { ACPI_GPE_REGISTER_INFO *GpeRegisterInfo; UINT32 RegisterBit; ACPI_FUNCTION_TRACE (EvMaskGpe); GpeRegisterInfo = GpeEventInfo->RegisterInfo; if (!GpeRegisterInfo) { return_ACPI_STATUS (AE_NOT_EXIST); } RegisterBit = AcpiHwGetGpeRegisterBit (GpeEventInfo); /* Perform the action */ if (IsMasked) { if (RegisterBit & GpeRegisterInfo->MaskForRun) { return_ACPI_STATUS (AE_BAD_PARAMETER); } (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); ACPI_SET_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit); } else { if (!(RegisterBit & GpeRegisterInfo->MaskForRun)) { return_ACPI_STATUS (AE_BAD_PARAMETER); } ACPI_CLEAR_BIT (GpeRegisterInfo->MaskForRun, (UINT8) RegisterBit); if (GpeEventInfo->RuntimeCount && !GpeEventInfo->DisableForDispatch) { (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); } } return_ACPI_STATUS (AE_OK); }
ACPI_STATUS AcpiEvFinishGpe ( ACPI_GPE_EVENT_INFO *GpeEventInfo) { ACPI_STATUS Status; if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) { /* * GPE is level-triggered, we clear the GPE status bit after * handling the event. */ Status = AcpiHwClearGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { return (Status); } } /* * Enable this GPE, conditionally. This means that the GPE will * only be physically enabled if the EnableMask bit is set * in the EventInfo. */ (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); return (AE_OK); }
ACPI_STATUS AcpiEvRemoveGpeReference ( ACPI_GPE_EVENT_INFO *GpeEventInfo) { ACPI_STATUS Status = AE_OK; ACPI_FUNCTION_TRACE (EvRemoveGpeReference); if (!GpeEventInfo->RuntimeCount) { return_ACPI_STATUS (AE_LIMIT); } GpeEventInfo->RuntimeCount--; if (!GpeEventInfo->RuntimeCount) { /* Disable on last reference */ Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); if (ACPI_SUCCESS (Status)) { Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); } if (ACPI_FAILURE (Status)) { GpeEventInfo->RuntimeCount++; } } return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiEvEnableGpe ( ACPI_GPE_EVENT_INFO *GpeEventInfo) { ACPI_STATUS Status; ACPI_FUNCTION_TRACE (EvEnableGpe); /* * We will only allow a GPE to be enabled if it has either an associated * method (_Lxx/_Exx) or a handler, or is using the implicit notify * feature. Otherwise, the GPE will be immediately disabled by * AcpiEvGpeDispatch the first time it fires. */ if ((GpeEventInfo->Flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_NONE) { return_ACPI_STATUS (AE_NO_HANDLER); } /* Clear the GPE (of stale events) */ Status = AcpiHwClearGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Enable the requested GPE */ Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiDisableGpe ( ACPI_HANDLE GpeDevice, UINT32 GpeNumber) { ACPI_STATUS Status = AE_OK; ACPI_GPE_EVENT_INFO *GpeEventInfo; ACPI_CPU_FLAGS Flags; ACPI_FUNCTION_TRACE (AcpiDisableGpe); Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock); /* Ensure that we have a valid GPE number */ GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber); if (!GpeEventInfo) { Status = AE_BAD_PARAMETER; goto UnlockAndExit; } /* Hardware-disable a runtime GPE on removal of the last reference */ if (!GpeEventInfo->RuntimeCount) { Status = AE_LIMIT; /* There are no references to remove */ goto UnlockAndExit; } GpeEventInfo->RuntimeCount--; if (!GpeEventInfo->RuntimeCount) { Status = AcpiEvUpdateGpeEnableMask (GpeEventInfo); if (ACPI_SUCCESS (Status)) { Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); } if (ACPI_FAILURE (Status)) { GpeEventInfo->RuntimeCount++; } } UnlockAndExit: AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags); return_ACPI_STATUS (Status); }
ACPI_STATUS AcpiEvEnableGpe ( ACPI_GPE_EVENT_INFO *GpeEventInfo) { ACPI_STATUS Status; ACPI_FUNCTION_TRACE (EvEnableGpe); /* Clear the GPE (of stale events) */ Status = AcpiHwClearGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { return_ACPI_STATUS (Status); } /* Enable the requested GPE */ Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_ENABLE); return_ACPI_STATUS (Status); }
UINT32 AcpiEvGpeDispatch ( ACPI_NAMESPACE_NODE *GpeDevice, ACPI_GPE_EVENT_INFO *GpeEventInfo, UINT32 GpeNumber) { ACPI_STATUS Status; UINT32 ReturnValue; ACPI_FUNCTION_TRACE (EvGpeDispatch); /* * Always disable the GPE so that it does not keep firing before * any asynchronous activity completes (either from the execution * of a GPE method or an asynchronous GPE handler.) * * If there is no handler or method to run, just disable the * GPE and leave it disabled permanently to prevent further such * pointless events from firing. */ Status = AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Unable to disable GPE %02X", GpeNumber)); return_UINT32 (ACPI_INTERRUPT_NOT_HANDLED); } /* * If edge-triggered, clear the GPE status bit now. Note that * level-triggered events are cleared after the GPE is serviced. */ if ((GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) { Status = AcpiHwClearGpe (GpeEventInfo); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Unable to clear GPE %02X", GpeNumber)); (void) AcpiHwLowSetGpe ( GpeEventInfo, ACPI_GPE_CONDITIONAL_ENABLE); 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, leave the GPE * disabled. */ switch (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags)) { case ACPI_GPE_DISPATCH_HANDLER: /* Invoke the installed handler (at interrupt level) */ ReturnValue = GpeEventInfo->Dispatch.Handler->Address ( GpeDevice, GpeNumber, GpeEventInfo->Dispatch.Handler->Context); /* If requested, clear (if level-triggered) and reenable the GPE */ if (ReturnValue & ACPI_REENABLE_GPE) { (void) AcpiEvFinishGpe (GpeEventInfo); } break; case ACPI_GPE_DISPATCH_METHOD: case ACPI_GPE_DISPATCH_NOTIFY: /* * Execute the method associated with the GPE * NOTE: Level-triggered GPEs are cleared after the method completes. */ Status = AcpiOsExecute (OSL_GPE_HANDLER, AcpiEvAsynchExecuteGpeMethod, GpeEventInfo); if (ACPI_FAILURE (Status)) { ACPI_EXCEPTION ((AE_INFO, Status, "Unable to queue handler for GPE %02X - event disabled", GpeNumber)); } break; default: /* * 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 %02X, disabling event", GpeNumber)); break; } return_UINT32 (ACPI_INTERRUPT_HANDLED); }
ACPI_STATUS AcpiEvMatchGpeMethod ( ACPI_HANDLE ObjHandle, UINT32 Level, void *Context, void **ReturnValue) { ACPI_NAMESPACE_NODE *MethodNode = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjHandle); ACPI_GPE_WALK_INFO *WalkInfo = ACPI_CAST_PTR (ACPI_GPE_WALK_INFO, Context); ACPI_GPE_EVENT_INFO *GpeEventInfo; UINT32 GpeNumber; char Name[ACPI_NAME_SIZE + 1]; UINT8 Type; ACPI_FUNCTION_TRACE (EvMatchGpeMethod); /* Check if requested OwnerId matches this OwnerId */ if ((WalkInfo->ExecuteByOwnerId) && (MethodNode->OwnerId != WalkInfo->OwnerId)) { return_ACPI_STATUS (AE_OK); } /* * Match and decode the _Lxx and _Exx GPE method names * * 1) Extract the method name and null terminate it */ ACPI_MOVE_32_TO_32 (Name, &MethodNode->Name.Integer); Name[ACPI_NAME_SIZE] = 0; /* 2) Name must begin with an underscore */ if (Name[0] != '_') { return_ACPI_STATUS (AE_OK); /* Ignore this method */ } /* * 3) Edge/Level determination is based on the 2nd character * of the method name */ 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_DEBUG_PRINT ((ACPI_DB_LOAD, "Ignoring unknown GPE method type: %s " "(name not of form _Lxx or _Exx)", Name)); return_ACPI_STATUS (AE_OK); } /* 4) The last two characters of the name are the hex GPE Number */ GpeNumber = strtoul (&Name[2], NULL, 16); if (GpeNumber == ACPI_UINT32_MAX) { /* Conversion failed; invalid method, just ignore it */ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "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 */ GpeEventInfo = AcpiEvLowGetGpeInfo (GpeNumber, WalkInfo->GpeBlock); if (!GpeEventInfo) { /* * This GpeNumber is 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); } if ((ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_HANDLER) || (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_RAW_HANDLER)) { /* If there is already a handler, ignore this GPE method */ return_ACPI_STATUS (AE_OK); } if (ACPI_GPE_DISPATCH_TYPE (GpeEventInfo->Flags) == ACPI_GPE_DISPATCH_METHOD) { /* * If there is already a method, ignore this method. But check * for a type mismatch (if both the _Lxx AND _Exx exist) */ if (Type != (GpeEventInfo->Flags & ACPI_GPE_XRUPT_TYPE_MASK)) { ACPI_ERROR ((AE_INFO, "For GPE 0x%.2X, found both _L%2.2X and _E%2.2X methods", GpeNumber, GpeNumber, GpeNumber)); } return_ACPI_STATUS (AE_OK); } /* Disable the GPE in case it's been enabled already. */ (void) AcpiHwLowSetGpe (GpeEventInfo, ACPI_GPE_DISABLE); /* * Add the GPE information from above to the GpeEventInfo block for * use during dispatch of this GPE. */ GpeEventInfo->Flags &= ~(ACPI_GPE_DISPATCH_MASK); GpeEventInfo->Flags |= (UINT8) (Type | ACPI_GPE_DISPATCH_METHOD); GpeEventInfo->Dispatch.MethodNode = MethodNode; ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Registered GPE method %s as GPE number 0x%.2X\n", Name, GpeNumber)); return_ACPI_STATUS (AE_OK); }