exfldio.c revision 99679
167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfldio - Aml Field I/O
499679Siwasaki *              $Revision: 87 $
567754Smsmith *
667754Smsmith *****************************************************************************/
767754Smsmith
867754Smsmith/******************************************************************************
967754Smsmith *
1067754Smsmith * 1. Copyright Notice
1167754Smsmith *
1291116Smsmith * Some or all of this work - Copyright (c) 1999 - 2002, 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
16099679Siwasaki    if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
16177424Smsmith    {
16299679Siwasaki        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
16399679Siwasaki            ACPI_GET_OBJECT_TYPE (RgnDesc),
16499679Siwasaki            AcpiUtGetObjectTypeName (RgnDesc)));
16599679Siwasaki
16677424Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
16777424Smsmith    }
16867754Smsmith
16977424Smsmith    /*
17077424Smsmith     * If the Region Address and Length have not been previously evaluated,
17177424Smsmith     * evaluate them now and save the results.
17277424Smsmith     */
17377424Smsmith    if (!(RgnDesc->Region.Flags & AOPOBJ_DATA_VALID))
17467754Smsmith    {
17577424Smsmith        Status = AcpiDsGetRegionArguments (RgnDesc);
17677424Smsmith        if (ACPI_FAILURE (Status))
17777424Smsmith        {
17877424Smsmith            return_ACPI_STATUS (Status);
17977424Smsmith        }
18067754Smsmith    }
18167754Smsmith
18277424Smsmith    /*
18377424Smsmith     * Validate the request.  The entire request from the byte offset for a
18477424Smsmith     * length of one field datum (access width) must fit within the region.
18577424Smsmith     * (Region length is specified in bytes)
18677424Smsmith     */
18787031Smsmith    if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset
18887031Smsmith                                    + FieldDatumByteOffset
18987031Smsmith                                    + ObjDesc->CommonField.AccessByteWidth))
19077424Smsmith    {
19177424Smsmith        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
19277424Smsmith        {
19383174Smsmith            /*
19477424Smsmith             * This is the case where the AccessType (AccWord, etc.) is wider
19577424Smsmith             * than the region itself.  For example, a region of length one
19677424Smsmith             * byte, and a field with Dword access specified.
19777424Smsmith             */
19882367Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
19991116Smsmith                "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
20099679Siwasaki                ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.AccessByteWidth,
20199679Siwasaki                RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length));
20277424Smsmith        }
20377424Smsmith
20477424Smsmith        /*
20577424Smsmith         * Offset rounded up to next multiple of field width
20677424Smsmith         * exceeds region length, indicate an error
20777424Smsmith         */
20882367Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
20991116Smsmith            "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
21099679Siwasaki            ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.BaseByteOffset,
21191116Smsmith            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
21299679Siwasaki            RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length));
21377424Smsmith
21477424Smsmith        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
21577424Smsmith    }
21677424Smsmith
21777424Smsmith    return_ACPI_STATUS (AE_OK);
21877424Smsmith}
21977424Smsmith
22077424Smsmith
22177424Smsmith/*******************************************************************************
22277424Smsmith *
22387031Smsmith * FUNCTION:    AcpiExAccessRegion
22477424Smsmith *
22587031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read
22687031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
22787031Smsmith *                                        parent field
22887031Smsmith *              *Value                  - Where to store value (must be 32 bits)
22987031Smsmith *              ReadWrite               - Read or Write flag
23077424Smsmith *
23177424Smsmith * RETURN:      Status
23277424Smsmith *
23387031Smsmith * DESCRIPTION: Read or Write a single field datum to an Operation Region.
23477424Smsmith *
23577424Smsmith ******************************************************************************/
23677424Smsmith
23777424SmsmithACPI_STATUS
23887031SmsmithAcpiExAccessRegion (
23977424Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
24077424Smsmith    UINT32                  FieldDatumByteOffset,
24187031Smsmith    ACPI_INTEGER            *Value,
24287031Smsmith    UINT32                  ReadWrite)
24377424Smsmith{
24477424Smsmith    ACPI_STATUS             Status;
24577424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
24677424Smsmith    ACPI_PHYSICAL_ADDRESS   Address;
24777424Smsmith
24877424Smsmith
24999146Siwasaki    ACPI_FUNCTION_TRACE ("ExAccessRegion");
25077424Smsmith
25177424Smsmith
25287031Smsmith    /*
25387031Smsmith     * The physical address of this field datum is:
25487031Smsmith     *
25587031Smsmith     * 1) The base of the region, plus
25687031Smsmith     * 2) The base offset of the field, plus
25787031Smsmith     * 3) The current offset into the field
25887031Smsmith     */
25987031Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
26087031Smsmith    Address = RgnDesc->Region.Address
26187031Smsmith                + ObjDesc->CommonField.BaseByteOffset
26287031Smsmith                + FieldDatumByteOffset;
26387031Smsmith
26487031Smsmith    if (ReadWrite == ACPI_READ)
26567754Smsmith    {
26687031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
26767754Smsmith    }
26887031Smsmith    else
26987031Smsmith    {
27087031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
27187031Smsmith    }
27267754Smsmith
27387031Smsmith    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
27491116Smsmith        " Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n",
27587031Smsmith        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
27687031Smsmith        RgnDesc->Region.SpaceId,
27791116Smsmith        ObjDesc->CommonField.AccessByteWidth,
27887031Smsmith        ObjDesc->CommonField.BaseByteOffset,
27987031Smsmith        FieldDatumByteOffset,
28091116Smsmith        ACPI_HIDWORD (Address), ACPI_LODWORD (Address)));
28167754Smsmith
28287031Smsmith    /* Invoke the appropriate AddressSpace/OpRegion handler */
28377424Smsmith
28487031Smsmith    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ReadWrite,
28591116Smsmith                    Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
28687031Smsmith
28787031Smsmith    if (ACPI_FAILURE (Status))
28887031Smsmith    {
28987031Smsmith        if (Status == AE_NOT_IMPLEMENTED)
29087031Smsmith        {
29187031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
29287031Smsmith                "Region %s(%X) not implemented\n",
29387031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
29487031Smsmith                RgnDesc->Region.SpaceId));
29587031Smsmith        }
29687031Smsmith
29787031Smsmith        else if (Status == AE_NOT_EXIST)
29887031Smsmith        {
29987031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
30087031Smsmith                "Region %s(%X) has no handler\n",
30187031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
30287031Smsmith                RgnDesc->Region.SpaceId));
30387031Smsmith        }
30487031Smsmith    }
30587031Smsmith
30687031Smsmith    return_ACPI_STATUS (Status);
30787031Smsmith}
30887031Smsmith
30987031Smsmith
31087031Smsmith/*******************************************************************************
31187031Smsmith *
31287031Smsmith * FUNCTION:    AcpiExRegisterOverflow
31387031Smsmith *
31487031Smsmith * PARAMETERS:  *ObjDesc                - Register(Field) to be written
31587031Smsmith *              Value                   - Value to be stored
31687031Smsmith *
31787031Smsmith * RETURN:      TRUE if value overflows the field, FALSE otherwise
31887031Smsmith *
31987031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written.
32087031Smsmith *              Used to check if the values written to Index and Bank registers
32187031Smsmith *              are out of range.  Normally, the value is simply truncated
32287031Smsmith *              to fit the field, but this case is most likely a serious
32387031Smsmith *              coding error in the ASL.
32487031Smsmith *
32587031Smsmith ******************************************************************************/
32687031Smsmith
32787031SmsmithBOOLEAN
32887031SmsmithAcpiExRegisterOverflow (
32987031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
33087031Smsmith    ACPI_INTEGER            Value)
33187031Smsmith{
33287031Smsmith
33391116Smsmith    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
33491116Smsmith    {
33591116Smsmith        /*
33691116Smsmith         * The field is large enough to hold the maximum integer, so we can
33791116Smsmith         * never overflow it.
33891116Smsmith         */
33991116Smsmith        return (FALSE);
34091116Smsmith    }
34191116Smsmith
34299679Siwasaki    if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
34387031Smsmith    {
34491116Smsmith        /*
34591116Smsmith         * The Value is larger than the maximum value that can fit into
34691116Smsmith         * the register.
34791116Smsmith         */
34887031Smsmith        return (TRUE);
34987031Smsmith    }
35087031Smsmith
35191116Smsmith    /* The Value will fit into the field with no truncation */
35291116Smsmith
35387031Smsmith    return (FALSE);
35487031Smsmith}
35587031Smsmith
35687031Smsmith
35787031Smsmith/*******************************************************************************
35887031Smsmith *
35987031Smsmith * FUNCTION:    AcpiExFieldDatumIo
36087031Smsmith *
36187031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read
36287031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
36387031Smsmith *                                        parent field
36487031Smsmith *              *Value                  - Where to store value (must be 64 bits)
36587031Smsmith *              ReadWrite               - Read or Write flag
36687031Smsmith *
36787031Smsmith * RETURN:      Status
36887031Smsmith *
36987031Smsmith * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
37087031Smsmith *              demultiplexed here to handle the different types of fields
37187031Smsmith *              (BufferField, RegionField, IndexField, BankField)
37287031Smsmith *
37387031Smsmith ******************************************************************************/
37487031Smsmith
37587031SmsmithACPI_STATUS
37687031SmsmithAcpiExFieldDatumIo (
37787031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
37887031Smsmith    UINT32                  FieldDatumByteOffset,
37987031Smsmith    ACPI_INTEGER            *Value,
38087031Smsmith    UINT32                  ReadWrite)
38187031Smsmith{
38287031Smsmith    ACPI_STATUS             Status;
38387031Smsmith    ACPI_INTEGER            LocalValue;
38487031Smsmith
38587031Smsmith
38691116Smsmith    ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
38787031Smsmith
38887031Smsmith
38987031Smsmith    if (ReadWrite == ACPI_READ)
39087031Smsmith    {
39187031Smsmith        if (!Value)
39287031Smsmith        {
39387031Smsmith            LocalValue = 0;
39487031Smsmith            Value = &LocalValue;  /* To support reads without saving return value */
39587031Smsmith        }
39687031Smsmith
39787031Smsmith        /* Clear the entire return buffer first, [Very Important!] */
39887031Smsmith
39987031Smsmith        *Value = 0;
40087031Smsmith    }
40187031Smsmith
40287031Smsmith    /*
40387031Smsmith     * The four types of fields are:
40487031Smsmith     *
40587031Smsmith     * BufferFields - Read/write from/to a Buffer
40687031Smsmith     * RegionFields - Read/write from/to a Operation Region.
40787031Smsmith     * BankFields   - Write to a Bank Register, then read/write from/to an OpRegion
40887031Smsmith     * IndexFields  - Write to an Index Register, then read/write from/to a Data Register
40987031Smsmith     */
41099679Siwasaki    switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
41177424Smsmith    {
41277424Smsmith    case ACPI_TYPE_BUFFER_FIELD:
41377424Smsmith        /*
41487031Smsmith         * If the BufferField arguments have not been previously evaluated,
41587031Smsmith         * evaluate them now and save the results.
41677424Smsmith         */
41787031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
41887031Smsmith        {
41987031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
42087031Smsmith            if (ACPI_FAILURE (Status))
42187031Smsmith            {
42287031Smsmith                return_ACPI_STATUS (Status);
42387031Smsmith            }
42487031Smsmith        }
42587031Smsmith
42687031Smsmith        if (ReadWrite == ACPI_READ)
42787031Smsmith        {
42887031Smsmith            /*
42987031Smsmith             * Copy the data from the source buffer.
43087031Smsmith             * Length is the field width in bytes.
43187031Smsmith             */
43291116Smsmith            ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
43387031Smsmith                            + ObjDesc->BufferField.BaseByteOffset
43487031Smsmith                            + FieldDatumByteOffset,
43587031Smsmith                            ObjDesc->CommonField.AccessByteWidth);
43687031Smsmith        }
43787031Smsmith        else
43887031Smsmith        {
43987031Smsmith            /*
44087031Smsmith             * Copy the data to the target buffer.
44187031Smsmith             * Length is the field width in bytes.
44287031Smsmith             */
44391116Smsmith            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
44487031Smsmith                    + ObjDesc->BufferField.BaseByteOffset
44587031Smsmith                    + FieldDatumByteOffset,
44687031Smsmith                    Value, ObjDesc->CommonField.AccessByteWidth);
44787031Smsmith        }
44887031Smsmith
44977424Smsmith        Status = AE_OK;
45077424Smsmith        break;
45167754Smsmith
45267754Smsmith
45377424Smsmith    case INTERNAL_TYPE_BANK_FIELD:
45467754Smsmith
45587031Smsmith        /* Ensure that the BankValue is not beyond the capacity of the register */
45687031Smsmith
45787031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
45899679Siwasaki                                    (ACPI_INTEGER) ObjDesc->BankField.Value))
45987031Smsmith        {
46087031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
46187031Smsmith        }
46287031Smsmith
46377424Smsmith        /*
46487031Smsmith         * For BankFields, we must write the BankValue to the BankRegister
46587031Smsmith         * (itself a RegionField) before we can access the data.
46677424Smsmith         */
46787031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
46887031Smsmith                                &ObjDesc->BankField.Value,
46987031Smsmith                                sizeof (ObjDesc->BankField.Value));
47077424Smsmith        if (ACPI_FAILURE (Status))
47177424Smsmith        {
47277424Smsmith            return_ACPI_STATUS (Status);
47377424Smsmith        }
47467754Smsmith
47577424Smsmith        /*
47687031Smsmith         * Now that the Bank has been selected, fall through to the
47787031Smsmith         * RegionField case and write the datum to the Operation Region
47877424Smsmith         */
47977424Smsmith
48099679Siwasaki        /*lint -fallthrough */
48177424Smsmith
48277424Smsmith
48387031Smsmith    case INTERNAL_TYPE_REGION_FIELD:
48487031Smsmith        /*
48587031Smsmith         * For simple RegionFields, we just directly access the owning
48687031Smsmith         * Operation Region.
48787031Smsmith         */
48887031Smsmith        Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
48987031Smsmith        if (ACPI_FAILURE (Status))
49077424Smsmith        {
49187031Smsmith            return_ACPI_STATUS (Status);
49277424Smsmith        }
49377424Smsmith
49487031Smsmith        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
49587031Smsmith                        ReadWrite);
49687031Smsmith        break;
49787031Smsmith
49887031Smsmith
49987031Smsmith    case INTERNAL_TYPE_INDEX_FIELD:
50087031Smsmith
50187031Smsmith
50287031Smsmith        /* Ensure that the IndexValue is not beyond the capacity of the register */
50387031Smsmith
50487031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
50599679Siwasaki                                    (ACPI_INTEGER) ObjDesc->IndexField.Value))
50677424Smsmith        {
50787031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
50877424Smsmith        }
50987031Smsmith
51087031Smsmith        /* Write the index value to the IndexRegister (itself a RegionField) */
51187031Smsmith
51287031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
51387031Smsmith                                &ObjDesc->IndexField.Value,
51487031Smsmith                                sizeof (ObjDesc->IndexField.Value));
51587031Smsmith        if (ACPI_FAILURE (Status))
51687031Smsmith        {
51787031Smsmith            return_ACPI_STATUS (Status);
51887031Smsmith        }
51987031Smsmith
52087031Smsmith        if (ReadWrite == ACPI_READ)
52187031Smsmith        {
52287031Smsmith            /* Read the datum from the DataRegister */
52387031Smsmith
52487031Smsmith            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
52587031Smsmith                            Value, ObjDesc->CommonField.AccessByteWidth);
52687031Smsmith        }
52787031Smsmith        else
52887031Smsmith        {
52987031Smsmith            /* Write the datum to the Data register */
53087031Smsmith
53187031Smsmith            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
53287031Smsmith                            Value, ObjDesc->CommonField.AccessByteWidth);
53387031Smsmith        }
53477424Smsmith        break;
53577424Smsmith
53677424Smsmith
53777424Smsmith    default:
53877424Smsmith
53987031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",
54099679Siwasaki            ObjDesc, AcpiUtGetObjectTypeName (ObjDesc)));
54177424Smsmith        Status = AE_AML_INTERNAL;
54277424Smsmith        break;
54367754Smsmith    }
54467754Smsmith
54587031Smsmith    if (ACPI_SUCCESS (Status))
54687031Smsmith    {
54787031Smsmith        if (ReadWrite == ACPI_READ)
54887031Smsmith        {
54987031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",
55091116Smsmith                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
55187031Smsmith        }
55287031Smsmith        else
55387031Smsmith        {
55487031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",
55591116Smsmith                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
55687031Smsmith        }
55787031Smsmith    }
55877424Smsmith
55987031Smsmith    return_ACPI_STATUS (Status);
56087031Smsmith}
56177424Smsmith
56287031Smsmith
56387031Smsmith/*******************************************************************************
56487031Smsmith *
56587031Smsmith * FUNCTION:    AcpiExWriteWithUpdateRule
56687031Smsmith *
56787031Smsmith * PARAMETERS:  *ObjDesc            - Field to be set
56887031Smsmith *              Value               - Value to store
56987031Smsmith *
57087031Smsmith * RETURN:      Status
57187031Smsmith *
57287031Smsmith * DESCRIPTION: Apply the field update rule to a field write
57387031Smsmith *
57487031Smsmith ******************************************************************************/
57587031Smsmith
57687031SmsmithACPI_STATUS
57787031SmsmithAcpiExWriteWithUpdateRule (
57887031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
57987031Smsmith    ACPI_INTEGER            Mask,
58087031Smsmith    ACPI_INTEGER            FieldValue,
58187031Smsmith    UINT32                  FieldDatumByteOffset)
58287031Smsmith{
58387031Smsmith    ACPI_STATUS             Status = AE_OK;
58487031Smsmith    ACPI_INTEGER            MergedValue;
58587031Smsmith    ACPI_INTEGER            CurrentValue;
58687031Smsmith
58787031Smsmith
58891116Smsmith    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
58987031Smsmith
59087031Smsmith
59187031Smsmith    /* Start with the new bits  */
59287031Smsmith
59387031Smsmith    MergedValue = FieldValue;
59487031Smsmith
59587031Smsmith    /* If the mask is all ones, we don't need to worry about the update rule */
59687031Smsmith
59799679Siwasaki    if (Mask != ACPI_INTEGER_MAX)
59887031Smsmith    {
59987031Smsmith        /* Decode the update rule */
60087031Smsmith
60187031Smsmith        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
60287031Smsmith        {
60387031Smsmith        case AML_FIELD_UPDATE_PRESERVE:
60487031Smsmith            /*
60587031Smsmith             * Check if update rule needs to be applied (not if mask is all
60687031Smsmith             * ones)  The left shift drops the bits we want to ignore.
60787031Smsmith             */
60891116Smsmith            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
60991116Smsmith                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
61087031Smsmith            {
61187031Smsmith                /*
61287031Smsmith                 * Read the current contents of the byte/word/dword containing
61387031Smsmith                 * the field, and merge with the new field value.
61487031Smsmith                 */
61587031Smsmith                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
61687031Smsmith                                &CurrentValue, ACPI_READ);
61787031Smsmith                MergedValue |= (CurrentValue & ~Mask);
61887031Smsmith            }
61987031Smsmith            break;
62087031Smsmith
62187031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ONES:
62287031Smsmith
62387031Smsmith            /* Set positions outside the field to all ones */
62487031Smsmith
62587031Smsmith            MergedValue |= ~Mask;
62687031Smsmith            break;
62787031Smsmith
62887031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
62987031Smsmith
63087031Smsmith            /* Set positions outside the field to all zeros */
63187031Smsmith
63287031Smsmith            MergedValue &= Mask;
63387031Smsmith            break;
63487031Smsmith
63587031Smsmith        default:
63687031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
63799679Siwasaki                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
63887031Smsmith                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
63987031Smsmith            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
64087031Smsmith        }
64187031Smsmith    }
64287031Smsmith
64387031Smsmith    /* Write the merged value */
64487031Smsmith
64587031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
64687031Smsmith                    &MergedValue, ACPI_WRITE);
64787031Smsmith
64887031Smsmith    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
64987031Smsmith        "Mask %8.8X%8.8X DatumOffset %X Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
65091116Smsmith        ACPI_HIDWORD (Mask), ACPI_LODWORD (Mask),
65187031Smsmith        FieldDatumByteOffset,
65291116Smsmith        ACPI_HIDWORD (FieldValue), ACPI_LODWORD (FieldValue),
65391116Smsmith        ACPI_HIDWORD (MergedValue),ACPI_LODWORD (MergedValue)));
65487031Smsmith
65577424Smsmith    return_ACPI_STATUS (Status);
65677424Smsmith}
65777424Smsmith
65877424Smsmith
65977424Smsmith/*******************************************************************************
66077424Smsmith *
66177424Smsmith * FUNCTION:    AcpiExGetBufferDatum
66277424Smsmith *
66387031Smsmith * PARAMETERS:  Datum               - Where the Datum is returned
66487031Smsmith *              Buffer              - Raw field buffer
66587031Smsmith *              ByteGranularity     - 1/2/4/8 Granularity of the field
66677424Smsmith *                                    (aka Datum Size)
66777424Smsmith *              Offset              - Datum offset into the buffer
66883174Smsmith *
66977424Smsmith * RETURN:      none
67077424Smsmith *
67187031Smsmith * DESCRIPTION: Get a datum from the buffer according to the buffer field
67277424Smsmith *              byte granularity
67377424Smsmith *
67477424Smsmith ******************************************************************************/
67577424Smsmith
67687031Smsmithvoid
67777424SmsmithAcpiExGetBufferDatum(
67887031Smsmith    ACPI_INTEGER            *Datum,
67977424Smsmith    void                    *Buffer,
68077424Smsmith    UINT32                  ByteGranularity,
68177424Smsmith    UINT32                  Offset)
68277424Smsmith{
68377424Smsmith
68491116Smsmith    ACPI_FUNCTION_ENTRY ();
68583174Smsmith
68683174Smsmith
68777424Smsmith    switch (ByteGranularity)
68867754Smsmith    {
68977424Smsmith    case ACPI_FIELD_BYTE_GRANULARITY:
69091116Smsmith
69177424Smsmith        *Datum = ((UINT8 *) Buffer) [Offset];
69277424Smsmith        break;
69377424Smsmith
69477424Smsmith    case ACPI_FIELD_WORD_GRANULARITY:
69591116Smsmith
69691116Smsmith        ACPI_MOVE_UNALIGNED16_TO_32 (Datum, &(((UINT16 *) Buffer) [Offset]));
69777424Smsmith        break;
69877424Smsmith
69977424Smsmith    case ACPI_FIELD_DWORD_GRANULARITY:
70091116Smsmith
70191116Smsmith        ACPI_MOVE_UNALIGNED32_TO_32 (Datum, &(((UINT32 *) Buffer) [Offset]));
70277424Smsmith        break;
70387031Smsmith
70487031Smsmith    case ACPI_FIELD_QWORD_GRANULARITY:
70591116Smsmith
70691116Smsmith        ACPI_MOVE_UNALIGNED64_TO_64 (Datum, &(((UINT64 *) Buffer) [Offset]));
70787031Smsmith        break;
70899679Siwasaki
70999679Siwasaki    default:
71099679Siwasaki        /* Should not get here */
71199679Siwasaki        break;
71267754Smsmith    }
71377424Smsmith}
71467754Smsmith
71567754Smsmith
71677424Smsmith/*******************************************************************************
71777424Smsmith *
71883174Smsmith * FUNCTION:    AcpiExSetBufferDatum
71977424Smsmith *
72077424Smsmith * PARAMETERS:  MergedDatum         - Value to store
72177424Smsmith *              Buffer              - Receiving buffer
72287031Smsmith *              ByteGranularity     - 1/2/4/8 Granularity of the field
72377424Smsmith *                                    (aka Datum Size)
72477424Smsmith *              Offset              - Datum offset into the buffer
72583174Smsmith *
72677424Smsmith * RETURN:      none
72777424Smsmith *
72877424Smsmith * DESCRIPTION: Store the merged datum to the buffer according to the
72977424Smsmith *              byte granularity
73077424Smsmith *
73177424Smsmith ******************************************************************************/
73277424Smsmith
73387031Smsmithvoid
73477424SmsmithAcpiExSetBufferDatum (
73587031Smsmith    ACPI_INTEGER            MergedDatum,
73677424Smsmith    void                    *Buffer,
73777424Smsmith    UINT32                  ByteGranularity,
73877424Smsmith    UINT32                  Offset)
73977424Smsmith{
74077424Smsmith
74191116Smsmith    ACPI_FUNCTION_ENTRY ();
74283174Smsmith
74383174Smsmith
74477424Smsmith    switch (ByteGranularity)
74577424Smsmith    {
74677424Smsmith    case ACPI_FIELD_BYTE_GRANULARITY:
74791116Smsmith
74877424Smsmith        ((UINT8 *) Buffer) [Offset] = (UINT8) MergedDatum;
74977424Smsmith        break;
75077424Smsmith
75177424Smsmith    case ACPI_FIELD_WORD_GRANULARITY:
75291116Smsmith
75391116Smsmith        ACPI_MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[Offset]), &MergedDatum);
75477424Smsmith        break;
75577424Smsmith
75677424Smsmith    case ACPI_FIELD_DWORD_GRANULARITY:
75791116Smsmith
75891116Smsmith        ACPI_MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[Offset]), &MergedDatum);
75977424Smsmith        break;
76087031Smsmith
76187031Smsmith    case ACPI_FIELD_QWORD_GRANULARITY:
76291116Smsmith
76391116Smsmith        ACPI_MOVE_UNALIGNED64_TO_64 (&(((UINT64 *) Buffer)[Offset]), &MergedDatum);
76487031Smsmith        break;
76599679Siwasaki
76699679Siwasaki    default:
76799679Siwasaki        /* Should not get here */
76899679Siwasaki        break;
76977424Smsmith    }
77067754Smsmith}
77167754Smsmith
77267754Smsmith
77367754Smsmith/*******************************************************************************
77467754Smsmith *
77577424Smsmith * FUNCTION:    AcpiExExtractFromField
77667754Smsmith *
77767754Smsmith * PARAMETERS:  *ObjDesc            - Field to be read
77867754Smsmith *              *Value              - Where to store value
77967754Smsmith *
78067754Smsmith * RETURN:      Status
78167754Smsmith *
78267754Smsmith * DESCRIPTION: Retrieve the value of the given field
78367754Smsmith *
78467754Smsmith ******************************************************************************/
78567754Smsmith
78667754SmsmithACPI_STATUS
78777424SmsmithAcpiExExtractFromField (
78867754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
78967754Smsmith    void                    *Buffer,
79077424Smsmith    UINT32                  BufferLength)
79167754Smsmith{
79267754Smsmith    ACPI_STATUS             Status;
79377424Smsmith    UINT32                  FieldDatumByteOffset;
79477424Smsmith    UINT32                  DatumOffset;
79587031Smsmith    ACPI_INTEGER            PreviousRawDatum;
79687031Smsmith    ACPI_INTEGER            ThisRawDatum = 0;
79787031Smsmith    ACPI_INTEGER            MergedDatum = 0;
79877424Smsmith    UINT32                  ByteFieldLength;
79977424Smsmith    UINT32                  DatumCount;
80067754Smsmith
80167754Smsmith
80291116Smsmith    ACPI_FUNCTION_TRACE ("ExExtractFromField");
80367754Smsmith
80477424Smsmith
80567754Smsmith    /*
80677424Smsmith     * The field must fit within the caller's buffer
80777424Smsmith     */
80891116Smsmith    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
80977424Smsmith    if (ByteFieldLength > BufferLength)
81077424Smsmith    {
81199146Siwasaki        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
81287031Smsmith            "Field size %X (bytes) too large for buffer (%X)\n",
81377424Smsmith            ByteFieldLength, BufferLength));
81477424Smsmith
81577424Smsmith        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
81677424Smsmith    }
81777424Smsmith
81877424Smsmith    /* Convert field byte count to datum count, round up if necessary */
81977424Smsmith
82091116Smsmith    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
82187031Smsmith                              ObjDesc->CommonField.AccessByteWidth);
82277424Smsmith
82399146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
82499679Siwasaki        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
82591116Smsmith        ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth));
82677424Smsmith
82777424Smsmith    /*
82867754Smsmith     * Clear the caller's buffer (the whole buffer length as given)
82967754Smsmith     * This is very important, especially in the cases where a byte is read,
83067754Smsmith     * but the buffer is really a UINT32 (4 bytes).
83167754Smsmith     */
83291116Smsmith    ACPI_MEMSET (Buffer, 0, BufferLength);
83367754Smsmith
83467754Smsmith    /* Read the first raw datum to prime the loop */
83567754Smsmith
83677424Smsmith    FieldDatumByteOffset = 0;
83777424Smsmith    DatumOffset= 0;
83867754Smsmith
83987031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
84087031Smsmith                    &PreviousRawDatum, ACPI_READ);
84167754Smsmith    if (ACPI_FAILURE (Status))
84267754Smsmith    {
84377424Smsmith        return_ACPI_STATUS (Status);
84467754Smsmith    }
84567754Smsmith
84677424Smsmith
84767754Smsmith    /* We might actually be done if the request fits in one datum */
84867754Smsmith
84977424Smsmith    if ((DatumCount == 1) &&
85087031Smsmith        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
85167754Smsmith    {
85277424Smsmith        /* 1) Shift the valid data bits down to start at bit 0 */
85367754Smsmith
85477424Smsmith        MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
85567754Smsmith
85677424Smsmith        /* 2) Mask off any upper unused bits (bits not part of the field) */
85777424Smsmith
85877424Smsmith        if (ObjDesc->CommonField.EndBufferValidBits)
85967754Smsmith        {
86091116Smsmith            MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
86167754Smsmith        }
86267754Smsmith
86377424Smsmith        /* Store the datum to the caller buffer */
86467754Smsmith
86583174Smsmith        AcpiExSetBufferDatum (MergedDatum, Buffer, ObjDesc->CommonField.AccessByteWidth,
86677424Smsmith                DatumOffset);
86767754Smsmith
86877424Smsmith        return_ACPI_STATUS (AE_OK);
86977424Smsmith    }
87067754Smsmith
87167754Smsmith
87277424Smsmith    /* We need to get more raw data to complete one or more field data */
87367754Smsmith
87477424Smsmith    while (DatumOffset < DatumCount)
87567754Smsmith    {
87677424Smsmith        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
87767754Smsmith
87877424Smsmith        /*
87977424Smsmith         * If the field is aligned on a byte boundary, we don't want
88077424Smsmith         * to perform a final read, since this would potentially read
88177424Smsmith         * past the end of the region.
88277424Smsmith         *
88391116Smsmith         * We could just split the aligned and non-aligned cases since the
88487031Smsmith         * aligned case is so very simple, but this would require more code.
88577424Smsmith         */
88687031Smsmith        if ((ObjDesc->CommonField.StartFieldBitOffset != 0)  ||
88787031Smsmith            ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
88877424Smsmith            (DatumOffset < (DatumCount -1))))
88967754Smsmith        {
89067754Smsmith            /*
89177424Smsmith             * Get the next raw datum, it contains some or all bits
89277424Smsmith             * of the current field datum
89367754Smsmith             */
89487031Smsmith            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
89587031Smsmith                            &ThisRawDatum, ACPI_READ);
89677424Smsmith            if (ACPI_FAILURE (Status))
89767754Smsmith            {
89877424Smsmith                return_ACPI_STATUS (Status);
89967754Smsmith            }
90077424Smsmith        }
90167754Smsmith
90277424Smsmith        /*
90377424Smsmith         * Create the (possibly) merged datum to be stored to the caller buffer
90477424Smsmith         */
90577424Smsmith        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
90677424Smsmith        {
90777424Smsmith            /* Field is not skewed and we can just copy the datum */
90871867Smsmith
90977424Smsmith            MergedDatum = PreviousRawDatum;
91077424Smsmith        }
91177424Smsmith        else
91277424Smsmith        {
91367754Smsmith            /*
91483174Smsmith             * Put together the appropriate bits of the two raw data to make a
91577424Smsmith             * single complete field datum
91677424Smsmith             *
91783174Smsmith             * 1) Normalize the first datum down to bit 0
91867754Smsmith             */
91977424Smsmith            MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
92067754Smsmith
92177424Smsmith            /* 2) Insert the second datum "above" the first datum */
92267754Smsmith
92377424Smsmith            MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
92483174Smsmith
92577424Smsmith            if ((DatumOffset >= (DatumCount -1)))
92667754Smsmith            {
92777424Smsmith                /*
92877424Smsmith                 * This is the last iteration of the loop.  We need to clear
92983174Smsmith                 * any unused bits (bits that are not part of this field) that
93083174Smsmith                 * came from the last raw datum before we store the final
93177424Smsmith                 * merged datum into the caller buffer.
93277424Smsmith                 */
93377424Smsmith                if (ObjDesc->CommonField.EndBufferValidBits)
93477424Smsmith                {
93583174Smsmith                    MergedDatum &=
93691116Smsmith                        ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
93777424Smsmith                }
93867754Smsmith            }
93977424Smsmith        }
94067754Smsmith
94177424Smsmith        /*
94277424Smsmith         * Store the merged field datum in the caller's buffer, according to
94377424Smsmith         * the granularity of the field (size of each datum).
94477424Smsmith         */
94591116Smsmith        AcpiExSetBufferDatum (MergedDatum, Buffer,
94687031Smsmith                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
94767754Smsmith
94877424Smsmith        /*
94983174Smsmith         * Save the raw datum that was just acquired since it may contain bits
95077424Smsmith         * of the *next* field datum.  Update offsets
95177424Smsmith         */
95277424Smsmith        PreviousRawDatum = ThisRawDatum;
95377424Smsmith        DatumOffset++;
95467754Smsmith    }
95567754Smsmith
95677424Smsmith    return_ACPI_STATUS (AE_OK);
95767754Smsmith}
95867754Smsmith
95967754Smsmith
96067754Smsmith/*******************************************************************************
96167754Smsmith *
96277424Smsmith * FUNCTION:    AcpiExInsertIntoField
96367754Smsmith *
96467754Smsmith * PARAMETERS:  *ObjDesc            - Field to be set
96577424Smsmith *              Buffer              - Value to store
96667754Smsmith *
96767754Smsmith * RETURN:      Status
96867754Smsmith *
96967754Smsmith * DESCRIPTION: Store the value into the given field
97067754Smsmith *
97177424Smsmith ******************************************************************************/
97267754Smsmith
97367754SmsmithACPI_STATUS
97477424SmsmithAcpiExInsertIntoField (
97567754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
97667754Smsmith    void                    *Buffer,
97777424Smsmith    UINT32                  BufferLength)
97867754Smsmith{
97967754Smsmith    ACPI_STATUS             Status;
98077424Smsmith    UINT32                  FieldDatumByteOffset;
98177424Smsmith    UINT32                  DatumOffset;
98287031Smsmith    ACPI_INTEGER            Mask;
98387031Smsmith    ACPI_INTEGER            MergedDatum;
98487031Smsmith    ACPI_INTEGER            PreviousRawDatum;
98587031Smsmith    ACPI_INTEGER            ThisRawDatum;
98677424Smsmith    UINT32                  ByteFieldLength;
98777424Smsmith    UINT32                  DatumCount;
98867754Smsmith
98967754Smsmith
99091116Smsmith    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
99167754Smsmith
99267754Smsmith
99367754Smsmith    /*
99483174Smsmith     * Incoming buffer must be at least as long as the field, we do not
99577424Smsmith     * allow "partial" field writes.  We do not care if the buffer is
99677424Smsmith     * larger than the field, this typically happens when an integer is
99777424Smsmith     * written to a field that is actually smaller than an integer.
99867754Smsmith     */
99991116Smsmith    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
100077424Smsmith    if (BufferLength < ByteFieldLength)
100177424Smsmith    {
100299146Siwasaki        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n",
100377424Smsmith            BufferLength, ByteFieldLength));
100467754Smsmith
100577424Smsmith        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
100677424Smsmith    }
100767754Smsmith
100877424Smsmith    /* Convert byte count to datum count, round up if necessary */
100967754Smsmith
101091116Smsmith    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
101167754Smsmith
101299146Siwasaki    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
101399679Siwasaki        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
101491116Smsmith        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth));
101567754Smsmith
101677424Smsmith    /*
101777424Smsmith     * Break the request into up to three parts (similar to an I/O request):
101877424Smsmith     * 1) non-aligned part at start
101977424Smsmith     * 2) aligned part in middle
102077424Smsmith     * 3) non-aligned part at the end
102177424Smsmith     */
102277424Smsmith    FieldDatumByteOffset = 0;
102377424Smsmith    DatumOffset= 0;
102467754Smsmith
102577424Smsmith    /* Get a single datum from the caller's buffer */
102677424Smsmith
102783174Smsmith    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer,
102877424Smsmith            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
102977424Smsmith
103067754Smsmith    /*
103177424Smsmith     * Part1:
103267754Smsmith     * Write a partial field datum if field does not begin on a datum boundary
103377424Smsmith     * Note: The code in this section also handles the aligned case
103467754Smsmith     *
103567754Smsmith     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
103677424Smsmith     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
103767754Smsmith     *
103877424Smsmith     * Mask off bits that are "below" the field (if any)
103967754Smsmith     */
104091116Smsmith    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
104167754Smsmith
104277424Smsmith    /* If the field fits in one datum, may need to mask upper bits */
104367754Smsmith
104487031Smsmith    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
104577424Smsmith         ObjDesc->CommonField.EndFieldValidBits)
104667754Smsmith    {
104777424Smsmith        /* There are bits above the field, mask them off also */
104867754Smsmith
104991116Smsmith        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
105067754Smsmith    }
105167754Smsmith
105277424Smsmith    /* Shift and mask the value into the field position */
105367754Smsmith
105477424Smsmith    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
105577424Smsmith    MergedDatum &= Mask;
105667754Smsmith
105777424Smsmith    /* Apply the update rule (if necessary) and write the datum to the field */
105877424Smsmith
105987031Smsmith    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
106077424Smsmith                        FieldDatumByteOffset);
106167754Smsmith    if (ACPI_FAILURE (Status))
106267754Smsmith    {
106377424Smsmith        return_ACPI_STATUS (Status);
106467754Smsmith    }
106567754Smsmith
106677424Smsmith    /* If the entire field fits within one datum, we are done. */
106767754Smsmith
106877424Smsmith    if ((DatumCount == 1) &&
106987031Smsmith       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
107067754Smsmith    {
107177424Smsmith        return_ACPI_STATUS (AE_OK);
107267754Smsmith    }
107367754Smsmith
107467754Smsmith    /*
107577424Smsmith     * Part2:
107677424Smsmith     * Write the aligned data.
107777424Smsmith     *
107867754Smsmith     * We don't need to worry about the update rule for these data, because
107977424Smsmith     * all of the bits in each datum are part of the field.
108067754Smsmith     *
108183174Smsmith     * The last datum must be special cased because it might contain bits
108283174Smsmith     * that are not part of the field -- therefore the "update rule" must be
108377424Smsmith     * applied in Part3 below.
108467754Smsmith     */
108577424Smsmith    while (DatumOffset < DatumCount)
108667754Smsmith    {
108777424Smsmith        DatumOffset++;
108877424Smsmith        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
108967754Smsmith
109083174Smsmith        /*
109183174Smsmith         * Get the next raw buffer datum.  It may contain bits of the previous
109277424Smsmith         * field datum
109377424Smsmith         */
109483174Smsmith        AcpiExGetBufferDatum (&ThisRawDatum, Buffer,
109577424Smsmith                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
109667754Smsmith
109777424Smsmith        /* Create the field datum based on the field alignment */
109867754Smsmith
109977424Smsmith        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
110067754Smsmith        {
110177424Smsmith            /*
110283174Smsmith             * Put together appropriate bits of the two raw buffer data to make
110377424Smsmith             * a single complete field datum
110477424Smsmith             */
110583174Smsmith            MergedDatum =
110677424Smsmith                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
110777424Smsmith                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
110867754Smsmith        }
110967754Smsmith        else
111067754Smsmith        {
111177424Smsmith            /* Field began aligned on datum boundary */
111277424Smsmith
111367754Smsmith            MergedDatum = ThisRawDatum;
111467754Smsmith        }
111567754Smsmith
111667754Smsmith        /*
111777424Smsmith         * Special handling for the last datum if the field does NOT end on
111877424Smsmith         * a datum boundary.  Update Rule must be applied to the bits outside
111977424Smsmith         * the field.
112067754Smsmith         */
112185756Smsmith        if (DatumOffset == DatumCount)
112277424Smsmith        {
112383174Smsmith            /*
112485756Smsmith             * If there are dangling non-aligned bits, perform one more merged write
112585756Smsmith             * Else - field is aligned at the end, no need for any more writes
112677424Smsmith             */
112785756Smsmith            if (ObjDesc->CommonField.EndFieldValidBits)
112885756Smsmith            {
112985756Smsmith                /*
113085756Smsmith                 * Part3:
113185756Smsmith                 * This is the last datum and the field does not end on a datum boundary.
113285756Smsmith                 * Build the partial datum and write with the update rule.
113385756Smsmith                 *
113485756Smsmith                 * Mask off the unused bits above (after) the end-of-field
113585756Smsmith                 */
113691116Smsmith                Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
113785756Smsmith                MergedDatum &= Mask;
113867754Smsmith
113985756Smsmith                /* Write the last datum with the update rule */
114067754Smsmith
114187031Smsmith                Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
114287031Smsmith                                    FieldDatumByteOffset);
114385756Smsmith                if (ACPI_FAILURE (Status))
114485756Smsmith                {
114585756Smsmith                    return_ACPI_STATUS (Status);
114685756Smsmith                }
114777424Smsmith            }
114877424Smsmith        }
114977424Smsmith        else
115067754Smsmith        {
115177424Smsmith            /* Normal case -- write the completed datum */
115267754Smsmith
115387031Smsmith            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
115487031Smsmith                            &MergedDatum, ACPI_WRITE);
115577424Smsmith            if (ACPI_FAILURE (Status))
115677424Smsmith            {
115777424Smsmith                return_ACPI_STATUS (Status);
115877424Smsmith            }
115967754Smsmith        }
116067754Smsmith
116177424Smsmith        /*
116283174Smsmith         * Save the most recent datum since it may contain bits of the *next*
116377424Smsmith         * field datum.  Update current byte offset.
116477424Smsmith         */
116577424Smsmith        PreviousRawDatum = ThisRawDatum;
116667754Smsmith    }
116767754Smsmith
116867754Smsmith    return_ACPI_STATUS (Status);
116967754Smsmith}
117067754Smsmith
117167754Smsmith
1172