167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8281075Sdim * Copyright (C) 2000 - 2015, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46193341Sjkim#include <contrib/dev/acpica/include/acdispat.h>
47193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
48281075Sdim#include <contrib/dev/acpica/include/amlcode.h>
4967754Smsmith
5067754Smsmith
5177424Smsmith#define _COMPONENT          ACPI_EXECUTER
5291116Smsmith        ACPI_MODULE_NAME    ("exfield")
5367754Smsmith
54281075Sdim/* Local prototypes */
5567754Smsmith
56281075Sdimstatic UINT32
57281075SdimAcpiExGetSerialAccessLength (
58281075Sdim    UINT32                  AccessorType,
59281075Sdim    UINT32                  AccessLength);
60281075Sdim
61281075Sdim
6267754Smsmith/*******************************************************************************
6367754Smsmith *
64281075Sdim * FUNCTION:    AcpiExGetSerialAccessLength
65281075Sdim *
66281075Sdim * PARAMETERS:  AccessorType    - The type of the protocol indicated by region
67281075Sdim *                                field access attributes
68281075Sdim *              AccessLength    - The access length of the region field
69281075Sdim *
70281075Sdim * RETURN:      Decoded access length
71281075Sdim *
72281075Sdim * DESCRIPTION: This routine returns the length of the GenericSerialBus
73281075Sdim *              protocol bytes
74281075Sdim *
75281075Sdim ******************************************************************************/
76281075Sdim
77281075Sdimstatic UINT32
78281075SdimAcpiExGetSerialAccessLength (
79281075Sdim    UINT32                  AccessorType,
80281075Sdim    UINT32                  AccessLength)
81281075Sdim{
82281075Sdim    UINT32                  Length;
83281075Sdim
84281075Sdim
85281075Sdim    switch (AccessorType)
86281075Sdim    {
87281075Sdim    case AML_FIELD_ATTRIB_QUICK:
88281075Sdim
89281075Sdim        Length = 0;
90281075Sdim        break;
91281075Sdim
92281075Sdim    case AML_FIELD_ATTRIB_SEND_RCV:
93281075Sdim    case AML_FIELD_ATTRIB_BYTE:
94281075Sdim
95281075Sdim        Length = 1;
96281075Sdim        break;
97281075Sdim
98281075Sdim    case AML_FIELD_ATTRIB_WORD:
99281075Sdim    case AML_FIELD_ATTRIB_WORD_CALL:
100281075Sdim
101281075Sdim        Length = 2;
102281075Sdim        break;
103281075Sdim
104281075Sdim    case AML_FIELD_ATTRIB_MULTIBYTE:
105281075Sdim    case AML_FIELD_ATTRIB_RAW_BYTES:
106281075Sdim    case AML_FIELD_ATTRIB_RAW_PROCESS:
107281075Sdim
108281075Sdim        Length = AccessLength;
109281075Sdim        break;
110281075Sdim
111281075Sdim    case AML_FIELD_ATTRIB_BLOCK:
112281075Sdim    case AML_FIELD_ATTRIB_BLOCK_CALL:
113281075Sdim    default:
114281075Sdim
115281075Sdim        Length = ACPI_GSBUS_BUFFER_SIZE - 2;
116281075Sdim        break;
117281075Sdim    }
118281075Sdim
119281075Sdim    return (Length);
120281075Sdim}
121281075Sdim
122281075Sdim
123281075Sdim/*******************************************************************************
124281075Sdim *
12577424Smsmith * FUNCTION:    AcpiExReadDataFromField
12667754Smsmith *
12799146Siwasaki * PARAMETERS:  WalkState           - Current execution state
12899146Siwasaki *              ObjDesc             - The named field
12987031Smsmith *              RetBufferDesc       - Where the return data object is stored
13067754Smsmith *
13187031Smsmith * RETURN:      Status
13267754Smsmith *
133241973Sjkim * DESCRIPTION: Read from a named field. Returns either an Integer or a
13487031Smsmith *              Buffer, depending on the size of the field.
13567754Smsmith *
13667754Smsmith ******************************************************************************/
13767754Smsmith
13867754SmsmithACPI_STATUS
13977424SmsmithAcpiExReadDataFromField (
14099146Siwasaki    ACPI_WALK_STATE         *WalkState,
14167754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
14277424Smsmith    ACPI_OPERAND_OBJECT     **RetBufferDesc)
14367754Smsmith{
14477424Smsmith    ACPI_STATUS             Status;
14577424Smsmith    ACPI_OPERAND_OBJECT     *BufferDesc;
146114237Snjl    ACPI_SIZE               Length;
14777424Smsmith    void                    *Buffer;
148197104Sjkim    UINT32                  Function;
149281075Sdim    UINT16                  AccessorType;
15067754Smsmith
15167754Smsmith
152167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
15367754Smsmith
15467754Smsmith
15567754Smsmith    /* Parameter validation */
15667754Smsmith
15777424Smsmith    if (!ObjDesc)
15867754Smsmith    {
15967754Smsmith        return_ACPI_STATUS (AE_AML_NO_OPERAND);
16067754Smsmith    }
161151937Sjkim    if (!RetBufferDesc)
162151937Sjkim    {
163151937Sjkim        return_ACPI_STATUS (AE_BAD_PARAMETER);
164151937Sjkim    }
16567754Smsmith
166193267Sjkim    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
16787031Smsmith    {
16887031Smsmith        /*
16987031Smsmith         * If the BufferField arguments have not been previously evaluated,
17087031Smsmith         * evaluate them now and save the results.
17187031Smsmith         */
17287031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
17387031Smsmith        {
17487031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
17587031Smsmith            if (ACPI_FAILURE (Status))
17687031Smsmith            {
17787031Smsmith                return_ACPI_STATUS (Status);
17887031Smsmith            }
17987031Smsmith        }
18087031Smsmith    }
181193267Sjkim    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
182197104Sjkim             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
183228110Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
184197104Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
185107325Siwasaki    {
186107325Siwasaki        /*
187228110Sjkim         * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
188197104Sjkim         * the data and then directly access the region handler.
189197104Sjkim         *
190228110Sjkim         * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
191107325Siwasaki         */
192197104Sjkim        if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
193197104Sjkim        {
194197104Sjkim            Length = ACPI_SMBUS_BUFFER_SIZE;
195197104Sjkim            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
196197104Sjkim        }
197228110Sjkim        else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
198228110Sjkim        {
199281075Sdim            AccessorType = ObjDesc->Field.Attribute;
200281075Sdim            Length = AcpiExGetSerialAccessLength (AccessorType,
201281075Sdim                ObjDesc->Field.AccessLength);
202281075Sdim
203281075Sdim            /*
204281075Sdim             * Add additional 2 bytes for the GenericSerialBus data buffer:
205281075Sdim             *
206281075Sdim             *     Status;      (Byte 0 of the data buffer)
207281075Sdim             *     Length;      (Byte 1 of the data buffer)
208281075Sdim             *     Data[x-1];   (Bytes 2-x of the arbitrary length data buffer)
209281075Sdim             */
210281075Sdim            Length += 2;
211281075Sdim            Function = ACPI_READ | (AccessorType << 16);
212228110Sjkim        }
213197104Sjkim        else /* IPMI */
214197104Sjkim        {
215197104Sjkim            Length = ACPI_IPMI_BUFFER_SIZE;
216197104Sjkim            Function = ACPI_READ;
217197104Sjkim        }
218197104Sjkim
219197104Sjkim        BufferDesc = AcpiUtCreateBufferObject (Length);
220107325Siwasaki        if (!BufferDesc)
221107325Siwasaki        {
222107325Siwasaki            return_ACPI_STATUS (AE_NO_MEMORY);
223107325Siwasaki        }
22487031Smsmith
225107325Siwasaki        /* Lock entire transaction if requested */
226107325Siwasaki
227167802Sjkim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
228107325Siwasaki
229197104Sjkim        /* Call the region handler for the read */
230197104Sjkim
231114237Snjl        Status = AcpiExAccessRegion (ObjDesc, 0,
232202771Sjkim                    ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
233197104Sjkim                    Function);
234167802Sjkim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
235107325Siwasaki        goto Exit;
236107325Siwasaki    }
237107325Siwasaki
23867754Smsmith    /*
23977424Smsmith     * Allocate a buffer for the contents of the field.
24067754Smsmith     *
241202771Sjkim     * If the field is larger than the current integer width, create
242241973Sjkim     * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
24377424Smsmith     * the use of arithmetic operators on the returned value if the
24477424Smsmith     * field size is equal or smaller than an Integer.
24577424Smsmith     *
24677424Smsmith     * Note: Field.length is in bits.
24767754Smsmith     */
248114237Snjl    Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
24999679Siwasaki    if (Length > AcpiGbl_IntegerByteWidth)
25067754Smsmith    {
25177424Smsmith        /* Field is too large for an Integer, create a Buffer instead */
25267754Smsmith
253107325Siwasaki        BufferDesc = AcpiUtCreateBufferObject (Length);
25477424Smsmith        if (!BufferDesc)
25577424Smsmith        {
25677424Smsmith            return_ACPI_STATUS (AE_NO_MEMORY);
25777424Smsmith        }
25877424Smsmith        Buffer = BufferDesc->Buffer.Pointer;
25967754Smsmith    }
26077424Smsmith    else
26177424Smsmith    {
26277424Smsmith        /* Field will fit within an Integer (normal case) */
26367754Smsmith
264199337Sjkim        BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
26577424Smsmith        if (!BufferDesc)
26677424Smsmith        {
26777424Smsmith            return_ACPI_STATUS (AE_NO_MEMORY);
26877424Smsmith        }
26977424Smsmith
27099679Siwasaki        Length = AcpiGbl_IntegerByteWidth;
27177424Smsmith        Buffer = &BufferDesc->Integer.Value;
27267754Smsmith    }
27367754Smsmith
274281075Sdim    if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
275281075Sdim        (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
276281075Sdim    {
277281075Sdim        /*
278281075Sdim         * For GPIO (GeneralPurposeIo), the Address will be the bit offset
279281075Sdim         * from the previous Connection() operator, making it effectively a
280281075Sdim         * pin number index. The BitLength is the length of the field, which
281281075Sdim         * is thus the number of pins.
282281075Sdim         */
283281075Sdim        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
284281075Sdim            "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
285281075Sdim            ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
286281075Sdim
287281075Sdim        /* Lock entire transaction if requested */
288281075Sdim
289281075Sdim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
290281075Sdim
291281075Sdim        /* Perform the write */
292281075Sdim
293281075Sdim        Status = AcpiExAccessRegion (ObjDesc, 0,
294281075Sdim                    (UINT64 *) Buffer, ACPI_READ);
295281075Sdim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
296281075Sdim        if (ACPI_FAILURE (Status))
297281075Sdim        {
298281075Sdim            AcpiUtRemoveReference (BufferDesc);
299281075Sdim        }
300281075Sdim        else
301281075Sdim        {
302281075Sdim            *RetBufferDesc = BufferDesc;
303281075Sdim        }
304281075Sdim        return_ACPI_STATUS (Status);
305281075Sdim    }
306281075Sdim
30799146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
308123315Snjl        "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
309193267Sjkim        ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
31099146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
311123315Snjl        "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
31287031Smsmith        ObjDesc->CommonField.BitLength,
31387031Smsmith        ObjDesc->CommonField.StartFieldBitOffset,
31487031Smsmith        ObjDesc->CommonField.BaseByteOffset));
31577424Smsmith
316107325Siwasaki    /* Lock entire transaction if requested */
317107325Siwasaki
318167802Sjkim    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
31977424Smsmith
32087031Smsmith    /* Read from the field */
32167754Smsmith
322114237Snjl    Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
323167802Sjkim    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
32467754Smsmith
325107325Siwasaki
326107325SiwasakiExit:
32777424Smsmith    if (ACPI_FAILURE (Status))
32877424Smsmith    {
32977424Smsmith        AcpiUtRemoveReference (BufferDesc);
33077424Smsmith    }
331151937Sjkim    else
33277424Smsmith    {
33377424Smsmith        *RetBufferDesc = BufferDesc;
33477424Smsmith    }
33577424Smsmith
33677424Smsmith    return_ACPI_STATUS (Status);
33767754Smsmith}
33867754Smsmith
33967754Smsmith
34067754Smsmith/*******************************************************************************
34167754Smsmith *
34277424Smsmith * FUNCTION:    AcpiExWriteDataToField
34367754Smsmith *
34487031Smsmith * PARAMETERS:  SourceDesc          - Contains data to write
34587031Smsmith *              ObjDesc             - The named field
346151937Sjkim *              ResultDesc          - Where the return value is returned, if any
34767754Smsmith *
34867754Smsmith * RETURN:      Status
34967754Smsmith *
35087031Smsmith * DESCRIPTION: Write to a named field
35167754Smsmith *
35267754Smsmith ******************************************************************************/
35367754Smsmith
35467754SmsmithACPI_STATUS
35577424SmsmithAcpiExWriteDataToField (
35677424Smsmith    ACPI_OPERAND_OBJECT     *SourceDesc,
357107325Siwasaki    ACPI_OPERAND_OBJECT     *ObjDesc,
358107325Siwasaki    ACPI_OPERAND_OBJECT     **ResultDesc)
35967754Smsmith{
36077424Smsmith    ACPI_STATUS             Status;
36177424Smsmith    UINT32                  Length;
36277424Smsmith    void                    *Buffer;
363107325Siwasaki    ACPI_OPERAND_OBJECT     *BufferDesc;
364197104Sjkim    UINT32                  Function;
365281075Sdim    UINT16                  AccessorType;
36667754Smsmith
36767754Smsmith
368167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
36967754Smsmith
37067754Smsmith
37171867Smsmith    /* Parameter validation */
37271867Smsmith
37377424Smsmith    if (!SourceDesc || !ObjDesc)
37467754Smsmith    {
37577424Smsmith        return_ACPI_STATUS (AE_AML_NO_OPERAND);
37667754Smsmith    }
37767754Smsmith
378193267Sjkim    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
37987031Smsmith    {
38087031Smsmith        /*
38187031Smsmith         * If the BufferField arguments have not been previously evaluated,
38287031Smsmith         * evaluate them now and save the results.
38387031Smsmith         */
38487031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
38587031Smsmith        {
38687031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
38787031Smsmith            if (ACPI_FAILURE (Status))
38887031Smsmith            {
38987031Smsmith                return_ACPI_STATUS (Status);
39087031Smsmith            }
39187031Smsmith        }
39287031Smsmith    }
393193267Sjkim    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
394197104Sjkim             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
395228110Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
396197104Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
397107325Siwasaki    {
398107325Siwasaki        /*
399228110Sjkim         * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
400197104Sjkim         * mechanism and handoff the buffer directly to the handler. For
401197104Sjkim         * these address spaces, the buffer is bi-directional; on a write,
402197104Sjkim         * return data is returned in the same buffer.
403107325Siwasaki         *
404197104Sjkim         * Source must be a buffer of sufficient size:
405228110Sjkim         * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
406197104Sjkim         *
407228110Sjkim         * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
408107325Siwasaki         */
409193267Sjkim        if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
410107325Siwasaki        {
411197104Sjkim            ACPI_ERROR ((AE_INFO,
412228110Sjkim                "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
413107325Siwasaki                AcpiUtGetObjectTypeName (SourceDesc)));
414151937Sjkim
415107325Siwasaki            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
416107325Siwasaki        }
41767754Smsmith
418197104Sjkim        if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
419107325Siwasaki        {
420197104Sjkim            Length = ACPI_SMBUS_BUFFER_SIZE;
421197104Sjkim            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
422197104Sjkim        }
423228110Sjkim        else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
424228110Sjkim        {
425281075Sdim            AccessorType = ObjDesc->Field.Attribute;
426281075Sdim            Length = AcpiExGetSerialAccessLength (AccessorType,
427281075Sdim                ObjDesc->Field.AccessLength);
428281075Sdim
429281075Sdim            /*
430281075Sdim             * Add additional 2 bytes for the GenericSerialBus data buffer:
431281075Sdim             *
432281075Sdim             *     Status;      (Byte 0 of the data buffer)
433281075Sdim             *     Length;      (Byte 1 of the data buffer)
434281075Sdim             *     Data[x-1];   (Bytes 2-x of the arbitrary length data buffer)
435281075Sdim             */
436281075Sdim            Length += 2;
437281075Sdim            Function = ACPI_WRITE | (AccessorType << 16);
438228110Sjkim        }
439197104Sjkim        else /* IPMI */
440197104Sjkim        {
441197104Sjkim            Length = ACPI_IPMI_BUFFER_SIZE;
442197104Sjkim            Function = ACPI_WRITE;
443197104Sjkim        }
444197104Sjkim
445197104Sjkim        if (SourceDesc->Buffer.Length < Length)
446197104Sjkim        {
447167802Sjkim            ACPI_ERROR ((AE_INFO,
448228110Sjkim                "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
449197104Sjkim                Length, SourceDesc->Buffer.Length));
450151937Sjkim
451107325Siwasaki            return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
452107325Siwasaki        }
453107325Siwasaki
454197104Sjkim        /* Create the bi-directional buffer */
455197104Sjkim
456197104Sjkim        BufferDesc = AcpiUtCreateBufferObject (Length);
457107325Siwasaki        if (!BufferDesc)
458107325Siwasaki        {
459107325Siwasaki            return_ACPI_STATUS (AE_NO_MEMORY);
460107325Siwasaki        }
461107325Siwasaki
462107325Siwasaki        Buffer = BufferDesc->Buffer.Pointer;
463197104Sjkim        ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);
464107325Siwasaki
465107325Siwasaki        /* Lock entire transaction if requested */
466107325Siwasaki
467167802Sjkim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
468107325Siwasaki
469114237Snjl        /*
470151937Sjkim         * Perform the write (returns status and perhaps data in the
471151937Sjkim         * same buffer)
472107325Siwasaki         */
473114237Snjl        Status = AcpiExAccessRegion (ObjDesc, 0,
474202771Sjkim                    (UINT64 *) Buffer, Function);
475167802Sjkim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
476107325Siwasaki
477107325Siwasaki        *ResultDesc = BufferDesc;
478107325Siwasaki        return_ACPI_STATUS (Status);
479107325Siwasaki    }
480281075Sdim    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
481281075Sdim             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
482281075Sdim    {
483281075Sdim        /*
484281075Sdim         * For GPIO (GeneralPurposeIo), we will bypass the entire field
485281075Sdim         * mechanism and handoff the bit address and bit width directly to
486281075Sdim         * the handler. The Address will be the bit offset
487281075Sdim         * from the previous Connection() operator, making it effectively a
488281075Sdim         * pin number index. The BitLength is the length of the field, which
489281075Sdim         * is thus the number of pins.
490281075Sdim         */
491281075Sdim        if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
492281075Sdim        {
493281075Sdim            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
494281075Sdim        }
495107325Siwasaki
496281075Sdim        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
497281075Sdim            "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]:  Pin %u Bits %u\n",
498281075Sdim            AcpiUtGetTypeName (SourceDesc->Common.Type),
499281075Sdim            SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
500281075Sdim            ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
501281075Sdim
502281075Sdim        Buffer = &SourceDesc->Integer.Value;
503281075Sdim
504281075Sdim        /* Lock entire transaction if requested */
505281075Sdim
506281075Sdim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
507281075Sdim
508281075Sdim        /* Perform the write */
509281075Sdim
510281075Sdim        Status = AcpiExAccessRegion (ObjDesc, 0,
511281075Sdim                    (UINT64 *) Buffer, ACPI_WRITE);
512281075Sdim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
513281075Sdim        return_ACPI_STATUS (Status);
514281075Sdim    }
515281075Sdim
516151937Sjkim    /* Get a pointer to the data to be written */
517151937Sjkim
518193267Sjkim    switch (SourceDesc->Common.Type)
51967754Smsmith    {
52077424Smsmith    case ACPI_TYPE_INTEGER:
521250838Sjkim
52277424Smsmith        Buffer = &SourceDesc->Integer.Value;
52377424Smsmith        Length = sizeof (SourceDesc->Integer.Value);
52477424Smsmith        break;
52577424Smsmith
52677424Smsmith    case ACPI_TYPE_BUFFER:
527250838Sjkim
52877424Smsmith        Buffer = SourceDesc->Buffer.Pointer;
52977424Smsmith        Length = SourceDesc->Buffer.Length;
53077424Smsmith        break;
53177424Smsmith
53277424Smsmith    case ACPI_TYPE_STRING:
533250838Sjkim
53477424Smsmith        Buffer = SourceDesc->String.Pointer;
53577424Smsmith        Length = SourceDesc->String.Length;
53677424Smsmith        break;
53777424Smsmith
53877424Smsmith    default:
539250838Sjkim
54077424Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
54167754Smsmith    }
54267754Smsmith
54399146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
544123315Snjl        "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
545193267Sjkim        SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
546193267Sjkim        SourceDesc->Common.Type, Buffer, Length));
547151937Sjkim
54899146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
549123315Snjl        "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
550193267Sjkim        ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
551193267Sjkim        ObjDesc->Common.Type,
55287031Smsmith        ObjDesc->CommonField.BitLength,
55387031Smsmith        ObjDesc->CommonField.StartFieldBitOffset,
55487031Smsmith        ObjDesc->CommonField.BaseByteOffset));
55567754Smsmith
556107325Siwasaki    /* Lock entire transaction if requested */
557107325Siwasaki
558167802Sjkim    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
55977424Smsmith
560107325Siwasaki    /* Write to the field */
561107325Siwasaki
56287031Smsmith    Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
563167802Sjkim    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
56467754Smsmith
56577424Smsmith    return_ACPI_STATUS (Status);
56677424Smsmith}
567