ACPI_STATUS
AcpiEnableGpe (
    ACPI_HANDLE             GpeDevice,
    UINT32                  GpeNumber,
    UINT8                   GpeType)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
    ACPI_CPU_FLAGS          Flags;


    ACPI_FUNCTION_TRACE (AcpiEnableGpe);


    /* Parameter validation */

    if (!GpeType || (GpeType & ~ACPI_GPE_TYPE_WAKE_RUN))
    {
        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }

    Flags = AcpiOsAcquireLock (AcpiGbl_GpeLock);

    /* Ensure that we have a valid GPE number */

    GpeEventInfo = AcpiEvGetGpeEventInfo (GpeDevice, GpeNumber);
    if (!GpeEventInfo)
    {
        Status = AE_BAD_PARAMETER;
        goto UnlockAndExit;
    }

    if (GpeType & ACPI_GPE_TYPE_RUNTIME)
    {
        if (GpeEventInfo->RuntimeCount == ACPI_UINT8_MAX)
        {
            Status = AE_LIMIT; /* Too many references */
            goto UnlockAndExit;
        }

        GpeEventInfo->RuntimeCount++;
        if (GpeEventInfo->RuntimeCount == 1)
        {
            Status = AcpiEvEnableGpe (GpeEventInfo);
            if (ACPI_FAILURE (Status))
            {
                GpeEventInfo->RuntimeCount--;
                goto UnlockAndExit;
            }
        }
    }

    if (GpeType & ACPI_GPE_TYPE_WAKE)
    {
        /* The GPE must have the ability to wake the system */

        if (!(GpeEventInfo->Flags & ACPI_GPE_CAN_WAKE))
        {
            Status = AE_TYPE;
            goto UnlockAndExit;
        }

        if (GpeEventInfo->WakeupCount == ACPI_UINT8_MAX)
        {
            Status = AE_LIMIT; /* Too many references */
            goto UnlockAndExit;
        }

        /*
         * Update the enable mask on the first wakeup reference. Wake GPEs
         * are only hardware-enabled just before sleeping.
         */
        GpeEventInfo->WakeupCount++;
        if (GpeEventInfo->WakeupCount == 1)
        {
            (void) AcpiEvUpdateGpeEnableMasks (GpeEventInfo);
        }
    }

UnlockAndExit:
    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
    return_ACPI_STATUS (Status);
}
ACPI_STATUS
AcpiDisableGpe (
    ACPI_HANDLE             GpeDevice,
    UINT32                  GpeNumber,
    UINT8                   GpeType)
{
    ACPI_STATUS             Status = AE_OK;
    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
    ACPI_CPU_FLAGS          Flags;


    ACPI_FUNCTION_TRACE (AcpiDisableGpe);


    /* Parameter validation */

    if (!GpeType || (GpeType & ~ACPI_GPE_TYPE_WAKE_RUN))
    {
        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }

    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 (GpeType & ACPI_GPE_TYPE_RUNTIME)
    {
        if (!GpeEventInfo->RuntimeCount)
        {
            Status = AE_LIMIT; /* There are no references to remove */
            goto UnlockAndExit;
        }

        GpeEventInfo->RuntimeCount--;
        if (!GpeEventInfo->RuntimeCount)
        {
            Status = AcpiEvDisableGpe (GpeEventInfo);
            if (ACPI_FAILURE (Status))
            {
                GpeEventInfo->RuntimeCount++;
                goto UnlockAndExit;
            }
        }
    }

    /*
     * Update masks for wake GPE on removal of the last reference.
     * No need to hardware-disable wake GPEs here, they are not currently
     * enabled.
     */
    if (GpeType & ACPI_GPE_TYPE_WAKE)
    {
        if (!GpeEventInfo->WakeupCount)
        {
            Status = AE_LIMIT; /* There are no references to remove */
            goto UnlockAndExit;
        }

        GpeEventInfo->WakeupCount--;
        if (!GpeEventInfo->WakeupCount)
        {
            (void) AcpiEvUpdateGpeEnableMasks (GpeEventInfo);
        }
    }


UnlockAndExit:
    AcpiOsReleaseLock (AcpiGbl_GpeLock, Flags);
    return_ACPI_STATUS (Status);
}
Exemple #3
0
static ACPI_STATUS
AcpiEvMatchPrwAndGpe (
    ACPI_HANDLE             ObjHandle,
    UINT32                  Level,
    void                    *Info,
    void                    **ReturnValue)
{
    ACPI_GPE_WALK_INFO      *GpeInfo = (void *) Info;
    ACPI_NAMESPACE_NODE     *GpeDevice;
    ACPI_GPE_BLOCK_INFO     *GpeBlock;
    ACPI_NAMESPACE_NODE     *TargetGpeDevice;
    ACPI_GPE_EVENT_INFO     *GpeEventInfo;
    ACPI_OPERAND_OBJECT     *PkgDesc;
    ACPI_OPERAND_OBJECT     *ObjDesc;
    UINT32                  GpeNumber;
    ACPI_STATUS             Status;


    ACPI_FUNCTION_TRACE (EvMatchPrwAndGpe);


    /* Check for a _PRW method under this device */

    Status = AcpiUtEvaluateObject (ObjHandle, METHOD_NAME__PRW,
                ACPI_BTYPE_PACKAGE, &PkgDesc);
    if (ACPI_FAILURE (Status))
    {
        /* Ignore all errors from _PRW, we don't want to abort the subsystem */

        return_ACPI_STATUS (AE_OK);
    }

    /* The returned _PRW package must have at least two elements */

    if (PkgDesc->Package.Count < 2)
    {
        goto Cleanup;
    }

    /* Extract pointers from the input context */

    GpeDevice = GpeInfo->GpeDevice;
    GpeBlock = GpeInfo->GpeBlock;

    /*
     * The _PRW object must return a package, we are only interested in the
     * first element
     */
    ObjDesc = PkgDesc->Package.Elements[0];

    if (ObjDesc->Common.Type == ACPI_TYPE_INTEGER)
    {
        /* Use FADT-defined GPE device (from definition of _PRW) */

        TargetGpeDevice = AcpiGbl_FadtGpeDevice;

        /* Integer is the GPE number in the FADT described GPE blocks */

        GpeNumber = (UINT32) ObjDesc->Integer.Value;
    }
    else if (ObjDesc->Common.Type == ACPI_TYPE_PACKAGE)
    {
        /* Package contains a GPE reference and GPE number within a GPE block */

        if ((ObjDesc->Package.Count < 2) ||
            ((ObjDesc->Package.Elements[0])->Common.Type !=
                ACPI_TYPE_LOCAL_REFERENCE) ||
            ((ObjDesc->Package.Elements[1])->Common.Type !=
                ACPI_TYPE_INTEGER))
        {
            goto Cleanup;
        }

        /* Get GPE block reference and decode */

        TargetGpeDevice = ObjDesc->Package.Elements[0]->Reference.Node;
        GpeNumber = (UINT32) ObjDesc->Package.Elements[1]->Integer.Value;
    }
    else
    {
        /* Unknown type, just ignore it */

        goto Cleanup;
    }

    /*
     * Is this GPE within this block?
     *
     * TRUE if and only if these conditions are true:
     *     1) The GPE devices match.
     *     2) The GPE index(number) is within the range of the Gpe Block
     *          associated with the GPE device.
     */
    if ((GpeDevice == TargetGpeDevice) &&
        (GpeNumber >= GpeBlock->BlockBaseNumber) &&
        (GpeNumber < GpeBlock->BlockBaseNumber +
            (GpeBlock->RegisterCount * 8)))
    {
        GpeEventInfo = &GpeBlock->EventInfo[GpeNumber -
            GpeBlock->BlockBaseNumber];

        /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */

        GpeEventInfo->Flags &= ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED);

        Status = AcpiEvSetGpeType (GpeEventInfo, ACPI_GPE_TYPE_WAKE);
        if (ACPI_FAILURE (Status))
        {
            goto Cleanup;
        }

        Status = AcpiEvUpdateGpeEnableMasks (GpeEventInfo, ACPI_GPE_DISABLE);
    }

Cleanup:
    AcpiUtRemoveReference (PkgDesc);
    return_ACPI_STATUS (AE_OK);
}