exfield.c revision 1.1.1.4.2.3
11.1Sjruoho/******************************************************************************
21.1Sjruoho *
31.1Sjruoho * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
41.1Sjruoho *
51.1Sjruoho *****************************************************************************/
61.1Sjruoho
71.1.1.2Sjruoho/*
81.1.1.4.2.3Sskrll * Copyright (C) 2000 - 2016, Intel Corp.
91.1Sjruoho * All rights reserved.
101.1Sjruoho *
111.1.1.2Sjruoho * Redistribution and use in source and binary forms, with or without
121.1.1.2Sjruoho * modification, are permitted provided that the following conditions
131.1.1.2Sjruoho * are met:
141.1.1.2Sjruoho * 1. Redistributions of source code must retain the above copyright
151.1.1.2Sjruoho *    notice, this list of conditions, and the following disclaimer,
161.1.1.2Sjruoho *    without modification.
171.1.1.2Sjruoho * 2. Redistributions in binary form must reproduce at minimum a disclaimer
181.1.1.2Sjruoho *    substantially similar to the "NO WARRANTY" disclaimer below
191.1.1.2Sjruoho *    ("Disclaimer") and any redistribution must be conditioned upon
201.1.1.2Sjruoho *    including a substantially similar Disclaimer requirement for further
211.1.1.2Sjruoho *    binary redistribution.
221.1.1.2Sjruoho * 3. Neither the names of the above-listed copyright holders nor the names
231.1.1.2Sjruoho *    of any contributors may be used to endorse or promote products derived
241.1.1.2Sjruoho *    from this software without specific prior written permission.
251.1.1.2Sjruoho *
261.1.1.2Sjruoho * Alternatively, this software may be distributed under the terms of the
271.1.1.2Sjruoho * GNU General Public License ("GPL") version 2 as published by the Free
281.1.1.2Sjruoho * Software Foundation.
291.1.1.2Sjruoho *
301.1.1.2Sjruoho * NO WARRANTY
311.1.1.2Sjruoho * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
321.1.1.2Sjruoho * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
331.1.1.2Sjruoho * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
341.1.1.2Sjruoho * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
351.1.1.2Sjruoho * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
361.1.1.2Sjruoho * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
371.1.1.2Sjruoho * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
381.1.1.2Sjruoho * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
391.1.1.2Sjruoho * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
401.1.1.2Sjruoho * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
411.1.1.2Sjruoho * POSSIBILITY OF SUCH DAMAGES.
421.1.1.2Sjruoho */
431.1Sjruoho
441.1Sjruoho#include "acpi.h"
451.1Sjruoho#include "accommon.h"
461.1Sjruoho#include "acdispat.h"
471.1Sjruoho#include "acinterp.h"
481.1.1.4Schristos#include "amlcode.h"
491.1Sjruoho
501.1Sjruoho
511.1Sjruoho#define _COMPONENT          ACPI_EXECUTER
521.1Sjruoho        ACPI_MODULE_NAME    ("exfield")
531.1Sjruoho
541.1.1.4Schristos/* Local prototypes */
551.1.1.4Schristos
561.1.1.4Schristosstatic UINT32
571.1.1.4SchristosAcpiExGetSerialAccessLength (
581.1.1.4Schristos    UINT32                  AccessorType,
591.1.1.4Schristos    UINT32                  AccessLength);
601.1.1.4Schristos
611.1.1.4Schristos
621.1.1.4Schristos/*******************************************************************************
631.1.1.4Schristos *
641.1.1.4Schristos * FUNCTION:    AcpiExGetSerialAccessLength
651.1.1.4Schristos *
661.1.1.4Schristos * PARAMETERS:  AccessorType    - The type of the protocol indicated by region
671.1.1.4Schristos *                                field access attributes
681.1.1.4Schristos *              AccessLength    - The access length of the region field
691.1.1.4Schristos *
701.1.1.4Schristos * RETURN:      Decoded access length
711.1.1.4Schristos *
721.1.1.4Schristos * DESCRIPTION: This routine returns the length of the GenericSerialBus
731.1.1.4Schristos *              protocol bytes
741.1.1.4Schristos *
751.1.1.4Schristos ******************************************************************************/
761.1.1.4Schristos
771.1.1.4Schristosstatic UINT32
781.1.1.4SchristosAcpiExGetSerialAccessLength (
791.1.1.4Schristos    UINT32                  AccessorType,
801.1.1.4Schristos    UINT32                  AccessLength)
811.1.1.4Schristos{
821.1.1.4Schristos    UINT32                  Length;
831.1.1.4Schristos
841.1.1.4Schristos
851.1.1.4Schristos    switch (AccessorType)
861.1.1.4Schristos    {
871.1.1.4Schristos    case AML_FIELD_ATTRIB_QUICK:
881.1.1.4Schristos
891.1.1.4Schristos        Length = 0;
901.1.1.4Schristos        break;
911.1.1.4Schristos
921.1.1.4Schristos    case AML_FIELD_ATTRIB_SEND_RCV:
931.1.1.4Schristos    case AML_FIELD_ATTRIB_BYTE:
941.1.1.4Schristos
951.1.1.4Schristos        Length = 1;
961.1.1.4Schristos        break;
971.1.1.4Schristos
981.1.1.4Schristos    case AML_FIELD_ATTRIB_WORD:
991.1.1.4Schristos    case AML_FIELD_ATTRIB_WORD_CALL:
1001.1.1.4Schristos
1011.1.1.4Schristos        Length = 2;
1021.1.1.4Schristos        break;
1031.1.1.4Schristos
1041.1.1.4Schristos    case AML_FIELD_ATTRIB_MULTIBYTE:
1051.1.1.4Schristos    case AML_FIELD_ATTRIB_RAW_BYTES:
1061.1.1.4Schristos    case AML_FIELD_ATTRIB_RAW_PROCESS:
1071.1.1.4Schristos
1081.1.1.4Schristos        Length = AccessLength;
1091.1.1.4Schristos        break;
1101.1.1.4Schristos
1111.1.1.4Schristos    case AML_FIELD_ATTRIB_BLOCK:
1121.1.1.4Schristos    case AML_FIELD_ATTRIB_BLOCK_CALL:
1131.1.1.4Schristos    default:
1141.1.1.4Schristos
1151.1.1.4Schristos        Length = ACPI_GSBUS_BUFFER_SIZE - 2;
1161.1.1.4Schristos        break;
1171.1.1.4Schristos    }
1181.1.1.4Schristos
1191.1.1.4Schristos    return (Length);
1201.1.1.4Schristos}
1211.1.1.4Schristos
1221.1Sjruoho
1231.1Sjruoho/*******************************************************************************
1241.1Sjruoho *
1251.1Sjruoho * FUNCTION:    AcpiExReadDataFromField
1261.1Sjruoho *
1271.1Sjruoho * PARAMETERS:  WalkState           - Current execution state
1281.1Sjruoho *              ObjDesc             - The named field
1291.1Sjruoho *              RetBufferDesc       - Where the return data object is stored
1301.1Sjruoho *
1311.1Sjruoho * RETURN:      Status
1321.1Sjruoho *
1331.1.1.3Schristos * DESCRIPTION: Read from a named field. Returns either an Integer or a
1341.1Sjruoho *              Buffer, depending on the size of the field.
1351.1Sjruoho *
1361.1Sjruoho ******************************************************************************/
1371.1Sjruoho
1381.1SjruohoACPI_STATUS
1391.1SjruohoAcpiExReadDataFromField (
1401.1Sjruoho    ACPI_WALK_STATE         *WalkState,
1411.1Sjruoho    ACPI_OPERAND_OBJECT     *ObjDesc,
1421.1Sjruoho    ACPI_OPERAND_OBJECT     **RetBufferDesc)
1431.1Sjruoho{
1441.1Sjruoho    ACPI_STATUS             Status;
1451.1Sjruoho    ACPI_OPERAND_OBJECT     *BufferDesc;
1461.1Sjruoho    ACPI_SIZE               Length;
1471.1Sjruoho    void                    *Buffer;
1481.1Sjruoho    UINT32                  Function;
1491.1.1.4Schristos    UINT16                  AccessorType;
1501.1Sjruoho
1511.1Sjruoho
1521.1Sjruoho    ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
1531.1Sjruoho
1541.1Sjruoho
1551.1Sjruoho    /* Parameter validation */
1561.1Sjruoho
1571.1Sjruoho    if (!ObjDesc)
1581.1Sjruoho    {
1591.1Sjruoho        return_ACPI_STATUS (AE_AML_NO_OPERAND);
1601.1Sjruoho    }
1611.1Sjruoho    if (!RetBufferDesc)
1621.1Sjruoho    {
1631.1Sjruoho        return_ACPI_STATUS (AE_BAD_PARAMETER);
1641.1Sjruoho    }
1651.1Sjruoho
1661.1Sjruoho    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
1671.1Sjruoho    {
1681.1Sjruoho        /*
1691.1Sjruoho         * If the BufferField arguments have not been previously evaluated,
1701.1Sjruoho         * evaluate them now and save the results.
1711.1Sjruoho         */
1721.1Sjruoho        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
1731.1Sjruoho        {
1741.1Sjruoho            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
1751.1Sjruoho            if (ACPI_FAILURE (Status))
1761.1Sjruoho            {
1771.1Sjruoho                return_ACPI_STATUS (Status);
1781.1Sjruoho            }
1791.1Sjruoho        }
1801.1Sjruoho    }
1811.1Sjruoho    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
1821.1Sjruoho             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
1831.1.1.3Schristos              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
1841.1Sjruoho              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
1851.1Sjruoho    {
1861.1Sjruoho        /*
1871.1.1.4.2.3Sskrll         * This is an SMBus, GSBus or IPMI read. We must create a buffer to
1881.1.1.4.2.3Sskrll         * hold the data and then directly access the region handler.
1891.1Sjruoho         *
1901.1.1.4.2.3Sskrll         * Note: SMBus and GSBus protocol value is passed in upper 16-bits
1911.1.1.4.2.3Sskrll         * of Function
1921.1Sjruoho         */
1931.1.1.4.2.3Sskrll        if (ObjDesc->Field.RegionObj->Region.SpaceId ==
1941.1.1.4.2.3Sskrll            ACPI_ADR_SPACE_SMBUS)
1951.1Sjruoho        {
1961.1Sjruoho            Length = ACPI_SMBUS_BUFFER_SIZE;
1971.1Sjruoho            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
1981.1Sjruoho        }
1991.1.1.4.2.3Sskrll        else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
2001.1.1.4.2.3Sskrll            ACPI_ADR_SPACE_GSBUS)
2011.1.1.3Schristos        {
2021.1.1.4Schristos            AccessorType = ObjDesc->Field.Attribute;
2031.1.1.4.2.3Sskrll            Length = AcpiExGetSerialAccessLength (
2041.1.1.4.2.3Sskrll                AccessorType, ObjDesc->Field.AccessLength);
2051.1.1.4Schristos
2061.1.1.4Schristos            /*
2071.1.1.4Schristos             * Add additional 2 bytes for the GenericSerialBus data buffer:
2081.1.1.4Schristos             *
2091.1.1.4.2.3Sskrll             *     Status;    (Byte 0 of the data buffer)
2101.1.1.4.2.3Sskrll             *     Length;    (Byte 1 of the data buffer)
2111.1.1.4.2.3Sskrll             *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
2121.1.1.4Schristos             */
2131.1.1.4Schristos            Length += 2;
2141.1.1.4Schristos            Function = ACPI_READ | (AccessorType << 16);
2151.1.1.3Schristos        }
2161.1Sjruoho        else /* IPMI */
2171.1Sjruoho        {
2181.1Sjruoho            Length = ACPI_IPMI_BUFFER_SIZE;
2191.1Sjruoho            Function = ACPI_READ;
2201.1Sjruoho        }
2211.1Sjruoho
2221.1Sjruoho        BufferDesc = AcpiUtCreateBufferObject (Length);
2231.1Sjruoho        if (!BufferDesc)
2241.1Sjruoho        {
2251.1Sjruoho            return_ACPI_STATUS (AE_NO_MEMORY);
2261.1Sjruoho        }
2271.1Sjruoho
2281.1Sjruoho        /* Lock entire transaction if requested */
2291.1Sjruoho
2301.1Sjruoho        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
2311.1Sjruoho
2321.1Sjruoho        /* Call the region handler for the read */
2331.1Sjruoho
2341.1Sjruoho        Status = AcpiExAccessRegion (ObjDesc, 0,
2351.1.1.4.2.3Sskrll            ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
2361.1.1.4.2.3Sskrll
2371.1Sjruoho        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
2381.1Sjruoho        goto Exit;
2391.1Sjruoho    }
2401.1Sjruoho
2411.1Sjruoho    /*
2421.1Sjruoho     * Allocate a buffer for the contents of the field.
2431.1Sjruoho     *
2441.1Sjruoho     * If the field is larger than the current integer width, create
2451.1.1.3Schristos     * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
2461.1Sjruoho     * the use of arithmetic operators on the returned value if the
2471.1Sjruoho     * field size is equal or smaller than an Integer.
2481.1Sjruoho     *
2491.1Sjruoho     * Note: Field.length is in bits.
2501.1Sjruoho     */
2511.1.1.4.2.3Sskrll    Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (
2521.1.1.4.2.3Sskrll        ObjDesc->Field.BitLength);
2531.1.1.4.2.3Sskrll
2541.1Sjruoho    if (Length > AcpiGbl_IntegerByteWidth)
2551.1Sjruoho    {
2561.1Sjruoho        /* Field is too large for an Integer, create a Buffer instead */
2571.1Sjruoho
2581.1Sjruoho        BufferDesc = AcpiUtCreateBufferObject (Length);
2591.1Sjruoho        if (!BufferDesc)
2601.1Sjruoho        {
2611.1Sjruoho            return_ACPI_STATUS (AE_NO_MEMORY);
2621.1Sjruoho        }
2631.1Sjruoho        Buffer = BufferDesc->Buffer.Pointer;
2641.1Sjruoho    }
2651.1Sjruoho    else
2661.1Sjruoho    {
2671.1Sjruoho        /* Field will fit within an Integer (normal case) */
2681.1Sjruoho
2691.1Sjruoho        BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
2701.1Sjruoho        if (!BufferDesc)
2711.1Sjruoho        {
2721.1Sjruoho            return_ACPI_STATUS (AE_NO_MEMORY);
2731.1Sjruoho        }
2741.1Sjruoho
2751.1Sjruoho        Length = AcpiGbl_IntegerByteWidth;
2761.1Sjruoho        Buffer = &BufferDesc->Integer.Value;
2771.1Sjruoho    }
2781.1Sjruoho
2791.1.1.4Schristos    if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
2801.1.1.4Schristos        (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
2811.1.1.4Schristos    {
2821.1.1.4Schristos        /*
2831.1.1.4Schristos         * For GPIO (GeneralPurposeIo), the Address will be the bit offset
2841.1.1.4Schristos         * from the previous Connection() operator, making it effectively a
2851.1.1.4Schristos         * pin number index. The BitLength is the length of the field, which
2861.1.1.4Schristos         * is thus the number of pins.
2871.1.1.4Schristos         */
2881.1.1.4Schristos        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
2891.1.1.4Schristos            "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
2901.1.1.4Schristos            ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
2911.1.1.4Schristos
2921.1.1.4Schristos        /* Lock entire transaction if requested */
2931.1.1.4Schristos
2941.1.1.4Schristos        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
2951.1.1.4Schristos
2961.1.1.4Schristos        /* Perform the write */
2971.1.1.4Schristos
2981.1.1.4.2.3Sskrll        Status = AcpiExAccessRegion (
2991.1.1.4.2.3Sskrll            ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ);
3001.1.1.4.2.3Sskrll
3011.1.1.4Schristos        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
3021.1.1.4Schristos        if (ACPI_FAILURE (Status))
3031.1.1.4Schristos        {
3041.1.1.4Schristos            AcpiUtRemoveReference (BufferDesc);
3051.1.1.4Schristos        }
3061.1.1.4Schristos        else
3071.1.1.4Schristos        {
3081.1.1.4Schristos            *RetBufferDesc = BufferDesc;
3091.1.1.4Schristos        }
3101.1.1.4Schristos        return_ACPI_STATUS (Status);
3111.1.1.4Schristos    }
3121.1.1.4Schristos
3131.1Sjruoho    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
3141.1Sjruoho        "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
3151.1Sjruoho        ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
3161.1Sjruoho    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
3171.1Sjruoho        "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
3181.1Sjruoho        ObjDesc->CommonField.BitLength,
3191.1Sjruoho        ObjDesc->CommonField.StartFieldBitOffset,
3201.1Sjruoho        ObjDesc->CommonField.BaseByteOffset));
3211.1Sjruoho
3221.1Sjruoho    /* Lock entire transaction if requested */
3231.1Sjruoho
3241.1Sjruoho    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
3251.1Sjruoho
3261.1Sjruoho    /* Read from the field */
3271.1Sjruoho
3281.1Sjruoho    Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
3291.1Sjruoho    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
3301.1Sjruoho
3311.1Sjruoho
3321.1SjruohoExit:
3331.1Sjruoho    if (ACPI_FAILURE (Status))
3341.1Sjruoho    {
3351.1Sjruoho        AcpiUtRemoveReference (BufferDesc);
3361.1Sjruoho    }
3371.1Sjruoho    else
3381.1Sjruoho    {
3391.1Sjruoho        *RetBufferDesc = BufferDesc;
3401.1Sjruoho    }
3411.1Sjruoho
3421.1Sjruoho    return_ACPI_STATUS (Status);
3431.1Sjruoho}
3441.1Sjruoho
3451.1Sjruoho
3461.1Sjruoho/*******************************************************************************
3471.1Sjruoho *
3481.1Sjruoho * FUNCTION:    AcpiExWriteDataToField
3491.1Sjruoho *
3501.1Sjruoho * PARAMETERS:  SourceDesc          - Contains data to write
3511.1Sjruoho *              ObjDesc             - The named field
3521.1Sjruoho *              ResultDesc          - Where the return value is returned, if any
3531.1Sjruoho *
3541.1Sjruoho * RETURN:      Status
3551.1Sjruoho *
3561.1Sjruoho * DESCRIPTION: Write to a named field
3571.1Sjruoho *
3581.1Sjruoho ******************************************************************************/
3591.1Sjruoho
3601.1SjruohoACPI_STATUS
3611.1SjruohoAcpiExWriteDataToField (
3621.1Sjruoho    ACPI_OPERAND_OBJECT     *SourceDesc,
3631.1Sjruoho    ACPI_OPERAND_OBJECT     *ObjDesc,
3641.1Sjruoho    ACPI_OPERAND_OBJECT     **ResultDesc)
3651.1Sjruoho{
3661.1Sjruoho    ACPI_STATUS             Status;
3671.1Sjruoho    UINT32                  Length;
3681.1Sjruoho    void                    *Buffer;
3691.1Sjruoho    ACPI_OPERAND_OBJECT     *BufferDesc;
3701.1Sjruoho    UINT32                  Function;
3711.1.1.4Schristos    UINT16                  AccessorType;
3721.1Sjruoho
3731.1Sjruoho
3741.1Sjruoho    ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
3751.1Sjruoho
3761.1Sjruoho
3771.1Sjruoho    /* Parameter validation */
3781.1Sjruoho
3791.1Sjruoho    if (!SourceDesc || !ObjDesc)
3801.1Sjruoho    {
3811.1Sjruoho        return_ACPI_STATUS (AE_AML_NO_OPERAND);
3821.1Sjruoho    }
3831.1Sjruoho
3841.1Sjruoho    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
3851.1Sjruoho    {
3861.1Sjruoho        /*
3871.1Sjruoho         * If the BufferField arguments have not been previously evaluated,
3881.1Sjruoho         * evaluate them now and save the results.
3891.1Sjruoho         */
3901.1Sjruoho        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
3911.1Sjruoho        {
3921.1Sjruoho            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
3931.1Sjruoho            if (ACPI_FAILURE (Status))
3941.1Sjruoho            {
3951.1Sjruoho                return_ACPI_STATUS (Status);
3961.1Sjruoho            }
3971.1Sjruoho        }
3981.1Sjruoho    }
3991.1Sjruoho    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
4001.1Sjruoho             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
4011.1.1.3Schristos              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
4021.1Sjruoho              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
4031.1Sjruoho    {
4041.1Sjruoho        /*
4051.1.1.4.2.3Sskrll         * This is an SMBus, GSBus or IPMI write. We will bypass the entire
4061.1.1.4.2.3Sskrll         * field mechanism and handoff the buffer directly to the handler.
4071.1.1.4.2.3Sskrll         * For these address spaces, the buffer is bi-directional; on a
4081.1.1.4.2.3Sskrll         * write, return data is returned in the same buffer.
4091.1Sjruoho         *
4101.1Sjruoho         * Source must be a buffer of sufficient size:
4111.1.1.4.2.3Sskrll         * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
4121.1.1.4.2.3Sskrll         * ACPI_IPMI_BUFFER_SIZE.
4131.1Sjruoho         *
4141.1.1.4.2.3Sskrll         * Note: SMBus and GSBus protocol type is passed in upper 16-bits
4151.1.1.4.2.3Sskrll         * of Function
4161.1Sjruoho         */
4171.1Sjruoho        if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
4181.1Sjruoho        {
4191.1Sjruoho            ACPI_ERROR ((AE_INFO,
4201.1.1.4.2.3Sskrll                "SMBus/IPMI/GenericSerialBus write requires "
4211.1.1.4.2.3Sskrll                "Buffer, found type %s",
4221.1Sjruoho                AcpiUtGetObjectTypeName (SourceDesc)));
4231.1Sjruoho
4241.1Sjruoho            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
4251.1Sjruoho        }
4261.1Sjruoho
4271.1.1.4.2.3Sskrll        if (ObjDesc->Field.RegionObj->Region.SpaceId ==
4281.1.1.4.2.3Sskrll            ACPI_ADR_SPACE_SMBUS)
4291.1Sjruoho        {
4301.1Sjruoho            Length = ACPI_SMBUS_BUFFER_SIZE;
4311.1Sjruoho            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
4321.1Sjruoho        }
4331.1.1.4.2.3Sskrll        else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
4341.1.1.4.2.3Sskrll            ACPI_ADR_SPACE_GSBUS)
4351.1.1.3Schristos        {
4361.1.1.4Schristos            AccessorType = ObjDesc->Field.Attribute;
4371.1.1.4.2.3Sskrll            Length = AcpiExGetSerialAccessLength (
4381.1.1.4.2.3Sskrll                AccessorType, ObjDesc->Field.AccessLength);
4391.1.1.4Schristos
4401.1.1.4Schristos            /*
4411.1.1.4Schristos             * Add additional 2 bytes for the GenericSerialBus data buffer:
4421.1.1.4Schristos             *
4431.1.1.4.2.3Sskrll             *     Status;    (Byte 0 of the data buffer)
4441.1.1.4.2.3Sskrll             *     Length;    (Byte 1 of the data buffer)
4451.1.1.4.2.3Sskrll             *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
4461.1.1.4Schristos             */
4471.1.1.4Schristos            Length += 2;
4481.1.1.4Schristos            Function = ACPI_WRITE | (AccessorType << 16);
4491.1.1.3Schristos        }
4501.1Sjruoho        else /* IPMI */
4511.1Sjruoho        {
4521.1Sjruoho            Length = ACPI_IPMI_BUFFER_SIZE;
4531.1Sjruoho            Function = ACPI_WRITE;
4541.1Sjruoho        }
4551.1Sjruoho
4561.1Sjruoho        if (SourceDesc->Buffer.Length < Length)
4571.1Sjruoho        {
4581.1Sjruoho            ACPI_ERROR ((AE_INFO,
4591.1.1.4.2.3Sskrll                "SMBus/IPMI/GenericSerialBus write requires "
4601.1.1.4.2.3Sskrll                "Buffer of length %u, found length %u",
4611.1Sjruoho                Length, SourceDesc->Buffer.Length));
4621.1Sjruoho
4631.1Sjruoho            return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
4641.1Sjruoho        }
4651.1Sjruoho
4661.1Sjruoho        /* Create the bi-directional buffer */
4671.1Sjruoho
4681.1Sjruoho        BufferDesc = AcpiUtCreateBufferObject (Length);
4691.1Sjruoho        if (!BufferDesc)
4701.1Sjruoho        {
4711.1Sjruoho            return_ACPI_STATUS (AE_NO_MEMORY);
4721.1Sjruoho        }
4731.1Sjruoho
4741.1Sjruoho        Buffer = BufferDesc->Buffer.Pointer;
4751.1.1.4.2.2Sskrll        memcpy (Buffer, SourceDesc->Buffer.Pointer, Length);
4761.1Sjruoho
4771.1Sjruoho        /* Lock entire transaction if requested */
4781.1Sjruoho
4791.1Sjruoho        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
4801.1Sjruoho
4811.1Sjruoho        /*
4821.1Sjruoho         * Perform the write (returns status and perhaps data in the
4831.1Sjruoho         * same buffer)
4841.1Sjruoho         */
4851.1.1.4.2.3Sskrll        Status = AcpiExAccessRegion (
4861.1.1.4.2.3Sskrll            ObjDesc, 0, (UINT64 *) Buffer, Function);
4871.1Sjruoho        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
4881.1Sjruoho
4891.1Sjruoho        *ResultDesc = BufferDesc;
4901.1Sjruoho        return_ACPI_STATUS (Status);
4911.1Sjruoho    }
4921.1.1.4Schristos    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
4931.1.1.4Schristos             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
4941.1.1.4Schristos    {
4951.1.1.4Schristos        /*
4961.1.1.4Schristos         * For GPIO (GeneralPurposeIo), we will bypass the entire field
4971.1.1.4Schristos         * mechanism and handoff the bit address and bit width directly to
4981.1.1.4Schristos         * the handler. The Address will be the bit offset
4991.1.1.4Schristos         * from the previous Connection() operator, making it effectively a
5001.1.1.4Schristos         * pin number index. The BitLength is the length of the field, which
5011.1.1.4Schristos         * is thus the number of pins.
5021.1.1.4Schristos         */
5031.1.1.4Schristos        if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
5041.1.1.4Schristos        {
5051.1.1.4Schristos            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
5061.1.1.4Schristos        }
5071.1.1.4Schristos
5081.1.1.4Schristos        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
5091.1.1.4.2.3Sskrll            "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]: Pin %u Bits %u\n",
5101.1.1.4Schristos            AcpiUtGetTypeName (SourceDesc->Common.Type),
5111.1.1.4Schristos            SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
5121.1.1.4Schristos            ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
5131.1.1.4Schristos
5141.1.1.4Schristos        Buffer = &SourceDesc->Integer.Value;
5151.1.1.4Schristos
5161.1.1.4Schristos        /* Lock entire transaction if requested */
5171.1.1.4Schristos
5181.1.1.4Schristos        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
5191.1.1.4Schristos
5201.1.1.4Schristos        /* Perform the write */
5211.1.1.4Schristos
5221.1.1.4.2.3Sskrll        Status = AcpiExAccessRegion (
5231.1.1.4.2.3Sskrll            ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
5241.1.1.4Schristos        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
5251.1.1.4Schristos        return_ACPI_STATUS (Status);
5261.1.1.4Schristos    }
5271.1Sjruoho
5281.1Sjruoho    /* Get a pointer to the data to be written */
5291.1Sjruoho
5301.1Sjruoho    switch (SourceDesc->Common.Type)
5311.1Sjruoho    {
5321.1Sjruoho    case ACPI_TYPE_INTEGER:
5331.1.1.3Schristos
5341.1Sjruoho        Buffer = &SourceDesc->Integer.Value;
5351.1Sjruoho        Length = sizeof (SourceDesc->Integer.Value);
5361.1Sjruoho        break;
5371.1Sjruoho
5381.1Sjruoho    case ACPI_TYPE_BUFFER:
5391.1.1.3Schristos
5401.1Sjruoho        Buffer = SourceDesc->Buffer.Pointer;
5411.1Sjruoho        Length = SourceDesc->Buffer.Length;
5421.1Sjruoho        break;
5431.1Sjruoho
5441.1Sjruoho    case ACPI_TYPE_STRING:
5451.1.1.3Schristos
5461.1Sjruoho        Buffer = SourceDesc->String.Pointer;
5471.1Sjruoho        Length = SourceDesc->String.Length;
5481.1Sjruoho        break;
5491.1Sjruoho
5501.1Sjruoho    default:
5511.1.1.3Schristos
5521.1Sjruoho        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
5531.1Sjruoho    }
5541.1Sjruoho
5551.1Sjruoho    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
5561.1Sjruoho        "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
5571.1Sjruoho        SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
5581.1Sjruoho        SourceDesc->Common.Type, Buffer, Length));
5591.1Sjruoho
5601.1Sjruoho    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
5611.1Sjruoho        "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
5621.1Sjruoho        ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
5631.1Sjruoho        ObjDesc->Common.Type,
5641.1Sjruoho        ObjDesc->CommonField.BitLength,
5651.1Sjruoho        ObjDesc->CommonField.StartFieldBitOffset,
5661.1Sjruoho        ObjDesc->CommonField.BaseByteOffset));
5671.1Sjruoho
5681.1Sjruoho    /* Lock entire transaction if requested */
5691.1Sjruoho
5701.1Sjruoho    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
5711.1Sjruoho
5721.1Sjruoho    /* Write to the field */
5731.1Sjruoho
5741.1Sjruoho    Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
5751.1Sjruoho    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
5761.1Sjruoho
5771.1Sjruoho    return_ACPI_STATUS (Status);
5781.1Sjruoho}
579