Пример #1
0
ACPI_STATUS
AcpiExReadGpio (
    ACPI_OPERAND_OBJECT     *ObjDesc,
    void                    *Buffer)
{
    ACPI_STATUS             Status;


    ACPI_FUNCTION_TRACE_PTR (ExReadGpio, ObjDesc);


    /*
     * For GPIO (GeneralPurposeIo), the Address will be the bit offset
     * from the previous Connection() operator, making it effectively a
     * pin number index. The BitLength is the length of the field, which
     * is thus the number of pins.
     */
    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
        ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /* Perform the read */

    Status = AcpiExAccessRegion (
        ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ);

    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    return_ACPI_STATUS (Status);
}
Пример #2
0
ACPI_STATUS
AcpiExWriteGpio (
    ACPI_OPERAND_OBJECT     *SourceDesc,
    ACPI_OPERAND_OBJECT     *ObjDesc,
    ACPI_OPERAND_OBJECT     **ReturnBuffer)
{
    ACPI_STATUS             Status;
    void                    *Buffer;


    ACPI_FUNCTION_TRACE_PTR (ExWriteGpio, ObjDesc);


    /*
     * For GPIO (GeneralPurposeIo), we will bypass the entire field
     * mechanism and handoff the bit address and bit width directly to
     * the handler. The Address will be the bit offset
     * from the previous Connection() operator, making it effectively a
     * pin number index. The BitLength is the length of the field, which
     * is thus the number of pins.
     */
    if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
    {
        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "GPIO FieldWrite [FROM]: (%s:%X), Value %.8X  [TO]: Pin %u Bits %u\n",
        AcpiUtGetTypeName (SourceDesc->Common.Type),
        SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
        ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));

    Buffer = &SourceDesc->Integer.Value;

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /* Perform the write */

    Status = AcpiExAccessRegion (
        ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
    return_ACPI_STATUS (Status);
}
Пример #3
0
static ACPI_STATUS
AcpiExFieldDatumIo (
    ACPI_OPERAND_OBJECT     *ObjDesc,
    UINT32                  FieldDatumByteOffset,
    UINT64                  *Value,
    UINT32                  ReadWrite)
{
    ACPI_STATUS             Status;
    UINT64                  LocalValue;


    ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);


    if (ReadWrite == ACPI_READ)
    {
        if (!Value)
        {
            LocalValue = 0;

            /* To support reads without saving return value */
            Value = &LocalValue;
        }

        /* Clear the entire return buffer first, [Very Important!] */

        *Value = 0;
    }

    /*
     * The four types of fields are:
     *
     * BufferField - Read/write from/to a Buffer
     * RegionField - Read/write from/to a Operation Region.
     * BankField   - Write to a Bank Register, then read/write from/to an
     *               OperationRegion
     * IndexField  - Write to an Index Register, then read/write from/to a
     *               Data Register
     */
    switch (ObjDesc->Common.Type)
    {
    case ACPI_TYPE_BUFFER_FIELD:
        /*
         * If the BufferField arguments have not been previously evaluated,
         * evaluate them now and save the results.
         */
        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
        {
            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }
        }

        if (ReadWrite == ACPI_READ)
        {
            /*
             * Copy the data from the source buffer.
             * Length is the field width in bytes.
             */
            memcpy (Value,
                (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
                    ObjDesc->BufferField.BaseByteOffset +
                    FieldDatumByteOffset,
                ObjDesc->CommonField.AccessByteWidth);
        }
        else
        {
            /*
             * Copy the data to the target buffer.
             * Length is the field width in bytes.
             */
            memcpy ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
                ObjDesc->BufferField.BaseByteOffset +
                FieldDatumByteOffset,
                Value, ObjDesc->CommonField.AccessByteWidth);
        }

        Status = AE_OK;
        break;

    case ACPI_TYPE_LOCAL_BANK_FIELD:
        /*
         * Ensure that the BankValue is not beyond the capacity of
         * the register
         */
        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
                (UINT64) ObjDesc->BankField.Value))
        {
            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
        }

        /*
         * For BankFields, we must write the BankValue to the BankRegister
         * (itself a RegionField) before we can access the data.
         */
        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
                    &ObjDesc->BankField.Value,
                    sizeof (ObjDesc->BankField.Value));
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        /*
         * Now that the Bank has been selected, fall through to the
         * RegionField case and write the datum to the Operation Region
         */

        /*lint -fallthrough */

    case ACPI_TYPE_LOCAL_REGION_FIELD:
        /*
         * For simple RegionFields, we just directly access the owning
         * Operation Region.
         */
        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
                    ReadWrite);
        break;

    case ACPI_TYPE_LOCAL_INDEX_FIELD:
        /*
         * Ensure that the IndexValue is not beyond the capacity of
         * the register
         */
        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
                (UINT64) ObjDesc->IndexField.Value))
        {
            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
        }

        /* Write the index value to the IndexRegister (itself a RegionField) */

        FieldDatumByteOffset += ObjDesc->IndexField.Value;

        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
            "Write to Index Register: Value %8.8X\n",
            FieldDatumByteOffset));

        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
                    &FieldDatumByteOffset,
                    sizeof (FieldDatumByteOffset));
        if (ACPI_FAILURE (Status))
        {
            return_ACPI_STATUS (Status);
        }

        if (ReadWrite == ACPI_READ)
        {
            /* Read the datum from the DataRegister */

            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
                "Read from Data Register\n"));

            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
                        Value, sizeof (UINT64));
        }
        else
        {
            /* Write the datum to the DataRegister */

            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
                "Write to Data Register: Value %8.8X%8.8X\n",
                ACPI_FORMAT_UINT64 (*Value)));

            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
                        Value, sizeof (UINT64));
        }
        break;

    default:

        ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
            ObjDesc->Common.Type));
        Status = AE_AML_INTERNAL;
        break;
    }

    if (ACPI_SUCCESS (Status))
    {
        if (ReadWrite == ACPI_READ)
        {
            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
                "Value Read %8.8X%8.8X, Width %u\n",
                ACPI_FORMAT_UINT64 (*Value),
                ObjDesc->CommonField.AccessByteWidth));
        }
        else
        {
            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
                "Value Written %8.8X%8.8X, Width %u\n",
                ACPI_FORMAT_UINT64 (*Value),
                ObjDesc->CommonField.AccessByteWidth));
        }
    }

    return_ACPI_STATUS (Status);
}
Пример #4
0
ACPI_STATUS
AcpiExReadDataFromField (
    ACPI_WALK_STATE         *WalkState,
    ACPI_OPERAND_OBJECT     *ObjDesc,
    ACPI_OPERAND_OBJECT     **RetBufferDesc)
{
    ACPI_STATUS             Status;
    ACPI_OPERAND_OBJECT     *BufferDesc;
    ACPI_SIZE               Length;
    void                    *Buffer;
    UINT32                  Function;


    ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);


    /* Parameter validation */

    if (!ObjDesc)
    {
        return_ACPI_STATUS (AE_AML_NO_OPERAND);
    }
    if (!RetBufferDesc)
    {
        return_ACPI_STATUS (AE_BAD_PARAMETER);
    }

    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
    {
        /*
         * If the BufferField arguments have not been previously evaluated,
         * evaluate them now and save the results.
         */
        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
        {
            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }
        }
    }
    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
    {
        /*
         * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
         * the data and then directly access the region handler.
         *
         * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
         */
        if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
        {
            Length = ACPI_SMBUS_BUFFER_SIZE;
            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
        }
        else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
        {
            Length = ACPI_GSBUS_BUFFER_SIZE;
            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
        }
        else /* IPMI */
        {
            Length = ACPI_IPMI_BUFFER_SIZE;
            Function = ACPI_READ;
        }

        BufferDesc = AcpiUtCreateBufferObject (Length);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        /* Lock entire transaction if requested */

        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

        /* Call the region handler for the read */

        Status = AcpiExAccessRegion (ObjDesc, 0,
                    ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
                    Function);
        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
        goto Exit;
    }

    /*
     * Allocate a buffer for the contents of the field.
     *
     * If the field is larger than the current integer width, create
     * a BUFFER to hold it.  Otherwise, use an INTEGER.  This allows
     * the use of arithmetic operators on the returned value if the
     * field size is equal or smaller than an Integer.
     *
     * Note: Field.length is in bits.
     */
    Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
    if (Length > AcpiGbl_IntegerByteWidth)
    {
        /* Field is too large for an Integer, create a Buffer instead */

        BufferDesc = AcpiUtCreateBufferObject (Length);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }
        Buffer = BufferDesc->Buffer.Pointer;
    }
    else
    {
        /* Field will fit within an Integer (normal case) */

        BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        Length = AcpiGbl_IntegerByteWidth;
        Buffer = &BufferDesc->Integer.Value;
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
        ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
        ObjDesc->CommonField.BitLength,
        ObjDesc->CommonField.StartFieldBitOffset,
        ObjDesc->CommonField.BaseByteOffset));

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /* Read from the field */

    Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);


Exit:
    if (ACPI_FAILURE (Status))
    {
        AcpiUtRemoveReference (BufferDesc);
    }
    else
    {
        *RetBufferDesc = BufferDesc;
    }

    return_ACPI_STATUS (Status);
}
Пример #5
0
ACPI_STATUS
AcpiExWriteDataToField (
    ACPI_OPERAND_OBJECT     *SourceDesc,
    ACPI_OPERAND_OBJECT     *ObjDesc,
    ACPI_OPERAND_OBJECT     **ResultDesc)
{
    ACPI_STATUS             Status;
    UINT32                  Length;
    void                    *Buffer;
    ACPI_OPERAND_OBJECT     *BufferDesc;
    UINT32                  Function;


    ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);


    /* Parameter validation */

    if (!SourceDesc || !ObjDesc)
    {
        return_ACPI_STATUS (AE_AML_NO_OPERAND);
    }

    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
    {
        /*
         * If the BufferField arguments have not been previously evaluated,
         * evaluate them now and save the results.
         */
        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
        {
            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }
        }
    }
    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
    {
        /*
         * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
         * mechanism and handoff the buffer directly to the handler. For
         * these address spaces, the buffer is bi-directional; on a write,
         * return data is returned in the same buffer.
         *
         * Source must be a buffer of sufficient size:
         * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
         *
         * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
         */
        if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
        {
            ACPI_ERROR ((AE_INFO,
                "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
                AcpiUtGetObjectTypeName (SourceDesc)));

            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
        }

        if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
        {
            Length = ACPI_SMBUS_BUFFER_SIZE;
            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
        }
        else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
        {
            Length = ACPI_GSBUS_BUFFER_SIZE;
            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
        }
        else /* IPMI */
        {
            Length = ACPI_IPMI_BUFFER_SIZE;
            Function = ACPI_WRITE;
        }

        if (SourceDesc->Buffer.Length < Length)
        {
            ACPI_ERROR ((AE_INFO,
                "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
                Length, SourceDesc->Buffer.Length));

            return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
        }

        /* Create the bi-directional buffer */

        BufferDesc = AcpiUtCreateBufferObject (Length);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        Buffer = BufferDesc->Buffer.Pointer;
        ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);

        /* Lock entire transaction if requested */

        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

        /*
         * Perform the write (returns status and perhaps data in the
         * same buffer)
         */
        Status = AcpiExAccessRegion (ObjDesc, 0,
                    (UINT64 *) Buffer, Function);
        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);

        *ResultDesc = BufferDesc;
        return_ACPI_STATUS (Status);
    }

    /* Get a pointer to the data to be written */

    switch (SourceDesc->Common.Type)
    {
    case ACPI_TYPE_INTEGER:
        Buffer = &SourceDesc->Integer.Value;
        Length = sizeof (SourceDesc->Integer.Value);
        break;

    case ACPI_TYPE_BUFFER:
        Buffer = SourceDesc->Buffer.Pointer;
        Length = SourceDesc->Buffer.Length;
        break;

    case ACPI_TYPE_STRING:
        Buffer = SourceDesc->String.Pointer;
        Length = SourceDesc->String.Length;
        break;

    default:
        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
        SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
        SourceDesc->Common.Type, Buffer, Length));

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
        ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
        ObjDesc->Common.Type,
        ObjDesc->CommonField.BitLength,
        ObjDesc->CommonField.StartFieldBitOffset,
        ObjDesc->CommonField.BaseByteOffset));

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /* Write to the field */

    Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);

    return_ACPI_STATUS (Status);
}
Пример #6
0
ACPI_STATUS
AcpiExWriteDataToField (
    ACPI_OPERAND_OBJECT     *SourceDesc,
    ACPI_OPERAND_OBJECT     *ObjDesc,
    ACPI_OPERAND_OBJECT     **ResultDesc)
{
    ACPI_STATUS             Status;
    UINT32                  Length;
    void                    *Buffer;
    ACPI_OPERAND_OBJECT     *BufferDesc;
    UINT32                  Function;
    UINT16                  AccessorType;


    ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);


    /* Parameter validation */

    if (!SourceDesc || !ObjDesc)
    {
        return_ACPI_STATUS (AE_AML_NO_OPERAND);
    }

    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
    {
        /*
         * If the BufferField arguments have not been previously evaluated,
         * evaluate them now and save the results.
         */
        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
        {
            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
            if (ACPI_FAILURE (Status))
            {
                return_ACPI_STATUS (Status);
            }
        }
    }
    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
    {
        /*
         * This is an SMBus, GSBus or IPMI write. We will bypass the entire
         * field mechanism and handoff the buffer directly to the handler.
         * For these address spaces, the buffer is bi-directional; on a
         * write, return data is returned in the same buffer.
         *
         * Source must be a buffer of sufficient size:
         * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
         * ACPI_IPMI_BUFFER_SIZE.
         *
         * Note: SMBus and GSBus protocol type is passed in upper 16-bits
         * of Function
         */
        if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
        {
            ACPI_ERROR ((AE_INFO,
                "SMBus/IPMI/GenericSerialBus write requires "
                "Buffer, found type %s",
                AcpiUtGetObjectTypeName (SourceDesc)));

            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
        }

        if (ObjDesc->Field.RegionObj->Region.SpaceId ==
            ACPI_ADR_SPACE_SMBUS)
        {
            Length = ACPI_SMBUS_BUFFER_SIZE;
            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
        }
        else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
            ACPI_ADR_SPACE_GSBUS)
        {
            AccessorType = ObjDesc->Field.Attribute;
            Length = AcpiExGetSerialAccessLength (
                AccessorType, ObjDesc->Field.AccessLength);

            /*
             * Add additional 2 bytes for the GenericSerialBus data buffer:
             *
             *     Status;    (Byte 0 of the data buffer)
             *     Length;    (Byte 1 of the data buffer)
             *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
             */
            Length += 2;
            Function = ACPI_WRITE | (AccessorType << 16);
        }
        else /* IPMI */
        {
            Length = ACPI_IPMI_BUFFER_SIZE;
            Function = ACPI_WRITE;
        }

        if (SourceDesc->Buffer.Length < Length)
        {
            ACPI_ERROR ((AE_INFO,
                "SMBus/IPMI/GenericSerialBus write requires "
                "Buffer of length %u, found length %u",
                Length, SourceDesc->Buffer.Length));

            return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
        }

        /* Create the bi-directional buffer */

        BufferDesc = AcpiUtCreateBufferObject (Length);
        if (!BufferDesc)
        {
            return_ACPI_STATUS (AE_NO_MEMORY);
        }

        Buffer = BufferDesc->Buffer.Pointer;
        memcpy (Buffer, SourceDesc->Buffer.Pointer, Length);

        /* Lock entire transaction if requested */

        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

        /*
         * Perform the write (returns status and perhaps data in the
         * same buffer)
         */
        Status = AcpiExAccessRegion (
            ObjDesc, 0, (UINT64 *) Buffer, Function);
        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);

        *ResultDesc = BufferDesc;
        return_ACPI_STATUS (Status);
    }
    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
    {
        /*
         * For GPIO (GeneralPurposeIo), we will bypass the entire field
         * mechanism and handoff the bit address and bit width directly to
         * the handler. The Address will be the bit offset
         * from the previous Connection() operator, making it effectively a
         * pin number index. The BitLength is the length of the field, which
         * is thus the number of pins.
         */
        if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
        {
            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
        }

        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
            "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]: Pin %u Bits %u\n",
            AcpiUtGetTypeName (SourceDesc->Common.Type),
            SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
            ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));

        Buffer = &SourceDesc->Integer.Value;

        /* Lock entire transaction if requested */

        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

        /* Perform the write */

        Status = AcpiExAccessRegion (
            ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
        return_ACPI_STATUS (Status);
    }

    /* Get a pointer to the data to be written */

    switch (SourceDesc->Common.Type)
    {
    case ACPI_TYPE_INTEGER:

        Buffer = &SourceDesc->Integer.Value;
        Length = sizeof (SourceDesc->Integer.Value);
        break;

    case ACPI_TYPE_BUFFER:

        Buffer = SourceDesc->Buffer.Pointer;
        Length = SourceDesc->Buffer.Length;
        break;

    case ACPI_TYPE_STRING:

        Buffer = SourceDesc->String.Pointer;
        Length = SourceDesc->String.Length;
        break;

    default:

        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    }

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
        SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
        SourceDesc->Common.Type, Buffer, Length));

    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
        "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
        ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
        ObjDesc->Common.Type,
        ObjDesc->CommonField.BitLength,
        ObjDesc->CommonField.StartFieldBitOffset,
        ObjDesc->CommonField.BaseByteOffset));

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /* Write to the field */

    Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);

    return_ACPI_STATUS (Status);
}
Пример #7
0
ACPI_STATUS
AcpiExWriteSerialBus (
    ACPI_OPERAND_OBJECT     *SourceDesc,
    ACPI_OPERAND_OBJECT     *ObjDesc,
    ACPI_OPERAND_OBJECT     **ReturnBuffer)
{
    ACPI_STATUS             Status;
    UINT32                  BufferLength;
    UINT32                  DataLength;
    void                    *Buffer;
    ACPI_OPERAND_OBJECT     *BufferDesc;
    UINT32                  Function;
    UINT16                  AccessorType;


    ACPI_FUNCTION_TRACE_PTR (ExWriteSerialBus, ObjDesc);


    /*
     * This is an SMBus, GSBus or IPMI write. We will bypass the entire
     * field mechanism and handoff the buffer directly to the handler.
     * For these address spaces, the buffer is bidirectional; on a
     * write, return data is returned in the same buffer.
     *
     * Source must be a buffer of sufficient size, these are fixed size:
     * ACPI_SMBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
     *
     * Note: SMBus and GSBus protocol type is passed in upper 16-bits
     * of Function
     *
     * Common buffer format:
     *     Status;    (Byte 0 of the data buffer)
     *     Length;    (Byte 1 of the data buffer)
     *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
     */
    if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
    {
        ACPI_ERROR ((AE_INFO,
            "SMBus/IPMI/GenericSerialBus write requires "
            "Buffer, found type %s",
            AcpiUtGetObjectTypeName (SourceDesc)));

        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    }

    switch (ObjDesc->Field.RegionObj->Region.SpaceId)
    {
    case ACPI_ADR_SPACE_SMBUS:

        BufferLength = ACPI_SMBUS_BUFFER_SIZE;
        Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
        break;

    case ACPI_ADR_SPACE_IPMI:

        BufferLength = ACPI_IPMI_BUFFER_SIZE;
        Function = ACPI_WRITE;
        break;

    case ACPI_ADR_SPACE_GSBUS:

        AccessorType = ObjDesc->Field.Attribute;
        Status = AcpiExGetProtocolBufferLength (AccessorType, &BufferLength);
        if (ACPI_FAILURE (Status))
        {
            ACPI_ERROR ((AE_INFO,
                "Invalid protocol ID for GSBus: 0x%4.4X", AccessorType));

            return_ACPI_STATUS (Status);
        }

        /* Add header length to get the full size of the buffer */

        BufferLength += ACPI_SERIAL_HEADER_SIZE;
        Function = ACPI_WRITE | (AccessorType << 16);
        break;

    default:
        return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    }

    /* Create the transfer/bidirectional/return buffer */

    BufferDesc = AcpiUtCreateBufferObject (BufferLength);
    if (!BufferDesc)
    {
        return_ACPI_STATUS (AE_NO_MEMORY);
    }

    /* Copy the input buffer data to the transfer buffer */

    Buffer = BufferDesc->Buffer.Pointer;
    DataLength = (BufferLength < SourceDesc->Buffer.Length ?
        BufferLength : SourceDesc->Buffer.Length);
    memcpy (Buffer, SourceDesc->Buffer.Pointer, DataLength);

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /*
     * Perform the write (returns status and perhaps data in the
     * same buffer)
     */
    Status = AcpiExAccessRegion (
        ObjDesc, 0, (UINT64 *) Buffer, Function);
    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);

    *ReturnBuffer = BufferDesc;
    return_ACPI_STATUS (Status);
}
Пример #8
0
ACPI_STATUS
AcpiExReadSerialBus (
    ACPI_OPERAND_OBJECT     *ObjDesc,
    ACPI_OPERAND_OBJECT     **ReturnBuffer)
{
    ACPI_STATUS             Status;
    UINT32                  BufferLength;
    ACPI_OPERAND_OBJECT     *BufferDesc;
    UINT32                  Function;
    UINT16                  AccessorType;


    ACPI_FUNCTION_TRACE_PTR (ExReadSerialBus, ObjDesc);


    /*
     * This is an SMBus, GSBus or IPMI read. We must create a buffer to
     * hold the data and then directly access the region handler.
     *
     * Note: SMBus and GSBus protocol value is passed in upper 16-bits
     * of Function
     *
     * Common buffer format:
     *     Status;    (Byte 0 of the data buffer)
     *     Length;    (Byte 1 of the data buffer)
     *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
     */
    switch (ObjDesc->Field.RegionObj->Region.SpaceId)
    {
    case ACPI_ADR_SPACE_SMBUS:

        BufferLength = ACPI_SMBUS_BUFFER_SIZE;
        Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
        break;

    case ACPI_ADR_SPACE_IPMI:

        BufferLength = ACPI_IPMI_BUFFER_SIZE;
        Function = ACPI_READ;
        break;

    case ACPI_ADR_SPACE_GSBUS:

        AccessorType = ObjDesc->Field.Attribute;
        if (AccessorType == AML_FIELD_ATTRIB_RAW_PROCESS_BYTES)
        {
            ACPI_ERROR ((AE_INFO,
                "Invalid direct read using bidirectional write-then-read protocol"));

            return_ACPI_STATUS (AE_AML_PROTOCOL);
        }

        Status = AcpiExGetProtocolBufferLength (AccessorType, &BufferLength);
        if (ACPI_FAILURE (Status))
        {
            ACPI_ERROR ((AE_INFO,
                "Invalid protocol ID for GSBus: 0x%4.4X", AccessorType));

            return_ACPI_STATUS (Status);
        }

        /* Add header length to get the full size of the buffer */

        BufferLength += ACPI_SERIAL_HEADER_SIZE;
        Function = ACPI_READ | (AccessorType << 16);
        break;

    default:
        return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    }

    /* Create the local transfer buffer that is returned to the caller */

    BufferDesc = AcpiUtCreateBufferObject (BufferLength);
    if (!BufferDesc)
    {
        return_ACPI_STATUS (AE_NO_MEMORY);
    }

    /* Lock entire transaction if requested */

    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);

    /* Call the region handler for the write-then-read */

    Status = AcpiExAccessRegion (ObjDesc, 0,
        ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);

    *ReturnBuffer = BufferDesc;
    return_ACPI_STATUS (Status);
}