exfldio.c revision 245582
167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfldio - Aml Field I/O
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8245582Sjkim * Copyright (C) 2000 - 2013, 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
4467754Smsmith
4577424Smsmith#define __EXFLDIO_C__
4667754Smsmith
47193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
48193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
49193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
50193341Sjkim#include <contrib/dev/acpica/include/amlcode.h>
51193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
52193341Sjkim#include <contrib/dev/acpica/include/acdispat.h>
5367754Smsmith
5467754Smsmith
5577424Smsmith#define _COMPONENT          ACPI_EXECUTER
5691116Smsmith        ACPI_MODULE_NAME    ("exfldio")
5767754Smsmith
58151937Sjkim/* Local prototypes */
5967754Smsmith
60151937Sjkimstatic ACPI_STATUS
61151937SjkimAcpiExFieldDatumIo (
62151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
63151937Sjkim    UINT32                  FieldDatumByteOffset,
64202771Sjkim    UINT64                  *Value,
65151937Sjkim    UINT32                  ReadWrite);
66151937Sjkim
67151937Sjkimstatic BOOLEAN
68151937SjkimAcpiExRegisterOverflow (
69151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
70202771Sjkim    UINT64                  Value);
71151937Sjkim
72151937Sjkimstatic ACPI_STATUS
73151937SjkimAcpiExSetupRegion (
74151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
75151937Sjkim    UINT32                  FieldDatumByteOffset);
76151937Sjkim
77151937Sjkim
7867754Smsmith/*******************************************************************************
7967754Smsmith *
8087031Smsmith * FUNCTION:    AcpiExSetupRegion
8167754Smsmith *
82151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be read or written
8387031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
8487031Smsmith *                                        parent field
8567754Smsmith *
8667754Smsmith * RETURN:      Status
8767754Smsmith *
8877424Smsmith * DESCRIPTION: Common processing for AcpiExExtractFromField and
89241973Sjkim *              AcpiExInsertIntoField. Initialize the Region if necessary and
90123315Snjl *              validate the request.
9167754Smsmith *
9267754Smsmith ******************************************************************************/
9367754Smsmith
94151937Sjkimstatic ACPI_STATUS
9587031SmsmithAcpiExSetupRegion (
9667754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
9777424Smsmith    UINT32                  FieldDatumByteOffset)
9867754Smsmith{
9977424Smsmith    ACPI_STATUS             Status = AE_OK;
10077424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
101228110Sjkim    UINT8                   SpaceId;
10267754Smsmith
10367754Smsmith
104167802Sjkim    ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
10567754Smsmith
10683174Smsmith
10777424Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
10867754Smsmith
109107325Siwasaki    /* We must have a valid region */
110107325Siwasaki
111193267Sjkim    if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
11277424Smsmith    {
113204773Sjkim        ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
114193267Sjkim            RgnDesc->Common.Type,
11599679Siwasaki            AcpiUtGetObjectTypeName (RgnDesc)));
11699679Siwasaki
11777424Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
11877424Smsmith    }
11967754Smsmith
120228110Sjkim    SpaceId = RgnDesc->Region.SpaceId;
121228110Sjkim
122228110Sjkim    /* Validate the Space ID */
123228110Sjkim
124228110Sjkim    if (!AcpiIsValidSpaceId (SpaceId))
125228110Sjkim    {
126228110Sjkim        ACPI_ERROR ((AE_INFO, "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId));
127228110Sjkim        return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
128228110Sjkim    }
129228110Sjkim
13077424Smsmith    /*
13177424Smsmith     * If the Region Address and Length have not been previously evaluated,
13277424Smsmith     * evaluate them now and save the results.
13377424Smsmith     */
134123315Snjl    if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
13567754Smsmith    {
13677424Smsmith        Status = AcpiDsGetRegionArguments (RgnDesc);
13777424Smsmith        if (ACPI_FAILURE (Status))
13877424Smsmith        {
13977424Smsmith            return_ACPI_STATUS (Status);
14077424Smsmith        }
14167754Smsmith    }
14267754Smsmith
143167802Sjkim    /*
144228110Sjkim     * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
145210976Sjkim     * address space and the request cannot be directly validated
146167802Sjkim     */
147228110Sjkim    if (SpaceId == ACPI_ADR_SPACE_SMBUS ||
148228110Sjkim        SpaceId == ACPI_ADR_SPACE_GSBUS ||
149228110Sjkim        SpaceId == ACPI_ADR_SPACE_IPMI)
150107325Siwasaki    {
151197104Sjkim        /* SMBus or IPMI has a non-linear address space */
152107325Siwasaki
153107325Siwasaki        return_ACPI_STATUS (AE_OK);
154107325Siwasaki    }
155107325Siwasaki
156123315Snjl#ifdef ACPI_UNDER_DEVELOPMENT
15777424Smsmith    /*
158123315Snjl     * If the Field access is AnyAcc, we can now compute the optimal
159123315Snjl     * access (because we know know the length of the parent region)
160123315Snjl     */
161123315Snjl    if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
162123315Snjl    {
163123315Snjl        if (ACPI_FAILURE (Status))
164123315Snjl        {
165123315Snjl            return_ACPI_STATUS (Status);
166123315Snjl        }
167123315Snjl    }
168123315Snjl#endif
169123315Snjl
170123315Snjl    /*
171241973Sjkim     * Validate the request. The entire request from the byte offset for a
17277424Smsmith     * length of one field datum (access width) must fit within the region.
17377424Smsmith     * (Region length is specified in bytes)
17477424Smsmith     */
175167802Sjkim    if (RgnDesc->Region.Length <
176210976Sjkim            (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
177167802Sjkim            ObjDesc->CommonField.AccessByteWidth))
17877424Smsmith    {
179138287Smarks        if (AcpiGbl_EnableInterpreterSlack)
180138287Smarks        {
181138287Smarks            /*
182138287Smarks             * Slack mode only:  We will go ahead and allow access to this
183138287Smarks             * field if it is within the region length rounded up to the next
184193267Sjkim             * access width boundary. ACPI_SIZE cast for 64-bit compile.
185138287Smarks             */
186138287Smarks            if (ACPI_ROUND_UP (RgnDesc->Region.Length,
187167802Sjkim                    ObjDesc->CommonField.AccessByteWidth) >=
188193267Sjkim                ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
189193267Sjkim                    ObjDesc->CommonField.AccessByteWidth +
190193267Sjkim                    FieldDatumByteOffset))
191138287Smarks            {
192138287Smarks                return_ACPI_STATUS (AE_OK);
193138287Smarks            }
194138287Smarks        }
195138287Smarks
19677424Smsmith        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
19777424Smsmith        {
19883174Smsmith            /*
19977424Smsmith             * This is the case where the AccessType (AccWord, etc.) is wider
200241973Sjkim             * than the region itself. For example, a region of length one
20177424Smsmith             * byte, and a field with Dword access specified.
20277424Smsmith             */
203167802Sjkim            ACPI_ERROR ((AE_INFO,
204204773Sjkim                "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
205123315Snjl                AcpiUtGetNodeName (ObjDesc->CommonField.Node),
206123315Snjl                ObjDesc->CommonField.AccessByteWidth,
207151937Sjkim                AcpiUtGetNodeName (RgnDesc->Region.Node),
208151937Sjkim                RgnDesc->Region.Length));
20977424Smsmith        }
21077424Smsmith
21177424Smsmith        /*
21277424Smsmith         * Offset rounded up to next multiple of field width
21377424Smsmith         * exceeds region length, indicate an error
21477424Smsmith         */
215167802Sjkim        ACPI_ERROR ((AE_INFO,
216204773Sjkim            "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)",
217123315Snjl            AcpiUtGetNodeName (ObjDesc->CommonField.Node),
218123315Snjl            ObjDesc->CommonField.BaseByteOffset,
21991116Smsmith            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
220151937Sjkim            AcpiUtGetNodeName (RgnDesc->Region.Node),
221151937Sjkim            RgnDesc->Region.Length));
22277424Smsmith
22377424Smsmith        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
22477424Smsmith    }
22577424Smsmith
22677424Smsmith    return_ACPI_STATUS (AE_OK);
22777424Smsmith}
22877424Smsmith
22977424Smsmith
23077424Smsmith/*******************************************************************************
23177424Smsmith *
23287031Smsmith * FUNCTION:    AcpiExAccessRegion
23377424Smsmith *
234151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be read
23587031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
23687031Smsmith *                                        parent field
237151937Sjkim *              Value                   - Where to store value (must at least
238202771Sjkim *                                        64 bits)
239107325Siwasaki *              Function                - Read or Write flag plus other region-
240107325Siwasaki *                                        dependent flags
24177424Smsmith *
24277424Smsmith * RETURN:      Status
24377424Smsmith *
24487031Smsmith * DESCRIPTION: Read or Write a single field datum to an Operation Region.
24577424Smsmith *
24677424Smsmith ******************************************************************************/
24777424Smsmith
24877424SmsmithACPI_STATUS
24987031SmsmithAcpiExAccessRegion (
25077424Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
25177424Smsmith    UINT32                  FieldDatumByteOffset,
252202771Sjkim    UINT64                  *Value,
253107325Siwasaki    UINT32                  Function)
25477424Smsmith{
25577424Smsmith    ACPI_STATUS             Status;
25677424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
257193267Sjkim    UINT32                  RegionOffset;
25877424Smsmith
25977424Smsmith
260167802Sjkim    ACPI_FUNCTION_TRACE (ExAccessRegion);
26177424Smsmith
26277424Smsmith
263114237Snjl    /*
264107325Siwasaki     * Ensure that the region operands are fully evaluated and verify
265107325Siwasaki     * the validity of the request
266107325Siwasaki     */
267107325Siwasaki    Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
268107325Siwasaki    if (ACPI_FAILURE (Status))
269107325Siwasaki    {
270107325Siwasaki        return_ACPI_STATUS (Status);
271107325Siwasaki    }
272107325Siwasaki
27387031Smsmith    /*
27487031Smsmith     * The physical address of this field datum is:
27587031Smsmith     *
27687031Smsmith     * 1) The base of the region, plus
27787031Smsmith     * 2) The base offset of the field, plus
27887031Smsmith     * 3) The current offset into the field
27987031Smsmith     */
28087031Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
281193267Sjkim    RegionOffset =
282193267Sjkim        ObjDesc->CommonField.BaseByteOffset +
283193267Sjkim        FieldDatumByteOffset;
28487031Smsmith
285107325Siwasaki    if ((Function & ACPI_IO_MASK) == ACPI_READ)
28667754Smsmith    {
28787031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
28867754Smsmith    }
28987031Smsmith    else
29087031Smsmith    {
29187031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
29287031Smsmith    }
29367754Smsmith
29487031Smsmith    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
295167802Sjkim        " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
29687031Smsmith        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
29787031Smsmith        RgnDesc->Region.SpaceId,
29891116Smsmith        ObjDesc->CommonField.AccessByteWidth,
29987031Smsmith        ObjDesc->CommonField.BaseByteOffset,
30087031Smsmith        FieldDatumByteOffset,
301193267Sjkim        ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset))));
30267754Smsmith
30387031Smsmith    /* Invoke the appropriate AddressSpace/OpRegion handler */
30477424Smsmith
305228110Sjkim    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc,
306228110Sjkim                Function, RegionOffset,
307151937Sjkim                ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
30887031Smsmith
30987031Smsmith    if (ACPI_FAILURE (Status))
31087031Smsmith    {
31187031Smsmith        if (Status == AE_NOT_IMPLEMENTED)
31287031Smsmith        {
313167802Sjkim            ACPI_ERROR ((AE_INFO,
314218590Sjkim                "Region %s (ID=%u) not implemented",
31587031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
31687031Smsmith                RgnDesc->Region.SpaceId));
31787031Smsmith        }
31887031Smsmith        else if (Status == AE_NOT_EXIST)
31987031Smsmith        {
320167802Sjkim            ACPI_ERROR ((AE_INFO,
321218590Sjkim                "Region %s (ID=%u) has no handler",
32287031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
32387031Smsmith                RgnDesc->Region.SpaceId));
32487031Smsmith        }
32587031Smsmith    }
32687031Smsmith
32787031Smsmith    return_ACPI_STATUS (Status);
32887031Smsmith}
32987031Smsmith
33087031Smsmith
33187031Smsmith/*******************************************************************************
33287031Smsmith *
33387031Smsmith * FUNCTION:    AcpiExRegisterOverflow
33487031Smsmith *
335151937Sjkim * PARAMETERS:  ObjDesc                 - Register(Field) to be written
33687031Smsmith *              Value                   - Value to be stored
33787031Smsmith *
33887031Smsmith * RETURN:      TRUE if value overflows the field, FALSE otherwise
33987031Smsmith *
34087031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written.
34187031Smsmith *              Used to check if the values written to Index and Bank registers
342241973Sjkim *              are out of range. Normally, the value is simply truncated
34387031Smsmith *              to fit the field, but this case is most likely a serious
34487031Smsmith *              coding error in the ASL.
34587031Smsmith *
34687031Smsmith ******************************************************************************/
34787031Smsmith
348151937Sjkimstatic BOOLEAN
34987031SmsmithAcpiExRegisterOverflow (
35087031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
351202771Sjkim    UINT64                  Value)
35287031Smsmith{
35387031Smsmith
35491116Smsmith    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
35591116Smsmith    {
35691116Smsmith        /*
35791116Smsmith         * The field is large enough to hold the maximum integer, so we can
35891116Smsmith         * never overflow it.
35991116Smsmith         */
36091116Smsmith        return (FALSE);
36191116Smsmith    }
36291116Smsmith
363202771Sjkim    if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
36487031Smsmith    {
36591116Smsmith        /*
36691116Smsmith         * The Value is larger than the maximum value that can fit into
36791116Smsmith         * the register.
36891116Smsmith         */
369228110Sjkim        ACPI_ERROR ((AE_INFO,
370228110Sjkim            "Index value 0x%8.8X%8.8X overflows field width 0x%X",
371228110Sjkim            ACPI_FORMAT_UINT64 (Value),
372228110Sjkim            ObjDesc->CommonField.BitLength));
373228110Sjkim
37487031Smsmith        return (TRUE);
37587031Smsmith    }
37687031Smsmith
37791116Smsmith    /* The Value will fit into the field with no truncation */
37891116Smsmith
37987031Smsmith    return (FALSE);
38087031Smsmith}
38187031Smsmith
38287031Smsmith
38387031Smsmith/*******************************************************************************
38487031Smsmith *
38587031Smsmith * FUNCTION:    AcpiExFieldDatumIo
38687031Smsmith *
387151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be read
38887031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
38987031Smsmith *                                        parent field
390151937Sjkim *              Value                   - Where to store value (must be 64 bits)
39187031Smsmith *              ReadWrite               - Read or Write flag
39287031Smsmith *
39387031Smsmith * RETURN:      Status
39487031Smsmith *
395241973Sjkim * DESCRIPTION: Read or Write a single datum of a field. The FieldType is
39687031Smsmith *              demultiplexed here to handle the different types of fields
39787031Smsmith *              (BufferField, RegionField, IndexField, BankField)
39887031Smsmith *
39987031Smsmith ******************************************************************************/
40087031Smsmith
401151937Sjkimstatic ACPI_STATUS
40287031SmsmithAcpiExFieldDatumIo (
40387031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
40487031Smsmith    UINT32                  FieldDatumByteOffset,
405202771Sjkim    UINT64                  *Value,
40687031Smsmith    UINT32                  ReadWrite)
40787031Smsmith{
40887031Smsmith    ACPI_STATUS             Status;
409202771Sjkim    UINT64                  LocalValue;
41087031Smsmith
41187031Smsmith
412167802Sjkim    ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
41387031Smsmith
41487031Smsmith
41587031Smsmith    if (ReadWrite == ACPI_READ)
41687031Smsmith    {
41787031Smsmith        if (!Value)
41887031Smsmith        {
41987031Smsmith            LocalValue = 0;
420151937Sjkim
421151937Sjkim            /* To support reads without saving return value */
422151937Sjkim            Value = &LocalValue;
42387031Smsmith        }
42487031Smsmith
42587031Smsmith        /* Clear the entire return buffer first, [Very Important!] */
42687031Smsmith
42787031Smsmith        *Value = 0;
42887031Smsmith    }
42987031Smsmith
43087031Smsmith    /*
43187031Smsmith     * The four types of fields are:
43287031Smsmith     *
433122944Snjl     * BufferField - Read/write from/to a Buffer
434122944Snjl     * RegionField - Read/write from/to a Operation Region.
435151937Sjkim     * BankField   - Write to a Bank Register, then read/write from/to an
436151937Sjkim     *               OperationRegion
437151937Sjkim     * IndexField  - Write to an Index Register, then read/write from/to a
438151937Sjkim     *               Data Register
43987031Smsmith     */
440193267Sjkim    switch (ObjDesc->Common.Type)
44177424Smsmith    {
44277424Smsmith    case ACPI_TYPE_BUFFER_FIELD:
44377424Smsmith        /*
44487031Smsmith         * If the BufferField arguments have not been previously evaluated,
44587031Smsmith         * evaluate them now and save the results.
44677424Smsmith         */
44787031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
44887031Smsmith        {
44987031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
45087031Smsmith            if (ACPI_FAILURE (Status))
45187031Smsmith            {
45287031Smsmith                return_ACPI_STATUS (Status);
45387031Smsmith            }
45487031Smsmith        }
45587031Smsmith
45687031Smsmith        if (ReadWrite == ACPI_READ)
45787031Smsmith        {
45887031Smsmith            /*
45987031Smsmith             * Copy the data from the source buffer.
46087031Smsmith             * Length is the field width in bytes.
46187031Smsmith             */
462151937Sjkim            ACPI_MEMCPY (Value,
463151937Sjkim                (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
464151937Sjkim                    ObjDesc->BufferField.BaseByteOffset +
465151937Sjkim                    FieldDatumByteOffset,
466151937Sjkim                ObjDesc->CommonField.AccessByteWidth);
46787031Smsmith        }
46887031Smsmith        else
46987031Smsmith        {
47087031Smsmith            /*
47187031Smsmith             * Copy the data to the target buffer.
47287031Smsmith             * Length is the field width in bytes.
47387031Smsmith             */
474151937Sjkim            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
475167802Sjkim                ObjDesc->BufferField.BaseByteOffset +
476167802Sjkim                FieldDatumByteOffset,
477167802Sjkim                Value, ObjDesc->CommonField.AccessByteWidth);
47887031Smsmith        }
47987031Smsmith
48077424Smsmith        Status = AE_OK;
48177424Smsmith        break;
48267754Smsmith
48367754Smsmith
484107325Siwasaki    case ACPI_TYPE_LOCAL_BANK_FIELD:
48567754Smsmith
486151937Sjkim        /*
487151937Sjkim         * Ensure that the BankValue is not beyond the capacity of
488151937Sjkim         * the register
489151937Sjkim         */
49087031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
491202771Sjkim                (UINT64) ObjDesc->BankField.Value))
49287031Smsmith        {
49387031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
49487031Smsmith        }
49587031Smsmith
49677424Smsmith        /*
49787031Smsmith         * For BankFields, we must write the BankValue to the BankRegister
49887031Smsmith         * (itself a RegionField) before we can access the data.
49977424Smsmith         */
50087031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
501167802Sjkim                    &ObjDesc->BankField.Value,
502167802Sjkim                    sizeof (ObjDesc->BankField.Value));
50377424Smsmith        if (ACPI_FAILURE (Status))
50477424Smsmith        {
50577424Smsmith            return_ACPI_STATUS (Status);
50677424Smsmith        }
50767754Smsmith
50877424Smsmith        /*
50987031Smsmith         * Now that the Bank has been selected, fall through to the
51087031Smsmith         * RegionField case and write the datum to the Operation Region
51177424Smsmith         */
51277424Smsmith
51399679Siwasaki        /*lint -fallthrough */
51477424Smsmith
51577424Smsmith
516107325Siwasaki    case ACPI_TYPE_LOCAL_REGION_FIELD:
51787031Smsmith        /*
51887031Smsmith         * For simple RegionFields, we just directly access the owning
51987031Smsmith         * Operation Region.
52087031Smsmith         */
52187031Smsmith        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
522167802Sjkim                    ReadWrite);
52387031Smsmith        break;
52487031Smsmith
52587031Smsmith
526107325Siwasaki    case ACPI_TYPE_LOCAL_INDEX_FIELD:
52787031Smsmith
52887031Smsmith
529151937Sjkim        /*
530151937Sjkim         * Ensure that the IndexValue is not beyond the capacity of
531151937Sjkim         * the register
532151937Sjkim         */
53387031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
534202771Sjkim                (UINT64) ObjDesc->IndexField.Value))
53577424Smsmith        {
53687031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
53777424Smsmith        }
53887031Smsmith
53987031Smsmith        /* Write the index value to the IndexRegister (itself a RegionField) */
54087031Smsmith
541122944Snjl        FieldDatumByteOffset += ObjDesc->IndexField.Value;
542122944Snjl
543122944Snjl        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
544167802Sjkim            "Write to Index Register: Value %8.8X\n",
545167802Sjkim            FieldDatumByteOffset));
546122944Snjl
54787031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
548167802Sjkim                    &FieldDatumByteOffset,
549167802Sjkim                    sizeof (FieldDatumByteOffset));
55087031Smsmith        if (ACPI_FAILURE (Status))
55187031Smsmith        {
55287031Smsmith            return_ACPI_STATUS (Status);
55387031Smsmith        }
55487031Smsmith
55587031Smsmith        if (ReadWrite == ACPI_READ)
55687031Smsmith        {
55787031Smsmith            /* Read the datum from the DataRegister */
55887031Smsmith
559193267Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
560193267Sjkim                "Read from Data Register\n"));
561193267Sjkim
56287031Smsmith            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
563202771Sjkim                        Value, sizeof (UINT64));
56487031Smsmith        }
56587031Smsmith        else
56687031Smsmith        {
567122944Snjl            /* Write the datum to the DataRegister */
56887031Smsmith
569193267Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
570193267Sjkim                "Write to Data Register: Value %8.8X%8.8X\n",
571193267Sjkim                ACPI_FORMAT_UINT64 (*Value)));
572193267Sjkim
57387031Smsmith            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
574202771Sjkim                        Value, sizeof (UINT64));
57587031Smsmith        }
57677424Smsmith        break;
57777424Smsmith
57877424Smsmith
57977424Smsmith    default:
58077424Smsmith
581204773Sjkim        ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
582193267Sjkim            ObjDesc->Common.Type));
58377424Smsmith        Status = AE_AML_INTERNAL;
58477424Smsmith        break;
58567754Smsmith    }
58667754Smsmith
58787031Smsmith    if (ACPI_SUCCESS (Status))
58887031Smsmith    {
58987031Smsmith        if (ReadWrite == ACPI_READ)
59087031Smsmith        {
591151937Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
592209746Sjkim                "Value Read %8.8X%8.8X, Width %u\n",
593151937Sjkim                ACPI_FORMAT_UINT64 (*Value),
594151937Sjkim                ObjDesc->CommonField.AccessByteWidth));
59587031Smsmith        }
59687031Smsmith        else
59787031Smsmith        {
598151937Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
599209746Sjkim                "Value Written %8.8X%8.8X, Width %u\n",
600151937Sjkim                ACPI_FORMAT_UINT64 (*Value),
601151937Sjkim                ObjDesc->CommonField.AccessByteWidth));
60287031Smsmith        }
60387031Smsmith    }
60477424Smsmith
60587031Smsmith    return_ACPI_STATUS (Status);
60687031Smsmith}
60777424Smsmith
60887031Smsmith
60987031Smsmith/*******************************************************************************
61087031Smsmith *
61187031Smsmith * FUNCTION:    AcpiExWriteWithUpdateRule
61287031Smsmith *
613151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be written
614151937Sjkim *              Mask                    - bitmask within field datum
615151937Sjkim *              FieldValue              - Value to write
616151937Sjkim *              FieldDatumByteOffset    - Offset of datum within field
61787031Smsmith *
61887031Smsmith * RETURN:      Status
61987031Smsmith *
62087031Smsmith * DESCRIPTION: Apply the field update rule to a field write
62187031Smsmith *
62287031Smsmith ******************************************************************************/
62387031Smsmith
62487031SmsmithACPI_STATUS
62587031SmsmithAcpiExWriteWithUpdateRule (
62687031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
627202771Sjkim    UINT64                  Mask,
628202771Sjkim    UINT64                  FieldValue,
62987031Smsmith    UINT32                  FieldDatumByteOffset)
63087031Smsmith{
63187031Smsmith    ACPI_STATUS             Status = AE_OK;
632202771Sjkim    UINT64                  MergedValue;
633202771Sjkim    UINT64                  CurrentValue;
63487031Smsmith
63587031Smsmith
636167802Sjkim    ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
63787031Smsmith
63887031Smsmith
63987031Smsmith    /* Start with the new bits  */
64087031Smsmith
64187031Smsmith    MergedValue = FieldValue;
64287031Smsmith
64387031Smsmith    /* If the mask is all ones, we don't need to worry about the update rule */
64487031Smsmith
645202771Sjkim    if (Mask != ACPI_UINT64_MAX)
64687031Smsmith    {
64787031Smsmith        /* Decode the update rule */
64887031Smsmith
64987031Smsmith        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
65087031Smsmith        {
65187031Smsmith        case AML_FIELD_UPDATE_PRESERVE:
65287031Smsmith            /*
65387031Smsmith             * Check if update rule needs to be applied (not if mask is all
65487031Smsmith             * ones)  The left shift drops the bits we want to ignore.
65587031Smsmith             */
65691116Smsmith            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
65791116Smsmith                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
65887031Smsmith            {
65987031Smsmith                /*
66087031Smsmith                 * Read the current contents of the byte/word/dword containing
66187031Smsmith                 * the field, and merge with the new field value.
66287031Smsmith                 */
66387031Smsmith                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
664167802Sjkim                            &CurrentValue, ACPI_READ);
665123315Snjl                if (ACPI_FAILURE (Status))
666123315Snjl                {
667123315Snjl                    return_ACPI_STATUS (Status);
668123315Snjl                }
669123315Snjl
67087031Smsmith                MergedValue |= (CurrentValue & ~Mask);
67187031Smsmith            }
67287031Smsmith            break;
67387031Smsmith
67487031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ONES:
67587031Smsmith
67687031Smsmith            /* Set positions outside the field to all ones */
67787031Smsmith
67887031Smsmith            MergedValue |= ~Mask;
67987031Smsmith            break;
68087031Smsmith
68187031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
68287031Smsmith
68387031Smsmith            /* Set positions outside the field to all zeros */
68487031Smsmith
68587031Smsmith            MergedValue &= Mask;
68687031Smsmith            break;
68787031Smsmith
68887031Smsmith        default:
689123315Snjl
690167802Sjkim            ACPI_ERROR ((AE_INFO,
691204773Sjkim                "Unknown UpdateRule value: 0x%X",
69287031Smsmith                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
69387031Smsmith            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
69487031Smsmith        }
69587031Smsmith    }
69687031Smsmith
697123315Snjl    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
698123315Snjl        "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
699123315Snjl        ACPI_FORMAT_UINT64 (Mask),
700123315Snjl        FieldDatumByteOffset,
701123315Snjl        ObjDesc->CommonField.AccessByteWidth,
702123315Snjl        ACPI_FORMAT_UINT64 (FieldValue),
703123315Snjl        ACPI_FORMAT_UINT64 (MergedValue)));
704123315Snjl
70587031Smsmith    /* Write the merged value */
70687031Smsmith
70787031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
708167802Sjkim                &MergedValue, ACPI_WRITE);
70987031Smsmith
71077424Smsmith    return_ACPI_STATUS (Status);
71177424Smsmith}
71277424Smsmith
71377424Smsmith
71477424Smsmith/*******************************************************************************
71577424Smsmith *
71677424Smsmith * FUNCTION:    AcpiExExtractFromField
71767754Smsmith *
718131440Smarks * PARAMETERS:  ObjDesc             - Field to be read
719131440Smarks *              Buffer              - Where to store the field data
720131440Smarks *              BufferLength        - Length of Buffer
72167754Smsmith *
72267754Smsmith * RETURN:      Status
72367754Smsmith *
724131440Smarks * DESCRIPTION: Retrieve the current value of the given field
72567754Smsmith *
72667754Smsmith ******************************************************************************/
72767754Smsmith
72867754SmsmithACPI_STATUS
72977424SmsmithAcpiExExtractFromField (
73067754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
73167754Smsmith    void                    *Buffer,
73277424Smsmith    UINT32                  BufferLength)
73367754Smsmith{
73467754Smsmith    ACPI_STATUS             Status;
735202771Sjkim    UINT64                  RawDatum;
736202771Sjkim    UINT64                  MergedDatum;
737151937Sjkim    UINT32                  FieldOffset = 0;
738151937Sjkim    UINT32                  BufferOffset = 0;
739151937Sjkim    UINT32                  BufferTailBits;
74077424Smsmith    UINT32                  DatumCount;
741151937Sjkim    UINT32                  FieldDatumCount;
742210976Sjkim    UINT32                  AccessBitWidth;
743123315Snjl    UINT32                  i;
74467754Smsmith
74567754Smsmith
746167802Sjkim    ACPI_FUNCTION_TRACE (ExExtractFromField);
74767754Smsmith
74877424Smsmith
749151937Sjkim    /* Validate target buffer and clear it */
75077424Smsmith
751167802Sjkim    if (BufferLength <
752210976Sjkim        ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
753151937Sjkim    {
754167802Sjkim        ACPI_ERROR ((AE_INFO,
755204773Sjkim            "Field size %u (bits) is too large for buffer (%u)",
756151937Sjkim            ObjDesc->CommonField.BitLength, BufferLength));
757151937Sjkim
758151937Sjkim        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
759151937Sjkim    }
760210976Sjkim
761151937Sjkim    ACPI_MEMSET (Buffer, 0, BufferLength);
762210976Sjkim    AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
763151937Sjkim
764210976Sjkim    /* Handle the simple case here */
765210976Sjkim
766210976Sjkim    if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
767210976Sjkim        (ObjDesc->CommonField.BitLength == AccessBitWidth))
768210976Sjkim    {
769210976Sjkim        Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
770210976Sjkim        return_ACPI_STATUS (Status);
771210976Sjkim    }
772210976Sjkim
773210976Sjkim/* TBD: Move to common setup code */
774210976Sjkim
775210976Sjkim    /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
776210976Sjkim
777210976Sjkim    if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
778210976Sjkim    {
779210976Sjkim        ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
780210976Sjkim        AccessBitWidth = sizeof (UINT64) * 8;
781210976Sjkim    }
782210976Sjkim
783151937Sjkim    /* Compute the number of datums (access width data items) */
784151937Sjkim
785151937Sjkim    DatumCount = ACPI_ROUND_UP_TO (
786210976Sjkim        ObjDesc->CommonField.BitLength, AccessBitWidth);
787210976Sjkim
788151937Sjkim    FieldDatumCount = ACPI_ROUND_UP_TO (
789210976Sjkim        ObjDesc->CommonField.BitLength +
790210976Sjkim        ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
791151937Sjkim
792151937Sjkim    /* Priming read from the field */
793151937Sjkim
794151937Sjkim    Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
795131440Smarks    if (ACPI_FAILURE (Status))
796123315Snjl    {
797131440Smarks        return_ACPI_STATUS (Status);
798123315Snjl    }
799151937Sjkim    MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
800123315Snjl
801151937Sjkim    /* Read the rest of the field */
80267754Smsmith
803151937Sjkim    for (i = 1; i < FieldDatumCount; i++)
804151937Sjkim    {
805151937Sjkim        /* Get next input datum from the field */
80667754Smsmith
807151937Sjkim        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
808151937Sjkim        Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
809167802Sjkim                    &RawDatum, ACPI_READ);
810123315Snjl        if (ACPI_FAILURE (Status))
811123315Snjl        {
812123315Snjl            return_ACPI_STATUS (Status);
813123315Snjl        }
81467754Smsmith
815167802Sjkim        /*
816167802Sjkim         * Merge with previous datum if necessary.
817167802Sjkim         *
818167802Sjkim         * Note: Before the shift, check if the shift value will be larger than
819167802Sjkim         * the integer size. If so, there is no need to perform the operation.
820167802Sjkim         * This avoids the differences in behavior between different compilers
821167802Sjkim         * concerning shift values larger than the target data width.
822167802Sjkim         */
823210976Sjkim        if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
824210976Sjkim            ACPI_INTEGER_BIT_SIZE)
825167802Sjkim        {
826167802Sjkim            MergedDatum |= RawDatum <<
827210976Sjkim                (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
828167802Sjkim        }
82967754Smsmith
830151937Sjkim        if (i == DatumCount)
83167754Smsmith        {
832151937Sjkim            break;
83377424Smsmith        }
83467754Smsmith
835151937Sjkim        /* Write merged datum to target buffer */
83671867Smsmith
837151937Sjkim        ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
838151937Sjkim            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
839167802Sjkim                BufferLength - BufferOffset));
84067754Smsmith
841151937Sjkim        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
842151937Sjkim        MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
843151937Sjkim    }
844123315Snjl
845151937Sjkim    /* Mask off any extra bits in the last datum */
846123315Snjl
847210976Sjkim    BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
848151937Sjkim    if (BufferTailBits)
849151937Sjkim    {
850151937Sjkim        MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
851123315Snjl    }
852123315Snjl
853151937Sjkim    /* Write the last datum to the buffer */
854123315Snjl
855151937Sjkim    ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
856151937Sjkim        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
857167802Sjkim            BufferLength - BufferOffset));
858123315Snjl
85977424Smsmith    return_ACPI_STATUS (AE_OK);
86067754Smsmith}
86167754Smsmith
86267754Smsmith
86367754Smsmith/*******************************************************************************
86467754Smsmith *
86577424Smsmith * FUNCTION:    AcpiExInsertIntoField
86667754Smsmith *
867131440Smarks * PARAMETERS:  ObjDesc             - Field to be written
868131440Smarks *              Buffer              - Data to be written
869131440Smarks *              BufferLength        - Length of Buffer
87067754Smsmith *
87167754Smsmith * RETURN:      Status
87267754Smsmith *
873131440Smarks * DESCRIPTION: Store the Buffer contents into the given field
87467754Smsmith *
87577424Smsmith ******************************************************************************/
87667754Smsmith
87767754SmsmithACPI_STATUS
87877424SmsmithAcpiExInsertIntoField (
87967754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
88067754Smsmith    void                    *Buffer,
88177424Smsmith    UINT32                  BufferLength)
88267754Smsmith{
883210976Sjkim    void                    *NewBuffer;
88467754Smsmith    ACPI_STATUS             Status;
885202771Sjkim    UINT64                  Mask;
886202771Sjkim    UINT64                  WidthMask;
887202771Sjkim    UINT64                  MergedDatum;
888202771Sjkim    UINT64                  RawDatum = 0;
889151937Sjkim    UINT32                  FieldOffset = 0;
890151937Sjkim    UINT32                  BufferOffset = 0;
891151937Sjkim    UINT32                  BufferTailBits;
89277424Smsmith    UINT32                  DatumCount;
893151937Sjkim    UINT32                  FieldDatumCount;
894210976Sjkim    UINT32                  AccessBitWidth;
895210976Sjkim    UINT32                  RequiredLength;
896151937Sjkim    UINT32                  i;
89767754Smsmith
89867754Smsmith
899167802Sjkim    ACPI_FUNCTION_TRACE (ExInsertIntoField);
90067754Smsmith
90167754Smsmith
902151937Sjkim    /* Validate input buffer */
903131440Smarks
904193267Sjkim    NewBuffer = NULL;
905193267Sjkim    RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
906193267Sjkim                        ObjDesc->CommonField.BitLength);
907193267Sjkim    /*
908193267Sjkim     * We must have a buffer that is at least as long as the field
909241973Sjkim     * we are writing to. This is because individual fields are
910193267Sjkim     * indivisible and partial writes are not supported -- as per
911193267Sjkim     * the ACPI specification.
912193267Sjkim     */
913193267Sjkim    if (BufferLength < RequiredLength)
91477424Smsmith    {
915193267Sjkim        /* We need to create a new buffer */
916151937Sjkim
917193267Sjkim        NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
918193267Sjkim        if (!NewBuffer)
919193267Sjkim        {
920193267Sjkim            return_ACPI_STATUS (AE_NO_MEMORY);
921193267Sjkim        }
922193267Sjkim
923193267Sjkim        /*
924193267Sjkim         * Copy the original data to the new buffer, starting
925241973Sjkim         * at Byte zero. All unused (upper) bytes of the
926193267Sjkim         * buffer will be 0.
927193267Sjkim         */
928193267Sjkim        ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
929193267Sjkim        Buffer = NewBuffer;
930193267Sjkim        BufferLength = RequiredLength;
93177424Smsmith    }
93267754Smsmith
933210976Sjkim/* TBD: Move to common setup code */
934210976Sjkim
935210976Sjkim    /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
936210976Sjkim    if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
937210976Sjkim    {
938210976Sjkim        ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
939210976Sjkim    }
940210976Sjkim
941210976Sjkim    AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
942210976Sjkim
943167802Sjkim    /*
944167802Sjkim     * Create the bitmasks used for bit insertion.
945167802Sjkim     * Note: This if/else is used to bypass compiler differences with the
946167802Sjkim     * shift operator
947167802Sjkim     */
948210976Sjkim    if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
949167802Sjkim    {
950202771Sjkim        WidthMask = ACPI_UINT64_MAX;
951167802Sjkim    }
952167802Sjkim    else
953167802Sjkim    {
954210976Sjkim        WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
955167802Sjkim    }
956167802Sjkim
957167802Sjkim    Mask = WidthMask &
958210976Sjkim        ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
959167802Sjkim
960151937Sjkim    /* Compute the number of datums (access width data items) */
96167754Smsmith
962151937Sjkim    DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
963210976Sjkim        AccessBitWidth);
964167802Sjkim
965151937Sjkim    FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
966210976Sjkim        ObjDesc->CommonField.StartFieldBitOffset,
967210976Sjkim        AccessBitWidth);
96867754Smsmith
969151937Sjkim    /* Get initial Datum from the input buffer */
97067754Smsmith
971151937Sjkim    ACPI_MEMCPY (&RawDatum, Buffer,
972151937Sjkim        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
973167802Sjkim            BufferLength - BufferOffset));
97467754Smsmith
975151937Sjkim    MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
97667754Smsmith
977151937Sjkim    /* Write the entire field */
97867754Smsmith
979151937Sjkim    for (i = 1; i < FieldDatumCount; i++)
98067754Smsmith    {
981151937Sjkim        /* Write merged datum to the target field */
98267754Smsmith
983151937Sjkim        MergedDatum &= Mask;
984151937Sjkim        Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
985151937Sjkim                    MergedDatum, FieldOffset);
986151937Sjkim        if (ACPI_FAILURE (Status))
987151937Sjkim        {
988193267Sjkim            goto Exit;
989151937Sjkim        }
990123315Snjl
991151937Sjkim        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
99267754Smsmith
993167802Sjkim        /*
994167802Sjkim         * Start new output datum by merging with previous input datum
995167802Sjkim         * if necessary.
996167802Sjkim         *
997167802Sjkim         * Note: Before the shift, check if the shift value will be larger than
998167802Sjkim         * the integer size. If so, there is no need to perform the operation.
999167802Sjkim         * This avoids the differences in behavior between different compilers
1000167802Sjkim         * concerning shift values larger than the target data width.
1001167802Sjkim         */
1002210976Sjkim        if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
1003210976Sjkim            ACPI_INTEGER_BIT_SIZE)
1004167802Sjkim        {
1005167802Sjkim            MergedDatum = RawDatum >>
1006210976Sjkim                (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
1007167802Sjkim        }
1008167802Sjkim        else
1009167802Sjkim        {
1010167802Sjkim            MergedDatum = 0;
1011167802Sjkim        }
1012167802Sjkim
1013167802Sjkim        Mask = WidthMask;
1014167802Sjkim
1015151937Sjkim        if (i == DatumCount)
101667754Smsmith        {
1017151937Sjkim            break;
101867754Smsmith        }
101977424Smsmith
1020151937Sjkim        /* Get the next input datum from the buffer */
102167754Smsmith
1022151937Sjkim        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1023151937Sjkim        ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
1024151937Sjkim            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1025210976Sjkim                 BufferLength - BufferOffset));
1026210976Sjkim
1027151937Sjkim        MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1028151937Sjkim    }
102967754Smsmith
1030151937Sjkim    /* Mask off any extra bits in the last datum */
103167754Smsmith
1032151937Sjkim    BufferTailBits = (ObjDesc->CommonField.BitLength +
1033210976Sjkim        ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
1034151937Sjkim    if (BufferTailBits)
1035151937Sjkim    {
1036151937Sjkim        Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1037151937Sjkim    }
1038123315Snjl
1039151937Sjkim    /* Write the last datum to the field */
104067754Smsmith
1041151937Sjkim    MergedDatum &= Mask;
1042151937Sjkim    Status = AcpiExWriteWithUpdateRule (ObjDesc,
1043151937Sjkim                Mask, MergedDatum, FieldOffset);
104467754Smsmith
1045193267SjkimExit:
1046193267Sjkim    /* Free temporary buffer if we used one */
1047193267Sjkim
1048193267Sjkim    if (NewBuffer)
1049193267Sjkim    {
1050193267Sjkim        ACPI_FREE (NewBuffer);
1051193267Sjkim    }
105267754Smsmith    return_ACPI_STATUS (Status);
105367754Smsmith}
1054