167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, 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        /*
187306536Sjkim         * This is an SMBus, GSBus or IPMI read. We must create a buffer to
188306536Sjkim         * hold the data and then directly access the region handler.
189197104Sjkim         *
190306536Sjkim         * Note: SMBus and GSBus protocol value is passed in upper 16-bits
191306536Sjkim         * of Function
192107325Siwasaki         */
193306536Sjkim        if (ObjDesc->Field.RegionObj->Region.SpaceId ==
194306536Sjkim            ACPI_ADR_SPACE_SMBUS)
195197104Sjkim        {
196197104Sjkim            Length = ACPI_SMBUS_BUFFER_SIZE;
197197104Sjkim            Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
198197104Sjkim        }
199306536Sjkim        else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
200306536Sjkim            ACPI_ADR_SPACE_GSBUS)
201228110Sjkim        {
202281075Sdim            AccessorType = ObjDesc->Field.Attribute;
203306536Sjkim            Length = AcpiExGetSerialAccessLength (
204306536Sjkim                AccessorType, ObjDesc->Field.AccessLength);
205281075Sdim
206281075Sdim            /*
207281075Sdim             * Add additional 2 bytes for the GenericSerialBus data buffer:
208281075Sdim             *
209306536Sjkim             *     Status;    (Byte 0 of the data buffer)
210306536Sjkim             *     Length;    (Byte 1 of the data buffer)
211306536Sjkim             *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
212281075Sdim             */
213281075Sdim            Length += 2;
214281075Sdim            Function = ACPI_READ | (AccessorType << 16);
215228110Sjkim        }
216197104Sjkim        else /* IPMI */
217197104Sjkim        {
218197104Sjkim            Length = ACPI_IPMI_BUFFER_SIZE;
219197104Sjkim            Function = ACPI_READ;
220197104Sjkim        }
221197104Sjkim
222197104Sjkim        BufferDesc = AcpiUtCreateBufferObject (Length);
223107325Siwasaki        if (!BufferDesc)
224107325Siwasaki        {
225107325Siwasaki            return_ACPI_STATUS (AE_NO_MEMORY);
226107325Siwasaki        }
22787031Smsmith
228107325Siwasaki        /* Lock entire transaction if requested */
229107325Siwasaki
230167802Sjkim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
231107325Siwasaki
232197104Sjkim        /* Call the region handler for the read */
233197104Sjkim
234114237Snjl        Status = AcpiExAccessRegion (ObjDesc, 0,
235306536Sjkim            ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), Function);
236306536Sjkim
237167802Sjkim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
238107325Siwasaki        goto Exit;
239107325Siwasaki    }
240107325Siwasaki
24167754Smsmith    /*
24277424Smsmith     * Allocate a buffer for the contents of the field.
24367754Smsmith     *
244202771Sjkim     * If the field is larger than the current integer width, create
245241973Sjkim     * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
24677424Smsmith     * the use of arithmetic operators on the returned value if the
24777424Smsmith     * field size is equal or smaller than an Integer.
24877424Smsmith     *
24977424Smsmith     * Note: Field.length is in bits.
25067754Smsmith     */
251306536Sjkim    Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (
252306536Sjkim        ObjDesc->Field.BitLength);
253306536Sjkim
25499679Siwasaki    if (Length > AcpiGbl_IntegerByteWidth)
25567754Smsmith    {
25677424Smsmith        /* Field is too large for an Integer, create a Buffer instead */
25767754Smsmith
258107325Siwasaki        BufferDesc = AcpiUtCreateBufferObject (Length);
25977424Smsmith        if (!BufferDesc)
26077424Smsmith        {
26177424Smsmith            return_ACPI_STATUS (AE_NO_MEMORY);
26277424Smsmith        }
26377424Smsmith        Buffer = BufferDesc->Buffer.Pointer;
26467754Smsmith    }
26577424Smsmith    else
26677424Smsmith    {
26777424Smsmith        /* Field will fit within an Integer (normal case) */
26867754Smsmith
269199337Sjkim        BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
27077424Smsmith        if (!BufferDesc)
27177424Smsmith        {
27277424Smsmith            return_ACPI_STATUS (AE_NO_MEMORY);
27377424Smsmith        }
27477424Smsmith
27599679Siwasaki        Length = AcpiGbl_IntegerByteWidth;
27677424Smsmith        Buffer = &BufferDesc->Integer.Value;
27767754Smsmith    }
27867754Smsmith
279281075Sdim    if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
280281075Sdim        (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
281281075Sdim    {
282281075Sdim        /*
283281075Sdim         * For GPIO (GeneralPurposeIo), the Address will be the bit offset
284281075Sdim         * from the previous Connection() operator, making it effectively a
285281075Sdim         * pin number index. The BitLength is the length of the field, which
286281075Sdim         * is thus the number of pins.
287281075Sdim         */
288281075Sdim        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
289281075Sdim            "GPIO FieldRead [FROM]:  Pin %u Bits %u\n",
290281075Sdim            ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
291281075Sdim
292281075Sdim        /* Lock entire transaction if requested */
293281075Sdim
294281075Sdim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
295281075Sdim
296281075Sdim        /* Perform the write */
297281075Sdim
298306536Sjkim        Status = AcpiExAccessRegion (
299306536Sjkim            ObjDesc, 0, (UINT64 *) Buffer, ACPI_READ);
300306536Sjkim
301281075Sdim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
302281075Sdim        if (ACPI_FAILURE (Status))
303281075Sdim        {
304281075Sdim            AcpiUtRemoveReference (BufferDesc);
305281075Sdim        }
306281075Sdim        else
307281075Sdim        {
308281075Sdim            *RetBufferDesc = BufferDesc;
309281075Sdim        }
310281075Sdim        return_ACPI_STATUS (Status);
311281075Sdim    }
312281075Sdim
31399146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
314123315Snjl        "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
315193267Sjkim        ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
31699146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
317123315Snjl        "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
31887031Smsmith        ObjDesc->CommonField.BitLength,
31987031Smsmith        ObjDesc->CommonField.StartFieldBitOffset,
32087031Smsmith        ObjDesc->CommonField.BaseByteOffset));
32177424Smsmith
322107325Siwasaki    /* Lock entire transaction if requested */
323107325Siwasaki
324167802Sjkim    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
32577424Smsmith
32687031Smsmith    /* Read from the field */
32767754Smsmith
328114237Snjl    Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
329167802Sjkim    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
33067754Smsmith
331107325Siwasaki
332107325SiwasakiExit:
33377424Smsmith    if (ACPI_FAILURE (Status))
33477424Smsmith    {
33577424Smsmith        AcpiUtRemoveReference (BufferDesc);
33677424Smsmith    }
337151937Sjkim    else
33877424Smsmith    {
33977424Smsmith        *RetBufferDesc = BufferDesc;
34077424Smsmith    }
34177424Smsmith
34277424Smsmith    return_ACPI_STATUS (Status);
34367754Smsmith}
34467754Smsmith
34567754Smsmith
34667754Smsmith/*******************************************************************************
34767754Smsmith *
34877424Smsmith * FUNCTION:    AcpiExWriteDataToField
34967754Smsmith *
35087031Smsmith * PARAMETERS:  SourceDesc          - Contains data to write
35187031Smsmith *              ObjDesc             - The named field
352151937Sjkim *              ResultDesc          - Where the return value is returned, if any
35367754Smsmith *
35467754Smsmith * RETURN:      Status
35567754Smsmith *
35687031Smsmith * DESCRIPTION: Write to a named field
35767754Smsmith *
35867754Smsmith ******************************************************************************/
35967754Smsmith
36067754SmsmithACPI_STATUS
36177424SmsmithAcpiExWriteDataToField (
36277424Smsmith    ACPI_OPERAND_OBJECT     *SourceDesc,
363107325Siwasaki    ACPI_OPERAND_OBJECT     *ObjDesc,
364107325Siwasaki    ACPI_OPERAND_OBJECT     **ResultDesc)
36567754Smsmith{
36677424Smsmith    ACPI_STATUS             Status;
36777424Smsmith    UINT32                  Length;
36877424Smsmith    void                    *Buffer;
369107325Siwasaki    ACPI_OPERAND_OBJECT     *BufferDesc;
370197104Sjkim    UINT32                  Function;
371281075Sdim    UINT16                  AccessorType;
37267754Smsmith
37367754Smsmith
374167802Sjkim    ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
37567754Smsmith
37667754Smsmith
37771867Smsmith    /* Parameter validation */
37871867Smsmith
37977424Smsmith    if (!SourceDesc || !ObjDesc)
38067754Smsmith    {
38177424Smsmith        return_ACPI_STATUS (AE_AML_NO_OPERAND);
38267754Smsmith    }
38367754Smsmith
384193267Sjkim    if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
38587031Smsmith    {
38687031Smsmith        /*
38787031Smsmith         * If the BufferField arguments have not been previously evaluated,
38887031Smsmith         * evaluate them now and save the results.
38987031Smsmith         */
39087031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
39187031Smsmith        {
39287031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
39387031Smsmith            if (ACPI_FAILURE (Status))
39487031Smsmith            {
39587031Smsmith                return_ACPI_STATUS (Status);
39687031Smsmith            }
39787031Smsmith        }
39887031Smsmith    }
399193267Sjkim    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
400197104Sjkim             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
401228110Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
402197104Sjkim              ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
403107325Siwasaki    {
404107325Siwasaki        /*
405306536Sjkim         * This is an SMBus, GSBus or IPMI write. We will bypass the entire
406306536Sjkim         * field mechanism and handoff the buffer directly to the handler.
407306536Sjkim         * For these address spaces, the buffer is bi-directional; on a
408306536Sjkim         * write, return data is returned in the same buffer.
409107325Siwasaki         *
410197104Sjkim         * Source must be a buffer of sufficient size:
411306536Sjkim         * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or
412306536Sjkim         * ACPI_IPMI_BUFFER_SIZE.
413197104Sjkim         *
414306536Sjkim         * Note: SMBus and GSBus protocol type is passed in upper 16-bits
415306536Sjkim         * of Function
416107325Siwasaki         */
417193267Sjkim        if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
418107325Siwasaki        {
419197104Sjkim            ACPI_ERROR ((AE_INFO,
420306536Sjkim                "SMBus/IPMI/GenericSerialBus write requires "
421306536Sjkim                "Buffer, found type %s",
422107325Siwasaki                AcpiUtGetObjectTypeName (SourceDesc)));
423151937Sjkim
424107325Siwasaki            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
425107325Siwasaki        }
42667754Smsmith
427306536Sjkim        if (ObjDesc->Field.RegionObj->Region.SpaceId ==
428306536Sjkim            ACPI_ADR_SPACE_SMBUS)
429107325Siwasaki        {
430197104Sjkim            Length = ACPI_SMBUS_BUFFER_SIZE;
431197104Sjkim            Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
432197104Sjkim        }
433306536Sjkim        else if (ObjDesc->Field.RegionObj->Region.SpaceId ==
434306536Sjkim            ACPI_ADR_SPACE_GSBUS)
435228110Sjkim        {
436281075Sdim            AccessorType = ObjDesc->Field.Attribute;
437306536Sjkim            Length = AcpiExGetSerialAccessLength (
438306536Sjkim                AccessorType, ObjDesc->Field.AccessLength);
439281075Sdim
440281075Sdim            /*
441281075Sdim             * Add additional 2 bytes for the GenericSerialBus data buffer:
442281075Sdim             *
443306536Sjkim             *     Status;    (Byte 0 of the data buffer)
444306536Sjkim             *     Length;    (Byte 1 of the data buffer)
445306536Sjkim             *     Data[x-1]: (Bytes 2-x of the arbitrary length data buffer)
446281075Sdim             */
447281075Sdim            Length += 2;
448281075Sdim            Function = ACPI_WRITE | (AccessorType << 16);
449228110Sjkim        }
450197104Sjkim        else /* IPMI */
451197104Sjkim        {
452197104Sjkim            Length = ACPI_IPMI_BUFFER_SIZE;
453197104Sjkim            Function = ACPI_WRITE;
454197104Sjkim        }
455197104Sjkim
456197104Sjkim        if (SourceDesc->Buffer.Length < Length)
457197104Sjkim        {
458167802Sjkim            ACPI_ERROR ((AE_INFO,
459306536Sjkim                "SMBus/IPMI/GenericSerialBus write requires "
460306536Sjkim                "Buffer of length %u, found length %u",
461197104Sjkim                Length, SourceDesc->Buffer.Length));
462151937Sjkim
463107325Siwasaki            return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
464107325Siwasaki        }
465107325Siwasaki
466197104Sjkim        /* Create the bi-directional buffer */
467197104Sjkim
468197104Sjkim        BufferDesc = AcpiUtCreateBufferObject (Length);
469107325Siwasaki        if (!BufferDesc)
470107325Siwasaki        {
471107325Siwasaki            return_ACPI_STATUS (AE_NO_MEMORY);
472107325Siwasaki        }
473107325Siwasaki
474107325Siwasaki        Buffer = BufferDesc->Buffer.Pointer;
475306536Sjkim        memcpy (Buffer, SourceDesc->Buffer.Pointer, Length);
476107325Siwasaki
477107325Siwasaki        /* Lock entire transaction if requested */
478107325Siwasaki
479167802Sjkim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
480107325Siwasaki
481114237Snjl        /*
482151937Sjkim         * Perform the write (returns status and perhaps data in the
483151937Sjkim         * same buffer)
484107325Siwasaki         */
485306536Sjkim        Status = AcpiExAccessRegion (
486306536Sjkim            ObjDesc, 0, (UINT64 *) Buffer, Function);
487167802Sjkim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
488107325Siwasaki
489107325Siwasaki        *ResultDesc = BufferDesc;
490107325Siwasaki        return_ACPI_STATUS (Status);
491107325Siwasaki    }
492281075Sdim    else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
493281075Sdim             (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO))
494281075Sdim    {
495281075Sdim        /*
496281075Sdim         * For GPIO (GeneralPurposeIo), we will bypass the entire field
497281075Sdim         * mechanism and handoff the bit address and bit width directly to
498281075Sdim         * the handler. The Address will be the bit offset
499281075Sdim         * from the previous Connection() operator, making it effectively a
500281075Sdim         * pin number index. The BitLength is the length of the field, which
501281075Sdim         * is thus the number of pins.
502281075Sdim         */
503281075Sdim        if (SourceDesc->Common.Type != ACPI_TYPE_INTEGER)
504281075Sdim        {
505281075Sdim            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
506281075Sdim        }
507107325Siwasaki
508281075Sdim        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
509306536Sjkim            "GPIO FieldWrite [FROM]: (%s:%X), Val %.8X  [TO]: Pin %u Bits %u\n",
510281075Sdim            AcpiUtGetTypeName (SourceDesc->Common.Type),
511281075Sdim            SourceDesc->Common.Type, (UINT32) SourceDesc->Integer.Value,
512281075Sdim            ObjDesc->Field.PinNumberIndex, ObjDesc->Field.BitLength));
513281075Sdim
514281075Sdim        Buffer = &SourceDesc->Integer.Value;
515281075Sdim
516281075Sdim        /* Lock entire transaction if requested */
517281075Sdim
518281075Sdim        AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
519281075Sdim
520281075Sdim        /* Perform the write */
521281075Sdim
522306536Sjkim        Status = AcpiExAccessRegion (
523306536Sjkim            ObjDesc, 0, (UINT64 *) Buffer, ACPI_WRITE);
524281075Sdim        AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
525281075Sdim        return_ACPI_STATUS (Status);
526281075Sdim    }
527281075Sdim
528151937Sjkim    /* Get a pointer to the data to be written */
529151937Sjkim
530193267Sjkim    switch (SourceDesc->Common.Type)
53167754Smsmith    {
53277424Smsmith    case ACPI_TYPE_INTEGER:
533250838Sjkim
53477424Smsmith        Buffer = &SourceDesc->Integer.Value;
53577424Smsmith        Length = sizeof (SourceDesc->Integer.Value);
53677424Smsmith        break;
53777424Smsmith
53877424Smsmith    case ACPI_TYPE_BUFFER:
539250838Sjkim
54077424Smsmith        Buffer = SourceDesc->Buffer.Pointer;
54177424Smsmith        Length = SourceDesc->Buffer.Length;
54277424Smsmith        break;
54377424Smsmith
54477424Smsmith    case ACPI_TYPE_STRING:
545250838Sjkim
54677424Smsmith        Buffer = SourceDesc->String.Pointer;
54777424Smsmith        Length = SourceDesc->String.Length;
54877424Smsmith        break;
54977424Smsmith
55077424Smsmith    default:
551250838Sjkim
55277424Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
55367754Smsmith    }
55467754Smsmith
55599146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
556123315Snjl        "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
557193267Sjkim        SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
558193267Sjkim        SourceDesc->Common.Type, Buffer, Length));
559151937Sjkim
56099146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
561123315Snjl        "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
562193267Sjkim        ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
563193267Sjkim        ObjDesc->Common.Type,
56487031Smsmith        ObjDesc->CommonField.BitLength,
56587031Smsmith        ObjDesc->CommonField.StartFieldBitOffset,
56687031Smsmith        ObjDesc->CommonField.BaseByteOffset));
56767754Smsmith
568107325Siwasaki    /* Lock entire transaction if requested */
569107325Siwasaki
570167802Sjkim    AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
57177424Smsmith
572107325Siwasaki    /* Write to the field */
573107325Siwasaki
57487031Smsmith    Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
575167802Sjkim    AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
57667754Smsmith
57777424Smsmith    return_ACPI_STATUS (Status);
57877424Smsmith}
579