exfldio.c revision 114237
167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfldio - Aml Field I/O
4114237Snjl *              $Revision: 92 $
567754Smsmith *
667754Smsmith *****************************************************************************/
767754Smsmith
867754Smsmith/******************************************************************************
967754Smsmith *
1067754Smsmith * 1. Copyright Notice
1167754Smsmith *
12114237Snjl * Some or all of this work - Copyright (c) 1999 - 2003, Intel Corp.
1370243Smsmith * All rights reserved.
1467754Smsmith *
1567754Smsmith * 2. License
1667754Smsmith *
1767754Smsmith * 2.1. This is your license from Intel Corp. under its intellectual property
1867754Smsmith * rights.  You may have additional license terms from the party that provided
1967754Smsmith * you this software, covering your right to use that party's intellectual
2067754Smsmith * property rights.
2167754Smsmith *
2267754Smsmith * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
2367754Smsmith * copy of the source code appearing in this file ("Covered Code") an
2467754Smsmith * irrevocable, perpetual, worldwide license under Intel's copyrights in the
2567754Smsmith * base code distributed originally by Intel ("Original Intel Code") to copy,
2667754Smsmith * make derivatives, distribute, use and display any portion of the Covered
2767754Smsmith * Code in any form, with the right to sublicense such rights; and
2867754Smsmith *
2967754Smsmith * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
3067754Smsmith * license (with the right to sublicense), under only those claims of Intel
3167754Smsmith * patents that are infringed by the Original Intel Code, to make, use, sell,
3267754Smsmith * offer to sell, and import the Covered Code and derivative works thereof
3367754Smsmith * solely to the minimum extent necessary to exercise the above copyright
3467754Smsmith * license, and in no event shall the patent license extend to any additions
3567754Smsmith * to or modifications of the Original Intel Code.  No other license or right
3667754Smsmith * is granted directly or by implication, estoppel or otherwise;
3767754Smsmith *
3867754Smsmith * The above copyright and patent license is granted only if the following
3967754Smsmith * conditions are met:
4067754Smsmith *
4167754Smsmith * 3. Conditions
4267754Smsmith *
4367754Smsmith * 3.1. Redistribution of Source with Rights to Further Distribute Source.
4467754Smsmith * Redistribution of source code of any substantial portion of the Covered
4567754Smsmith * Code or modification with rights to further distribute source must include
4667754Smsmith * the above Copyright Notice, the above License, this list of Conditions,
4767754Smsmith * and the following Disclaimer and Export Compliance provision.  In addition,
4867754Smsmith * Licensee must cause all Covered Code to which Licensee contributes to
4967754Smsmith * contain a file documenting the changes Licensee made to create that Covered
5067754Smsmith * Code and the date of any change.  Licensee must include in that file the
5167754Smsmith * documentation of any changes made by any predecessor Licensee.  Licensee
5267754Smsmith * must include a prominent statement that the modification is derived,
5367754Smsmith * directly or indirectly, from Original Intel Code.
5467754Smsmith *
5567754Smsmith * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
5667754Smsmith * Redistribution of source code of any substantial portion of the Covered
5767754Smsmith * Code or modification without rights to further distribute source must
5867754Smsmith * include the following Disclaimer and Export Compliance provision in the
5967754Smsmith * documentation and/or other materials provided with distribution.  In
6067754Smsmith * addition, Licensee may not authorize further sublicense of source of any
6167754Smsmith * portion of the Covered Code, and must include terms to the effect that the
6267754Smsmith * license from Licensee to its licensee is limited to the intellectual
6367754Smsmith * property embodied in the software Licensee provides to its licensee, and
6467754Smsmith * not to intellectual property embodied in modifications its licensee may
6567754Smsmith * make.
6667754Smsmith *
6767754Smsmith * 3.3. Redistribution of Executable. Redistribution in executable form of any
6867754Smsmith * substantial portion of the Covered Code or modification must reproduce the
6967754Smsmith * above Copyright Notice, and the following Disclaimer and Export Compliance
7067754Smsmith * provision in the documentation and/or other materials provided with the
7167754Smsmith * distribution.
7267754Smsmith *
7367754Smsmith * 3.4. Intel retains all right, title, and interest in and to the Original
7467754Smsmith * Intel Code.
7567754Smsmith *
7667754Smsmith * 3.5. Neither the name Intel nor any other trademark owned or controlled by
7767754Smsmith * Intel shall be used in advertising or otherwise to promote the sale, use or
7867754Smsmith * other dealings in products derived from or relating to the Covered Code
7967754Smsmith * without prior written authorization from Intel.
8067754Smsmith *
8167754Smsmith * 4. Disclaimer and Export Compliance
8267754Smsmith *
8367754Smsmith * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
8467754Smsmith * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
8567754Smsmith * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
8667754Smsmith * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
8767754Smsmith * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
8867754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
8967754Smsmith * PARTICULAR PURPOSE.
9067754Smsmith *
9167754Smsmith * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
9267754Smsmith * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
9367754Smsmith * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
9467754Smsmith * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
9567754Smsmith * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
9667754Smsmith * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
9767754Smsmith * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
9867754Smsmith * LIMITED REMEDY.
9967754Smsmith *
10067754Smsmith * 4.3. Licensee shall not export, either directly or indirectly, any of this
10167754Smsmith * software or system incorporating such software without first obtaining any
10267754Smsmith * required license or other approval from the U. S. Department of Commerce or
10367754Smsmith * any other agency or department of the United States Government.  In the
10467754Smsmith * event Licensee exports any such software from the United States or
10567754Smsmith * re-exports any such software from a foreign destination, Licensee shall
10667754Smsmith * ensure that the distribution and export/re-export of the software is in
10767754Smsmith * compliance with all laws, regulations, orders, or other restrictions of the
10867754Smsmith * U.S. Export Administration Regulations. Licensee agrees that neither it nor
10967754Smsmith * any of its subsidiaries will export/re-export any technical data, process,
11067754Smsmith * software, or service, directly or indirectly, to any country for which the
11167754Smsmith * United States government or any agency thereof requires an export license,
11267754Smsmith * other governmental approval, or letter of assurance, without first obtaining
11367754Smsmith * such license, approval or letter.
11467754Smsmith *
11567754Smsmith *****************************************************************************/
11667754Smsmith
11767754Smsmith
11877424Smsmith#define __EXFLDIO_C__
11967754Smsmith
12067754Smsmith#include "acpi.h"
12167754Smsmith#include "acinterp.h"
12267754Smsmith#include "amlcode.h"
12367754Smsmith#include "acevents.h"
12477424Smsmith#include "acdispat.h"
12567754Smsmith
12667754Smsmith
12777424Smsmith#define _COMPONENT          ACPI_EXECUTER
12891116Smsmith        ACPI_MODULE_NAME    ("exfldio")
12967754Smsmith
13067754Smsmith
13167754Smsmith/*******************************************************************************
13267754Smsmith *
13387031Smsmith * FUNCTION:    AcpiExSetupRegion
13467754Smsmith *
13587031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read or written
13687031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
13787031Smsmith *                                        parent field
13867754Smsmith *
13967754Smsmith * RETURN:      Status
14067754Smsmith *
14177424Smsmith * DESCRIPTION: Common processing for AcpiExExtractFromField and
14287031Smsmith *              AcpiExInsertIntoField.  Initialize the
14367754Smsmith *
14467754Smsmith ******************************************************************************/
14567754Smsmith
14667754SmsmithACPI_STATUS
14787031SmsmithAcpiExSetupRegion (
14867754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
14977424Smsmith    UINT32                  FieldDatumByteOffset)
15067754Smsmith{
15177424Smsmith    ACPI_STATUS             Status = AE_OK;
15277424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
15367754Smsmith
15467754Smsmith
15591116Smsmith    ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
15667754Smsmith
15783174Smsmith
15877424Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
15967754Smsmith
160107325Siwasaki    /* We must have a valid region */
161107325Siwasaki
16299679Siwasaki    if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
16377424Smsmith    {
16499679Siwasaki        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
165102550Siwasaki            ACPI_GET_OBJECT_TYPE (RgnDesc),
16699679Siwasaki            AcpiUtGetObjectTypeName (RgnDesc)));
16799679Siwasaki
16877424Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
16977424Smsmith    }
17067754Smsmith
17177424Smsmith    /*
17277424Smsmith     * If the Region Address and Length have not been previously evaluated,
17377424Smsmith     * evaluate them now and save the results.
17477424Smsmith     */
17577424Smsmith    if (!(RgnDesc->Region.Flags & AOPOBJ_DATA_VALID))
17667754Smsmith    {
17777424Smsmith        Status = AcpiDsGetRegionArguments (RgnDesc);
17877424Smsmith        if (ACPI_FAILURE (Status))
17977424Smsmith        {
18077424Smsmith            return_ACPI_STATUS (Status);
18177424Smsmith        }
18267754Smsmith    }
18367754Smsmith
184107325Siwasaki    if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
185107325Siwasaki    {
186107325Siwasaki        /* SMBus has a non-linear address space */
187107325Siwasaki
188107325Siwasaki        return_ACPI_STATUS (AE_OK);
189107325Siwasaki    }
190107325Siwasaki
19177424Smsmith    /*
19277424Smsmith     * Validate the request.  The entire request from the byte offset for a
19377424Smsmith     * length of one field datum (access width) must fit within the region.
19477424Smsmith     * (Region length is specified in bytes)
19577424Smsmith     */
19687031Smsmith    if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset
19787031Smsmith                                    + FieldDatumByteOffset
19887031Smsmith                                    + ObjDesc->CommonField.AccessByteWidth))
19977424Smsmith    {
20077424Smsmith        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
20177424Smsmith        {
20283174Smsmith            /*
20377424Smsmith             * This is the case where the AccessType (AccWord, etc.) is wider
20477424Smsmith             * than the region itself.  For example, a region of length one
20577424Smsmith             * byte, and a field with Dword access specified.
20677424Smsmith             */
20782367Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
20891116Smsmith                "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
20999679Siwasaki                ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.AccessByteWidth,
21099679Siwasaki                RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length));
21177424Smsmith        }
21277424Smsmith
21377424Smsmith        /*
21477424Smsmith         * Offset rounded up to next multiple of field width
21577424Smsmith         * exceeds region length, indicate an error
21677424Smsmith         */
21782367Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
21891116Smsmith            "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
21999679Siwasaki            ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.BaseByteOffset,
22091116Smsmith            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
22199679Siwasaki            RgnDesc->Region.Node->Name.Ascii, 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 *
23487031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read
23587031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
23687031Smsmith *                                        parent field
237107325Siwasaki *              *Value                  - Where to store value (must at least
238107325Siwasaki *                                        the size of ACPI_INTEGER)
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,
25287031Smsmith    ACPI_INTEGER            *Value,
253107325Siwasaki    UINT32                  Function)
25477424Smsmith{
25577424Smsmith    ACPI_STATUS             Status;
25677424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
25777424Smsmith    ACPI_PHYSICAL_ADDRESS   Address;
25877424Smsmith
25977424Smsmith
26099146Siwasaki    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;
28187031Smsmith    Address = RgnDesc->Region.Address
28287031Smsmith                + ObjDesc->CommonField.BaseByteOffset
28387031Smsmith                + 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,
29591116Smsmith        " Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n",
29687031Smsmith        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
29787031Smsmith        RgnDesc->Region.SpaceId,
29891116Smsmith        ObjDesc->CommonField.AccessByteWidth,
29987031Smsmith        ObjDesc->CommonField.BaseByteOffset,
30087031Smsmith        FieldDatumByteOffset,
30191116Smsmith        ACPI_HIDWORD (Address), ACPI_LODWORD (Address)));
30267754Smsmith
30387031Smsmith    /* Invoke the appropriate AddressSpace/OpRegion handler */
30477424Smsmith
305107325Siwasaki    Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function,
30691116Smsmith                    Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
30787031Smsmith
30887031Smsmith    if (ACPI_FAILURE (Status))
30987031Smsmith    {
31087031Smsmith        if (Status == AE_NOT_IMPLEMENTED)
31187031Smsmith        {
31287031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
31387031Smsmith                "Region %s(%X) not implemented\n",
31487031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
31587031Smsmith                RgnDesc->Region.SpaceId));
31687031Smsmith        }
31787031Smsmith        else if (Status == AE_NOT_EXIST)
31887031Smsmith        {
31987031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
32087031Smsmith                "Region %s(%X) has no handler\n",
32187031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
32287031Smsmith                RgnDesc->Region.SpaceId));
32387031Smsmith        }
32487031Smsmith    }
32587031Smsmith
32687031Smsmith    return_ACPI_STATUS (Status);
32787031Smsmith}
32887031Smsmith
32987031Smsmith
33087031Smsmith/*******************************************************************************
33187031Smsmith *
33287031Smsmith * FUNCTION:    AcpiExRegisterOverflow
33387031Smsmith *
33487031Smsmith * PARAMETERS:  *ObjDesc                - Register(Field) to be written
33587031Smsmith *              Value                   - Value to be stored
33687031Smsmith *
33787031Smsmith * RETURN:      TRUE if value overflows the field, FALSE otherwise
33887031Smsmith *
33987031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written.
34087031Smsmith *              Used to check if the values written to Index and Bank registers
34187031Smsmith *              are out of range.  Normally, the value is simply truncated
34287031Smsmith *              to fit the field, but this case is most likely a serious
34387031Smsmith *              coding error in the ASL.
34487031Smsmith *
34587031Smsmith ******************************************************************************/
34687031Smsmith
34787031SmsmithBOOLEAN
34887031SmsmithAcpiExRegisterOverflow (
34987031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
35087031Smsmith    ACPI_INTEGER            Value)
35187031Smsmith{
35287031Smsmith
35391116Smsmith    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
35491116Smsmith    {
35591116Smsmith        /*
35691116Smsmith         * The field is large enough to hold the maximum integer, so we can
35791116Smsmith         * never overflow it.
35891116Smsmith         */
35991116Smsmith        return (FALSE);
36091116Smsmith    }
36191116Smsmith
36299679Siwasaki    if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
36387031Smsmith    {
36491116Smsmith        /*
36591116Smsmith         * The Value is larger than the maximum value that can fit into
36691116Smsmith         * the register.
36791116Smsmith         */
36887031Smsmith        return (TRUE);
36987031Smsmith    }
37087031Smsmith
37191116Smsmith    /* The Value will fit into the field with no truncation */
37291116Smsmith
37387031Smsmith    return (FALSE);
37487031Smsmith}
37587031Smsmith
37687031Smsmith
37787031Smsmith/*******************************************************************************
37887031Smsmith *
37987031Smsmith * FUNCTION:    AcpiExFieldDatumIo
38087031Smsmith *
38187031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read
38287031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
38387031Smsmith *                                        parent field
38487031Smsmith *              *Value                  - Where to store value (must be 64 bits)
38587031Smsmith *              ReadWrite               - Read or Write flag
38687031Smsmith *
38787031Smsmith * RETURN:      Status
38887031Smsmith *
38987031Smsmith * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
39087031Smsmith *              demultiplexed here to handle the different types of fields
39187031Smsmith *              (BufferField, RegionField, IndexField, BankField)
39287031Smsmith *
39387031Smsmith ******************************************************************************/
39487031Smsmith
39587031SmsmithACPI_STATUS
39687031SmsmithAcpiExFieldDatumIo (
39787031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
39887031Smsmith    UINT32                  FieldDatumByteOffset,
39987031Smsmith    ACPI_INTEGER            *Value,
40087031Smsmith    UINT32                  ReadWrite)
40187031Smsmith{
40287031Smsmith    ACPI_STATUS             Status;
40387031Smsmith    ACPI_INTEGER            LocalValue;
40487031Smsmith
40587031Smsmith
40691116Smsmith    ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
40787031Smsmith
40887031Smsmith
40987031Smsmith    if (ReadWrite == ACPI_READ)
41087031Smsmith    {
41187031Smsmith        if (!Value)
41287031Smsmith        {
41387031Smsmith            LocalValue = 0;
41487031Smsmith            Value = &LocalValue;  /* To support reads without saving return value */
41587031Smsmith        }
41687031Smsmith
41787031Smsmith        /* Clear the entire return buffer first, [Very Important!] */
41887031Smsmith
41987031Smsmith        *Value = 0;
42087031Smsmith    }
42187031Smsmith
42287031Smsmith    /*
42387031Smsmith     * The four types of fields are:
42487031Smsmith     *
42587031Smsmith     * BufferFields - Read/write from/to a Buffer
42687031Smsmith     * RegionFields - Read/write from/to a Operation Region.
42787031Smsmith     * BankFields   - Write to a Bank Register, then read/write from/to an OpRegion
42887031Smsmith     * IndexFields  - Write to an Index Register, then read/write from/to a Data Register
42987031Smsmith     */
43099679Siwasaki    switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
43177424Smsmith    {
43277424Smsmith    case ACPI_TYPE_BUFFER_FIELD:
43377424Smsmith        /*
43487031Smsmith         * If the BufferField arguments have not been previously evaluated,
43587031Smsmith         * evaluate them now and save the results.
43677424Smsmith         */
43787031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
43887031Smsmith        {
43987031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
44087031Smsmith            if (ACPI_FAILURE (Status))
44187031Smsmith            {
44287031Smsmith                return_ACPI_STATUS (Status);
44387031Smsmith            }
44487031Smsmith        }
44587031Smsmith
44687031Smsmith        if (ReadWrite == ACPI_READ)
44787031Smsmith        {
44887031Smsmith            /*
44987031Smsmith             * Copy the data from the source buffer.
45087031Smsmith             * Length is the field width in bytes.
45187031Smsmith             */
45291116Smsmith            ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
45387031Smsmith                            + ObjDesc->BufferField.BaseByteOffset
45487031Smsmith                            + FieldDatumByteOffset,
45587031Smsmith                            ObjDesc->CommonField.AccessByteWidth);
45687031Smsmith        }
45787031Smsmith        else
45887031Smsmith        {
45987031Smsmith            /*
46087031Smsmith             * Copy the data to the target buffer.
46187031Smsmith             * Length is the field width in bytes.
46287031Smsmith             */
46391116Smsmith            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
46487031Smsmith                    + ObjDesc->BufferField.BaseByteOffset
46587031Smsmith                    + FieldDatumByteOffset,
46687031Smsmith                    Value, ObjDesc->CommonField.AccessByteWidth);
46787031Smsmith        }
46887031Smsmith
46977424Smsmith        Status = AE_OK;
47077424Smsmith        break;
47167754Smsmith
47267754Smsmith
473107325Siwasaki    case ACPI_TYPE_LOCAL_BANK_FIELD:
47467754Smsmith
47587031Smsmith        /* Ensure that the BankValue is not beyond the capacity of the register */
47687031Smsmith
47787031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
47899679Siwasaki                                    (ACPI_INTEGER) ObjDesc->BankField.Value))
47987031Smsmith        {
48087031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
48187031Smsmith        }
48287031Smsmith
48377424Smsmith        /*
48487031Smsmith         * For BankFields, we must write the BankValue to the BankRegister
48587031Smsmith         * (itself a RegionField) before we can access the data.
48677424Smsmith         */
48787031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
48887031Smsmith                                &ObjDesc->BankField.Value,
48987031Smsmith                                sizeof (ObjDesc->BankField.Value));
49077424Smsmith        if (ACPI_FAILURE (Status))
49177424Smsmith        {
49277424Smsmith            return_ACPI_STATUS (Status);
49377424Smsmith        }
49467754Smsmith
49577424Smsmith        /*
49687031Smsmith         * Now that the Bank has been selected, fall through to the
49787031Smsmith         * RegionField case and write the datum to the Operation Region
49877424Smsmith         */
49977424Smsmith
50099679Siwasaki        /*lint -fallthrough */
50177424Smsmith
50277424Smsmith
503107325Siwasaki    case ACPI_TYPE_LOCAL_REGION_FIELD:
50487031Smsmith        /*
50587031Smsmith         * For simple RegionFields, we just directly access the owning
50687031Smsmith         * Operation Region.
50787031Smsmith         */
50887031Smsmith        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
50987031Smsmith                        ReadWrite);
51087031Smsmith        break;
51187031Smsmith
51287031Smsmith
513107325Siwasaki    case ACPI_TYPE_LOCAL_INDEX_FIELD:
51487031Smsmith
51587031Smsmith
51687031Smsmith        /* Ensure that the IndexValue is not beyond the capacity of the register */
51787031Smsmith
51887031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
51999679Siwasaki                                    (ACPI_INTEGER) ObjDesc->IndexField.Value))
52077424Smsmith        {
52187031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
52277424Smsmith        }
52387031Smsmith
52487031Smsmith        /* Write the index value to the IndexRegister (itself a RegionField) */
52587031Smsmith
52687031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
52787031Smsmith                                &ObjDesc->IndexField.Value,
52887031Smsmith                                sizeof (ObjDesc->IndexField.Value));
52987031Smsmith        if (ACPI_FAILURE (Status))
53087031Smsmith        {
53187031Smsmith            return_ACPI_STATUS (Status);
53287031Smsmith        }
53387031Smsmith
53487031Smsmith        if (ReadWrite == ACPI_READ)
53587031Smsmith        {
53687031Smsmith            /* Read the datum from the DataRegister */
53787031Smsmith
53887031Smsmith            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
53987031Smsmith                            Value, ObjDesc->CommonField.AccessByteWidth);
54087031Smsmith        }
54187031Smsmith        else
54287031Smsmith        {
54387031Smsmith            /* Write the datum to the Data register */
54487031Smsmith
54587031Smsmith            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
54687031Smsmith                            Value, ObjDesc->CommonField.AccessByteWidth);
54787031Smsmith        }
54877424Smsmith        break;
54977424Smsmith
55077424Smsmith
55177424Smsmith    default:
55277424Smsmith
55387031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",
55499679Siwasaki            ObjDesc, AcpiUtGetObjectTypeName (ObjDesc)));
55577424Smsmith        Status = AE_AML_INTERNAL;
55677424Smsmith        break;
55767754Smsmith    }
55867754Smsmith
55987031Smsmith    if (ACPI_SUCCESS (Status))
56087031Smsmith    {
56187031Smsmith        if (ReadWrite == ACPI_READ)
56287031Smsmith        {
56387031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",
56491116Smsmith                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
56587031Smsmith        }
56687031Smsmith        else
56787031Smsmith        {
56887031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",
56991116Smsmith                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
57087031Smsmith        }
57187031Smsmith    }
57277424Smsmith
57387031Smsmith    return_ACPI_STATUS (Status);
57487031Smsmith}
57577424Smsmith
57687031Smsmith
57787031Smsmith/*******************************************************************************
57887031Smsmith *
57987031Smsmith * FUNCTION:    AcpiExWriteWithUpdateRule
58087031Smsmith *
58187031Smsmith * PARAMETERS:  *ObjDesc            - Field to be set
58287031Smsmith *              Value               - Value to store
58387031Smsmith *
58487031Smsmith * RETURN:      Status
58587031Smsmith *
58687031Smsmith * DESCRIPTION: Apply the field update rule to a field write
58787031Smsmith *
58887031Smsmith ******************************************************************************/
58987031Smsmith
59087031SmsmithACPI_STATUS
59187031SmsmithAcpiExWriteWithUpdateRule (
59287031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
59387031Smsmith    ACPI_INTEGER            Mask,
59487031Smsmith    ACPI_INTEGER            FieldValue,
59587031Smsmith    UINT32                  FieldDatumByteOffset)
59687031Smsmith{
59787031Smsmith    ACPI_STATUS             Status = AE_OK;
59887031Smsmith    ACPI_INTEGER            MergedValue;
59987031Smsmith    ACPI_INTEGER            CurrentValue;
60087031Smsmith
60187031Smsmith
60291116Smsmith    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
60387031Smsmith
60487031Smsmith
60587031Smsmith    /* Start with the new bits  */
60687031Smsmith
60787031Smsmith    MergedValue = FieldValue;
60887031Smsmith
60987031Smsmith    /* If the mask is all ones, we don't need to worry about the update rule */
61087031Smsmith
61199679Siwasaki    if (Mask != ACPI_INTEGER_MAX)
61287031Smsmith    {
61387031Smsmith        /* Decode the update rule */
61487031Smsmith
61587031Smsmith        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
61687031Smsmith        {
61787031Smsmith        case AML_FIELD_UPDATE_PRESERVE:
61887031Smsmith            /*
61987031Smsmith             * Check if update rule needs to be applied (not if mask is all
62087031Smsmith             * ones)  The left shift drops the bits we want to ignore.
62187031Smsmith             */
62291116Smsmith            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
62391116Smsmith                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
62487031Smsmith            {
62587031Smsmith                /*
62687031Smsmith                 * Read the current contents of the byte/word/dword containing
62787031Smsmith                 * the field, and merge with the new field value.
62887031Smsmith                 */
62987031Smsmith                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
63087031Smsmith                                &CurrentValue, ACPI_READ);
63187031Smsmith                MergedValue |= (CurrentValue & ~Mask);
63287031Smsmith            }
63387031Smsmith            break;
63487031Smsmith
63587031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ONES:
63687031Smsmith
63787031Smsmith            /* Set positions outside the field to all ones */
63887031Smsmith
63987031Smsmith            MergedValue |= ~Mask;
64087031Smsmith            break;
64187031Smsmith
64287031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
64387031Smsmith
64487031Smsmith            /* Set positions outside the field to all zeros */
64587031Smsmith
64687031Smsmith            MergedValue &= Mask;
64787031Smsmith            break;
64887031Smsmith
64987031Smsmith        default:
65087031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
65199679Siwasaki                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
65287031Smsmith                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
65387031Smsmith            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
65487031Smsmith        }
65587031Smsmith    }
65687031Smsmith
65787031Smsmith    /* Write the merged value */
65887031Smsmith
65987031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
66087031Smsmith                    &MergedValue, ACPI_WRITE);
66187031Smsmith
66287031Smsmith    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
66387031Smsmith        "Mask %8.8X%8.8X DatumOffset %X Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
66491116Smsmith        ACPI_HIDWORD (Mask), ACPI_LODWORD (Mask),
66587031Smsmith        FieldDatumByteOffset,
66691116Smsmith        ACPI_HIDWORD (FieldValue), ACPI_LODWORD (FieldValue),
66791116Smsmith        ACPI_HIDWORD (MergedValue),ACPI_LODWORD (MergedValue)));
66887031Smsmith
66977424Smsmith    return_ACPI_STATUS (Status);
67077424Smsmith}
67177424Smsmith
67277424Smsmith
67377424Smsmith/*******************************************************************************
67477424Smsmith *
67577424Smsmith * FUNCTION:    AcpiExGetBufferDatum
67677424Smsmith *
67787031Smsmith * PARAMETERS:  Datum               - Where the Datum is returned
67887031Smsmith *              Buffer              - Raw field buffer
67987031Smsmith *              ByteGranularity     - 1/2/4/8 Granularity of the field
68077424Smsmith *                                    (aka Datum Size)
68177424Smsmith *              Offset              - Datum offset into the buffer
68283174Smsmith *
68377424Smsmith * RETURN:      none
68477424Smsmith *
68587031Smsmith * DESCRIPTION: Get a datum from the buffer according to the buffer field
68677424Smsmith *              byte granularity
68777424Smsmith *
68877424Smsmith ******************************************************************************/
68977424Smsmith
69087031Smsmithvoid
69177424SmsmithAcpiExGetBufferDatum(
69287031Smsmith    ACPI_INTEGER            *Datum,
69377424Smsmith    void                    *Buffer,
69477424Smsmith    UINT32                  ByteGranularity,
69577424Smsmith    UINT32                  Offset)
69677424Smsmith{
69777424Smsmith
69891116Smsmith    ACPI_FUNCTION_ENTRY ();
69983174Smsmith
70083174Smsmith
70177424Smsmith    switch (ByteGranularity)
70267754Smsmith    {
70377424Smsmith    case ACPI_FIELD_BYTE_GRANULARITY:
70491116Smsmith
70577424Smsmith        *Datum = ((UINT8 *) Buffer) [Offset];
70677424Smsmith        break;
70777424Smsmith
70877424Smsmith    case ACPI_FIELD_WORD_GRANULARITY:
70991116Smsmith
71091116Smsmith        ACPI_MOVE_UNALIGNED16_TO_32 (Datum, &(((UINT16 *) Buffer) [Offset]));
71177424Smsmith        break;
71277424Smsmith
71377424Smsmith    case ACPI_FIELD_DWORD_GRANULARITY:
71491116Smsmith
71591116Smsmith        ACPI_MOVE_UNALIGNED32_TO_32 (Datum, &(((UINT32 *) Buffer) [Offset]));
71677424Smsmith        break;
71787031Smsmith
71887031Smsmith    case ACPI_FIELD_QWORD_GRANULARITY:
71991116Smsmith
72091116Smsmith        ACPI_MOVE_UNALIGNED64_TO_64 (Datum, &(((UINT64 *) Buffer) [Offset]));
72187031Smsmith        break;
72299679Siwasaki
72399679Siwasaki    default:
72499679Siwasaki        /* Should not get here */
72599679Siwasaki        break;
72667754Smsmith    }
72777424Smsmith}
72867754Smsmith
72967754Smsmith
73077424Smsmith/*******************************************************************************
73177424Smsmith *
73283174Smsmith * FUNCTION:    AcpiExSetBufferDatum
73377424Smsmith *
73477424Smsmith * PARAMETERS:  MergedDatum         - Value to store
73577424Smsmith *              Buffer              - Receiving buffer
73687031Smsmith *              ByteGranularity     - 1/2/4/8 Granularity of the field
73777424Smsmith *                                    (aka Datum Size)
73877424Smsmith *              Offset              - Datum offset into the buffer
73983174Smsmith *
74077424Smsmith * RETURN:      none
74177424Smsmith *
74277424Smsmith * DESCRIPTION: Store the merged datum to the buffer according to the
74377424Smsmith *              byte granularity
74477424Smsmith *
74577424Smsmith ******************************************************************************/
74677424Smsmith
74787031Smsmithvoid
74877424SmsmithAcpiExSetBufferDatum (
74987031Smsmith    ACPI_INTEGER            MergedDatum,
75077424Smsmith    void                    *Buffer,
75177424Smsmith    UINT32                  ByteGranularity,
75277424Smsmith    UINT32                  Offset)
75377424Smsmith{
75477424Smsmith
75591116Smsmith    ACPI_FUNCTION_ENTRY ();
75683174Smsmith
75783174Smsmith
75877424Smsmith    switch (ByteGranularity)
75977424Smsmith    {
76077424Smsmith    case ACPI_FIELD_BYTE_GRANULARITY:
76191116Smsmith
76277424Smsmith        ((UINT8 *) Buffer) [Offset] = (UINT8) MergedDatum;
76377424Smsmith        break;
76477424Smsmith
76577424Smsmith    case ACPI_FIELD_WORD_GRANULARITY:
76691116Smsmith
76791116Smsmith        ACPI_MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[Offset]), &MergedDatum);
76877424Smsmith        break;
76977424Smsmith
77077424Smsmith    case ACPI_FIELD_DWORD_GRANULARITY:
77191116Smsmith
77291116Smsmith        ACPI_MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[Offset]), &MergedDatum);
77377424Smsmith        break;
77487031Smsmith
77587031Smsmith    case ACPI_FIELD_QWORD_GRANULARITY:
77691116Smsmith
77791116Smsmith        ACPI_MOVE_UNALIGNED64_TO_64 (&(((UINT64 *) Buffer)[Offset]), &MergedDatum);
77887031Smsmith        break;
77999679Siwasaki
78099679Siwasaki    default:
78199679Siwasaki        /* Should not get here */
78299679Siwasaki        break;
78377424Smsmith    }
78467754Smsmith}
78567754Smsmith
78667754Smsmith
78767754Smsmith/*******************************************************************************
78867754Smsmith *
78977424Smsmith * FUNCTION:    AcpiExExtractFromField
79067754Smsmith *
79167754Smsmith * PARAMETERS:  *ObjDesc            - Field to be read
79267754Smsmith *              *Value              - Where to store value
79367754Smsmith *
79467754Smsmith * RETURN:      Status
79567754Smsmith *
79667754Smsmith * DESCRIPTION: Retrieve the value of the given field
79767754Smsmith *
79867754Smsmith ******************************************************************************/
79967754Smsmith
80067754SmsmithACPI_STATUS
80177424SmsmithAcpiExExtractFromField (
80267754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
80367754Smsmith    void                    *Buffer,
80477424Smsmith    UINT32                  BufferLength)
80567754Smsmith{
80667754Smsmith    ACPI_STATUS             Status;
80777424Smsmith    UINT32                  FieldDatumByteOffset;
80877424Smsmith    UINT32                  DatumOffset;
80987031Smsmith    ACPI_INTEGER            PreviousRawDatum;
81087031Smsmith    ACPI_INTEGER            ThisRawDatum = 0;
81187031Smsmith    ACPI_INTEGER            MergedDatum = 0;
81277424Smsmith    UINT32                  ByteFieldLength;
81377424Smsmith    UINT32                  DatumCount;
81467754Smsmith
81567754Smsmith
81691116Smsmith    ACPI_FUNCTION_TRACE ("ExExtractFromField");
81767754Smsmith
81877424Smsmith
81967754Smsmith    /*
82077424Smsmith     * The field must fit within the caller's buffer
82177424Smsmith     */
82291116Smsmith    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
82377424Smsmith    if (ByteFieldLength > BufferLength)
82477424Smsmith    {
82599146Siwasaki        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
82687031Smsmith            "Field size %X (bytes) too large for buffer (%X)\n",
82777424Smsmith            ByteFieldLength, BufferLength));
82877424Smsmith
82977424Smsmith        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
83077424Smsmith    }
83177424Smsmith
83277424Smsmith    /* Convert field byte count to datum count, round up if necessary */
83377424Smsmith
83491116Smsmith    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
83587031Smsmith                              ObjDesc->CommonField.AccessByteWidth);
83677424Smsmith
83799146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
83899679Siwasaki        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
83991116Smsmith        ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth));
84077424Smsmith
84177424Smsmith    /*
84267754Smsmith     * Clear the caller's buffer (the whole buffer length as given)
84367754Smsmith     * This is very important, especially in the cases where a byte is read,
84467754Smsmith     * but the buffer is really a UINT32 (4 bytes).
84567754Smsmith     */
84691116Smsmith    ACPI_MEMSET (Buffer, 0, BufferLength);
84767754Smsmith
84867754Smsmith    /* Read the first raw datum to prime the loop */
84967754Smsmith
85077424Smsmith    FieldDatumByteOffset = 0;
85177424Smsmith    DatumOffset= 0;
85267754Smsmith
85387031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
85487031Smsmith                    &PreviousRawDatum, ACPI_READ);
85567754Smsmith    if (ACPI_FAILURE (Status))
85667754Smsmith    {
85777424Smsmith        return_ACPI_STATUS (Status);
85867754Smsmith    }
85967754Smsmith
86077424Smsmith
86167754Smsmith    /* We might actually be done if the request fits in one datum */
86267754Smsmith
86377424Smsmith    if ((DatumCount == 1) &&
86487031Smsmith        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
86567754Smsmith    {
86677424Smsmith        /* 1) Shift the valid data bits down to start at bit 0 */
86767754Smsmith
86877424Smsmith        MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
86967754Smsmith
87077424Smsmith        /* 2) Mask off any upper unused bits (bits not part of the field) */
87177424Smsmith
87277424Smsmith        if (ObjDesc->CommonField.EndBufferValidBits)
87367754Smsmith        {
87491116Smsmith            MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
87567754Smsmith        }
87667754Smsmith
87777424Smsmith        /* Store the datum to the caller buffer */
87867754Smsmith
87983174Smsmith        AcpiExSetBufferDatum (MergedDatum, Buffer, ObjDesc->CommonField.AccessByteWidth,
88077424Smsmith                DatumOffset);
88167754Smsmith
88277424Smsmith        return_ACPI_STATUS (AE_OK);
88377424Smsmith    }
88467754Smsmith
88567754Smsmith
88677424Smsmith    /* We need to get more raw data to complete one or more field data */
88767754Smsmith
88877424Smsmith    while (DatumOffset < DatumCount)
88967754Smsmith    {
89077424Smsmith        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
89167754Smsmith
89277424Smsmith        /*
89377424Smsmith         * If the field is aligned on a byte boundary, we don't want
89477424Smsmith         * to perform a final read, since this would potentially read
89577424Smsmith         * past the end of the region.
89677424Smsmith         *
89791116Smsmith         * We could just split the aligned and non-aligned cases since the
89887031Smsmith         * aligned case is so very simple, but this would require more code.
89977424Smsmith         */
90087031Smsmith        if ((ObjDesc->CommonField.StartFieldBitOffset != 0)  ||
90187031Smsmith            ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
90277424Smsmith            (DatumOffset < (DatumCount -1))))
90367754Smsmith        {
90467754Smsmith            /*
90577424Smsmith             * Get the next raw datum, it contains some or all bits
90677424Smsmith             * of the current field datum
90767754Smsmith             */
90887031Smsmith            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
90987031Smsmith                            &ThisRawDatum, ACPI_READ);
91077424Smsmith            if (ACPI_FAILURE (Status))
91167754Smsmith            {
91277424Smsmith                return_ACPI_STATUS (Status);
91367754Smsmith            }
91477424Smsmith        }
91567754Smsmith
91677424Smsmith        /*
91777424Smsmith         * Create the (possibly) merged datum to be stored to the caller buffer
91877424Smsmith         */
91977424Smsmith        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
92077424Smsmith        {
92177424Smsmith            /* Field is not skewed and we can just copy the datum */
92271867Smsmith
92377424Smsmith            MergedDatum = PreviousRawDatum;
92477424Smsmith        }
92577424Smsmith        else
92677424Smsmith        {
92767754Smsmith            /*
92883174Smsmith             * Put together the appropriate bits of the two raw data to make a
92977424Smsmith             * single complete field datum
93077424Smsmith             *
93183174Smsmith             * 1) Normalize the first datum down to bit 0
93267754Smsmith             */
93377424Smsmith            MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
93467754Smsmith
93577424Smsmith            /* 2) Insert the second datum "above" the first datum */
93667754Smsmith
93777424Smsmith            MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
93883174Smsmith
93977424Smsmith            if ((DatumOffset >= (DatumCount -1)))
94067754Smsmith            {
94177424Smsmith                /*
94277424Smsmith                 * This is the last iteration of the loop.  We need to clear
94383174Smsmith                 * any unused bits (bits that are not part of this field) that
94483174Smsmith                 * came from the last raw datum before we store the final
94577424Smsmith                 * merged datum into the caller buffer.
94677424Smsmith                 */
94777424Smsmith                if (ObjDesc->CommonField.EndBufferValidBits)
94877424Smsmith                {
94983174Smsmith                    MergedDatum &=
95091116Smsmith                        ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
95177424Smsmith                }
95267754Smsmith            }
95377424Smsmith        }
95467754Smsmith
95577424Smsmith        /*
95677424Smsmith         * Store the merged field datum in the caller's buffer, according to
95777424Smsmith         * the granularity of the field (size of each datum).
95877424Smsmith         */
95991116Smsmith        AcpiExSetBufferDatum (MergedDatum, Buffer,
96087031Smsmith                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
96167754Smsmith
96277424Smsmith        /*
96383174Smsmith         * Save the raw datum that was just acquired since it may contain bits
96477424Smsmith         * of the *next* field datum.  Update offsets
96577424Smsmith         */
96677424Smsmith        PreviousRawDatum = ThisRawDatum;
96777424Smsmith        DatumOffset++;
96867754Smsmith    }
96967754Smsmith
97077424Smsmith    return_ACPI_STATUS (AE_OK);
97167754Smsmith}
97267754Smsmith
97367754Smsmith
97467754Smsmith/*******************************************************************************
97567754Smsmith *
97677424Smsmith * FUNCTION:    AcpiExInsertIntoField
97767754Smsmith *
97867754Smsmith * PARAMETERS:  *ObjDesc            - Field to be set
97977424Smsmith *              Buffer              - Value to store
98067754Smsmith *
98167754Smsmith * RETURN:      Status
98267754Smsmith *
98367754Smsmith * DESCRIPTION: Store the value into the given field
98467754Smsmith *
98577424Smsmith ******************************************************************************/
98667754Smsmith
98767754SmsmithACPI_STATUS
98877424SmsmithAcpiExInsertIntoField (
98967754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
99067754Smsmith    void                    *Buffer,
99177424Smsmith    UINT32                  BufferLength)
99267754Smsmith{
99367754Smsmith    ACPI_STATUS             Status;
99477424Smsmith    UINT32                  FieldDatumByteOffset;
99577424Smsmith    UINT32                  DatumOffset;
99687031Smsmith    ACPI_INTEGER            Mask;
99787031Smsmith    ACPI_INTEGER            MergedDatum;
99887031Smsmith    ACPI_INTEGER            PreviousRawDatum;
99987031Smsmith    ACPI_INTEGER            ThisRawDatum;
100077424Smsmith    UINT32                  ByteFieldLength;
100177424Smsmith    UINT32                  DatumCount;
100267754Smsmith
100367754Smsmith
100491116Smsmith    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
100567754Smsmith
100667754Smsmith
100767754Smsmith    /*
100883174Smsmith     * Incoming buffer must be at least as long as the field, we do not
100977424Smsmith     * allow "partial" field writes.  We do not care if the buffer is
101077424Smsmith     * larger than the field, this typically happens when an integer is
101177424Smsmith     * written to a field that is actually smaller than an integer.
101267754Smsmith     */
101391116Smsmith    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
101477424Smsmith    if (BufferLength < ByteFieldLength)
101577424Smsmith    {
101699146Siwasaki        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n",
101777424Smsmith            BufferLength, ByteFieldLength));
101867754Smsmith
101977424Smsmith        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
102077424Smsmith    }
102167754Smsmith
102277424Smsmith    /* Convert byte count to datum count, round up if necessary */
102367754Smsmith
102491116Smsmith    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
102567754Smsmith
102699146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
102799679Siwasaki        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
102891116Smsmith        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth));
102967754Smsmith
103077424Smsmith    /*
103177424Smsmith     * Break the request into up to three parts (similar to an I/O request):
103277424Smsmith     * 1) non-aligned part at start
103377424Smsmith     * 2) aligned part in middle
103477424Smsmith     * 3) non-aligned part at the end
103577424Smsmith     */
103677424Smsmith    FieldDatumByteOffset = 0;
103777424Smsmith    DatumOffset= 0;
103867754Smsmith
103977424Smsmith    /* Get a single datum from the caller's buffer */
104077424Smsmith
104183174Smsmith    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer,
104277424Smsmith            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
104377424Smsmith
104467754Smsmith    /*
104577424Smsmith     * Part1:
104667754Smsmith     * Write a partial field datum if field does not begin on a datum boundary
104777424Smsmith     * Note: The code in this section also handles the aligned case
104867754Smsmith     *
104967754Smsmith     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
105077424Smsmith     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
105167754Smsmith     *
105277424Smsmith     * Mask off bits that are "below" the field (if any)
105367754Smsmith     */
105491116Smsmith    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
105567754Smsmith
105677424Smsmith    /* If the field fits in one datum, may need to mask upper bits */
105767754Smsmith
105887031Smsmith    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
105977424Smsmith         ObjDesc->CommonField.EndFieldValidBits)
106067754Smsmith    {
106177424Smsmith        /* There are bits above the field, mask them off also */
106267754Smsmith
106391116Smsmith        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
106467754Smsmith    }
106567754Smsmith
106677424Smsmith    /* Shift and mask the value into the field position */
106767754Smsmith
106877424Smsmith    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
106977424Smsmith    MergedDatum &= Mask;
107067754Smsmith
107177424Smsmith    /* Apply the update rule (if necessary) and write the datum to the field */
107277424Smsmith
107387031Smsmith    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
107477424Smsmith                        FieldDatumByteOffset);
107567754Smsmith    if (ACPI_FAILURE (Status))
107667754Smsmith    {
107777424Smsmith        return_ACPI_STATUS (Status);
107867754Smsmith    }
107967754Smsmith
108077424Smsmith    /* If the entire field fits within one datum, we are done. */
108167754Smsmith
108277424Smsmith    if ((DatumCount == 1) &&
108387031Smsmith       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
108467754Smsmith    {
108577424Smsmith        return_ACPI_STATUS (AE_OK);
108667754Smsmith    }
108767754Smsmith
108867754Smsmith    /*
108977424Smsmith     * Part2:
109077424Smsmith     * Write the aligned data.
109177424Smsmith     *
109267754Smsmith     * We don't need to worry about the update rule for these data, because
109377424Smsmith     * all of the bits in each datum are part of the field.
109467754Smsmith     *
109583174Smsmith     * The last datum must be special cased because it might contain bits
109683174Smsmith     * that are not part of the field -- therefore the "update rule" must be
109777424Smsmith     * applied in Part3 below.
109867754Smsmith     */
109977424Smsmith    while (DatumOffset < DatumCount)
110067754Smsmith    {
110177424Smsmith        DatumOffset++;
110277424Smsmith        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
110367754Smsmith
110483174Smsmith        /*
110583174Smsmith         * Get the next raw buffer datum.  It may contain bits of the previous
110677424Smsmith         * field datum
110777424Smsmith         */
110883174Smsmith        AcpiExGetBufferDatum (&ThisRawDatum, Buffer,
110977424Smsmith                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
111067754Smsmith
111177424Smsmith        /* Create the field datum based on the field alignment */
111267754Smsmith
111377424Smsmith        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
111467754Smsmith        {
111577424Smsmith            /*
111683174Smsmith             * Put together appropriate bits of the two raw buffer data to make
111777424Smsmith             * a single complete field datum
111877424Smsmith             */
111983174Smsmith            MergedDatum =
112077424Smsmith                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
112177424Smsmith                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
112267754Smsmith        }
112367754Smsmith        else
112467754Smsmith        {
112577424Smsmith            /* Field began aligned on datum boundary */
112677424Smsmith
112767754Smsmith            MergedDatum = ThisRawDatum;
112867754Smsmith        }
112967754Smsmith
113067754Smsmith        /*
113177424Smsmith         * Special handling for the last datum if the field does NOT end on
113277424Smsmith         * a datum boundary.  Update Rule must be applied to the bits outside
113377424Smsmith         * the field.
113467754Smsmith         */
113585756Smsmith        if (DatumOffset == DatumCount)
113677424Smsmith        {
113783174Smsmith            /*
113885756Smsmith             * If there are dangling non-aligned bits, perform one more merged write
113985756Smsmith             * Else - field is aligned at the end, no need for any more writes
114077424Smsmith             */
114185756Smsmith            if (ObjDesc->CommonField.EndFieldValidBits)
114285756Smsmith            {
114385756Smsmith                /*
114485756Smsmith                 * Part3:
114585756Smsmith                 * This is the last datum and the field does not end on a datum boundary.
114685756Smsmith                 * Build the partial datum and write with the update rule.
114785756Smsmith                 *
114885756Smsmith                 * Mask off the unused bits above (after) the end-of-field
114985756Smsmith                 */
115091116Smsmith                Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
115185756Smsmith                MergedDatum &= Mask;
115267754Smsmith
115385756Smsmith                /* Write the last datum with the update rule */
115467754Smsmith
115587031Smsmith                Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
115687031Smsmith                                    FieldDatumByteOffset);
115785756Smsmith                if (ACPI_FAILURE (Status))
115885756Smsmith                {
115985756Smsmith                    return_ACPI_STATUS (Status);
116085756Smsmith                }
116177424Smsmith            }
116277424Smsmith        }
116377424Smsmith        else
116467754Smsmith        {
116577424Smsmith            /* Normal case -- write the completed datum */
116667754Smsmith
116787031Smsmith            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
116887031Smsmith                            &MergedDatum, ACPI_WRITE);
116977424Smsmith            if (ACPI_FAILURE (Status))
117077424Smsmith            {
117177424Smsmith                return_ACPI_STATUS (Status);
117277424Smsmith            }
117367754Smsmith        }
117467754Smsmith
117577424Smsmith        /*
117683174Smsmith         * Save the most recent datum since it may contain bits of the *next*
117777424Smsmith         * field datum.  Update current byte offset.
117877424Smsmith         */
117977424Smsmith        PreviousRawDatum = ThisRawDatum;
118067754Smsmith    }
118167754Smsmith
118267754Smsmith    return_ACPI_STATUS (Status);
118367754Smsmith}
118467754Smsmith
118567754Smsmith
1186