exfldio.c revision 87031
167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfldio - Aml Field I/O
487031Smsmith *              $Revision: 75 $
567754Smsmith *
667754Smsmith *****************************************************************************/
767754Smsmith
867754Smsmith/******************************************************************************
967754Smsmith *
1067754Smsmith * 1. Copyright Notice
1167754Smsmith *
1271867Smsmith * Some or all of this work - Copyright (c) 1999, 2000, 2001, 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 "acnamesp.h"
12467754Smsmith#include "achware.h"
12567754Smsmith#include "acevents.h"
12677424Smsmith#include "acdispat.h"
12767754Smsmith
12867754Smsmith
12977424Smsmith#define _COMPONENT          ACPI_EXECUTER
13077424Smsmith        MODULE_NAME         ("exfldio")
13167754Smsmith
13267754Smsmith
13367754Smsmith/*******************************************************************************
13467754Smsmith *
13587031Smsmith * FUNCTION:    AcpiExSetupRegion
13667754Smsmith *
13787031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read or written
13887031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
13987031Smsmith *                                        parent field
14067754Smsmith *
14167754Smsmith * RETURN:      Status
14267754Smsmith *
14377424Smsmith * DESCRIPTION: Common processing for AcpiExExtractFromField and
14487031Smsmith *              AcpiExInsertIntoField.  Initialize the
14567754Smsmith *
14667754Smsmith ******************************************************************************/
14767754Smsmith
14867754SmsmithACPI_STATUS
14987031SmsmithAcpiExSetupRegion (
15067754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
15177424Smsmith    UINT32                  FieldDatumByteOffset)
15267754Smsmith{
15377424Smsmith    ACPI_STATUS             Status = AE_OK;
15477424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
15567754Smsmith
15667754Smsmith
15787031Smsmith    FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
15867754Smsmith
15983174Smsmith
16077424Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
16167754Smsmith
16277424Smsmith    if (ACPI_TYPE_REGION != RgnDesc->Common.Type)
16377424Smsmith    {
16482367Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %x %s\n",
16577424Smsmith            RgnDesc->Common.Type, AcpiUtGetTypeName (RgnDesc->Common.Type)));
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,
19982367Smsmith                "Field access width (%d bytes) too large for region size (%X)\n",
20077424Smsmith                ObjDesc->CommonField.AccessByteWidth, RgnDesc->Region.Length));
20177424Smsmith        }
20277424Smsmith
20377424Smsmith        /*
20477424Smsmith         * Offset rounded up to next multiple of field width
20577424Smsmith         * exceeds region length, indicate an error
20677424Smsmith         */
20782367Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
20887031Smsmith            "Field Base+Offset+Width %X+%X+%X exceeds region size (%X bytes) field=%p region=%p\n",
20983174Smsmith            ObjDesc->CommonField.BaseByteOffset, FieldDatumByteOffset,
21077424Smsmith            ObjDesc->CommonField.AccessByteWidth,
21177424Smsmith            RgnDesc->Region.Length, ObjDesc, RgnDesc));
21277424Smsmith
21377424Smsmith        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
21477424Smsmith    }
21577424Smsmith
21677424Smsmith    return_ACPI_STATUS (AE_OK);
21777424Smsmith}
21877424Smsmith
21977424Smsmith
22077424Smsmith/*******************************************************************************
22177424Smsmith *
22287031Smsmith * FUNCTION:    AcpiExAccessRegion
22377424Smsmith *
22487031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read
22587031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
22687031Smsmith *                                        parent field
22787031Smsmith *              *Value                  - Where to store value (must be 32 bits)
22887031Smsmith *              ReadWrite               - Read or Write flag
22977424Smsmith *
23077424Smsmith * RETURN:      Status
23177424Smsmith *
23287031Smsmith * DESCRIPTION: Read or Write a single field datum to an Operation Region.
23377424Smsmith *
23477424Smsmith ******************************************************************************/
23577424Smsmith
23677424SmsmithACPI_STATUS
23787031SmsmithAcpiExAccessRegion (
23877424Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
23977424Smsmith    UINT32                  FieldDatumByteOffset,
24087031Smsmith    ACPI_INTEGER            *Value,
24187031Smsmith    UINT32                  ReadWrite)
24277424Smsmith{
24377424Smsmith    ACPI_STATUS             Status;
24477424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
24577424Smsmith    ACPI_PHYSICAL_ADDRESS   Address;
24677424Smsmith
24777424Smsmith
24887031Smsmith    FUNCTION_TRACE ("AcpiExAccessRegion");
24977424Smsmith
25077424Smsmith
25187031Smsmith    /*
25287031Smsmith     * The physical address of this field datum is:
25387031Smsmith     *
25487031Smsmith     * 1) The base of the region, plus
25587031Smsmith     * 2) The base offset of the field, plus
25687031Smsmith     * 3) The current offset into the field
25787031Smsmith     */
25887031Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
25987031Smsmith    Address = RgnDesc->Region.Address
26087031Smsmith                + ObjDesc->CommonField.BaseByteOffset
26187031Smsmith                + FieldDatumByteOffset;
26287031Smsmith
26387031Smsmith    if (ReadWrite == ACPI_READ)
26467754Smsmith    {
26587031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
26667754Smsmith    }
26787031Smsmith    else
26887031Smsmith    {
26987031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
27087031Smsmith    }
27167754Smsmith
27287031Smsmith    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
27387031Smsmith        " Region[%s-%X] Width %X Base:Off %X:%X at %8.8X%8.8X\n",
27487031Smsmith        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
27587031Smsmith        RgnDesc->Region.SpaceId,
27687031Smsmith        ObjDesc->CommonField.AccessBitWidth,
27787031Smsmith        ObjDesc->CommonField.BaseByteOffset,
27887031Smsmith        FieldDatumByteOffset,
27987031Smsmith        HIDWORD (Address), LODWORD (Address)));
28067754Smsmith
28187031Smsmith    /* Invoke the appropriate AddressSpace/OpRegion handler */
28277424Smsmith
28387031Smsmith    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ReadWrite,
28487031Smsmith                    Address, ObjDesc->CommonField.AccessBitWidth, Value);
28587031Smsmith
28687031Smsmith    if (ACPI_FAILURE (Status))
28787031Smsmith    {
28887031Smsmith        if (Status == AE_NOT_IMPLEMENTED)
28987031Smsmith        {
29087031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
29187031Smsmith                "Region %s(%X) not implemented\n",
29287031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
29387031Smsmith                RgnDesc->Region.SpaceId));
29487031Smsmith        }
29587031Smsmith
29687031Smsmith        else if (Status == AE_NOT_EXIST)
29787031Smsmith        {
29887031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
29987031Smsmith                "Region %s(%X) has no handler\n",
30087031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
30187031Smsmith                RgnDesc->Region.SpaceId));
30287031Smsmith        }
30387031Smsmith    }
30487031Smsmith
30587031Smsmith    return_ACPI_STATUS (Status);
30687031Smsmith}
30787031Smsmith
30887031Smsmith
30987031Smsmith/*******************************************************************************
31087031Smsmith *
31187031Smsmith * FUNCTION:    AcpiExRegisterOverflow
31287031Smsmith *
31387031Smsmith * PARAMETERS:  *ObjDesc                - Register(Field) to be written
31487031Smsmith *              Value                   - Value to be stored
31587031Smsmith *
31687031Smsmith * RETURN:      TRUE if value overflows the field, FALSE otherwise
31787031Smsmith *
31887031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written.
31987031Smsmith *              Used to check if the values written to Index and Bank registers
32087031Smsmith *              are out of range.  Normally, the value is simply truncated
32187031Smsmith *              to fit the field, but this case is most likely a serious
32287031Smsmith *              coding error in the ASL.
32387031Smsmith *
32487031Smsmith ******************************************************************************/
32587031Smsmith
32687031SmsmithBOOLEAN
32787031SmsmithAcpiExRegisterOverflow (
32887031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
32987031Smsmith    ACPI_INTEGER            Value)
33087031Smsmith{
33187031Smsmith
33267754Smsmith    /*
33387031Smsmith     * Is the Value larger than the maximum value that can fit into
33487031Smsmith     * the field?
33567754Smsmith     */
33687031Smsmith    if (Value >= (ACPI_INTEGER) (1 << ObjDesc->CommonField.BitLength))
33787031Smsmith    {
33887031Smsmith        return (TRUE);
33987031Smsmith    }
34087031Smsmith
34187031Smsmith    return (FALSE);
34287031Smsmith}
34387031Smsmith
34487031Smsmith
34587031Smsmith/*******************************************************************************
34687031Smsmith *
34787031Smsmith * FUNCTION:    AcpiExFieldDatumIo
34887031Smsmith *
34987031Smsmith * PARAMETERS:  *ObjDesc                - Field to be read
35087031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
35187031Smsmith *                                        parent field
35287031Smsmith *              *Value                  - Where to store value (must be 64 bits)
35387031Smsmith *              ReadWrite               - Read or Write flag
35487031Smsmith *
35587031Smsmith * RETURN:      Status
35687031Smsmith *
35787031Smsmith * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
35887031Smsmith *              demultiplexed here to handle the different types of fields
35987031Smsmith *              (BufferField, RegionField, IndexField, BankField)
36087031Smsmith *
36187031Smsmith ******************************************************************************/
36287031Smsmith
36387031SmsmithACPI_STATUS
36487031SmsmithAcpiExFieldDatumIo (
36587031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
36687031Smsmith    UINT32                  FieldDatumByteOffset,
36787031Smsmith    ACPI_INTEGER            *Value,
36887031Smsmith    UINT32                  ReadWrite)
36987031Smsmith{
37087031Smsmith    ACPI_STATUS             Status;
37187031Smsmith    ACPI_INTEGER            LocalValue;
37287031Smsmith
37387031Smsmith
37487031Smsmith    FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
37587031Smsmith
37687031Smsmith
37787031Smsmith    if (ReadWrite == ACPI_READ)
37887031Smsmith    {
37987031Smsmith        if (!Value)
38087031Smsmith        {
38187031Smsmith            LocalValue = 0;
38287031Smsmith            Value = &LocalValue;  /* To support reads without saving return value */
38387031Smsmith        }
38487031Smsmith
38587031Smsmith        /* Clear the entire return buffer first, [Very Important!] */
38687031Smsmith
38787031Smsmith        *Value = 0;
38887031Smsmith    }
38987031Smsmith
39087031Smsmith    /*
39187031Smsmith     * The four types of fields are:
39287031Smsmith     *
39387031Smsmith     * BufferFields - Read/write from/to a Buffer
39487031Smsmith     * RegionFields - Read/write from/to a Operation Region.
39587031Smsmith     * BankFields   - Write to a Bank Register, then read/write from/to an OpRegion
39687031Smsmith     * IndexFields  - Write to an Index Register, then read/write from/to a Data Register
39787031Smsmith     */
39877424Smsmith    switch (ObjDesc->Common.Type)
39977424Smsmith    {
40077424Smsmith    case ACPI_TYPE_BUFFER_FIELD:
40177424Smsmith        /*
40287031Smsmith         * If the BufferField arguments have not been previously evaluated,
40387031Smsmith         * evaluate them now and save the results.
40477424Smsmith         */
40587031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
40687031Smsmith        {
40787031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
40887031Smsmith            if (ACPI_FAILURE (Status))
40987031Smsmith            {
41087031Smsmith                return_ACPI_STATUS (Status);
41187031Smsmith            }
41287031Smsmith        }
41387031Smsmith
41487031Smsmith        if (ReadWrite == ACPI_READ)
41587031Smsmith        {
41687031Smsmith            /*
41787031Smsmith             * Copy the data from the source buffer.
41887031Smsmith             * Length is the field width in bytes.
41987031Smsmith             */
42087031Smsmith            MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
42187031Smsmith                            + ObjDesc->BufferField.BaseByteOffset
42287031Smsmith                            + FieldDatumByteOffset,
42387031Smsmith                            ObjDesc->CommonField.AccessByteWidth);
42487031Smsmith        }
42587031Smsmith        else
42687031Smsmith        {
42787031Smsmith            /*
42887031Smsmith             * Copy the data to the target buffer.
42987031Smsmith             * Length is the field width in bytes.
43087031Smsmith             */
43187031Smsmith            MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
43287031Smsmith                    + ObjDesc->BufferField.BaseByteOffset
43387031Smsmith                    + FieldDatumByteOffset,
43487031Smsmith                    Value, ObjDesc->CommonField.AccessByteWidth);
43587031Smsmith        }
43687031Smsmith
43777424Smsmith        Status = AE_OK;
43877424Smsmith        break;
43967754Smsmith
44067754Smsmith
44177424Smsmith    case INTERNAL_TYPE_BANK_FIELD:
44267754Smsmith
44387031Smsmith        /* Ensure that the BankValue is not beyond the capacity of the register */
44487031Smsmith
44587031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
44687031Smsmith                                    ObjDesc->BankField.Value))
44787031Smsmith        {
44887031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
44987031Smsmith        }
45087031Smsmith
45177424Smsmith        /*
45287031Smsmith         * For BankFields, we must write the BankValue to the BankRegister
45387031Smsmith         * (itself a RegionField) before we can access the data.
45477424Smsmith         */
45587031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
45687031Smsmith                                &ObjDesc->BankField.Value,
45787031Smsmith                                sizeof (ObjDesc->BankField.Value));
45877424Smsmith        if (ACPI_FAILURE (Status))
45977424Smsmith        {
46077424Smsmith            return_ACPI_STATUS (Status);
46177424Smsmith        }
46267754Smsmith
46377424Smsmith        /*
46487031Smsmith         * Now that the Bank has been selected, fall through to the
46587031Smsmith         * RegionField case and write the datum to the Operation Region
46677424Smsmith         */
46777424Smsmith
46887031Smsmith        /* No break; ! */
46977424Smsmith
47077424Smsmith
47187031Smsmith    case INTERNAL_TYPE_REGION_FIELD:
47287031Smsmith        /*
47387031Smsmith         * For simple RegionFields, we just directly access the owning
47487031Smsmith         * Operation Region.
47587031Smsmith         */
47687031Smsmith        Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
47787031Smsmith        if (ACPI_FAILURE (Status))
47877424Smsmith        {
47987031Smsmith            return_ACPI_STATUS (Status);
48077424Smsmith        }
48177424Smsmith
48287031Smsmith        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
48387031Smsmith                        ReadWrite);
48487031Smsmith        break;
48587031Smsmith
48687031Smsmith
48787031Smsmith    case INTERNAL_TYPE_INDEX_FIELD:
48887031Smsmith
48987031Smsmith
49087031Smsmith        /* Ensure that the IndexValue is not beyond the capacity of the register */
49187031Smsmith
49287031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
49387031Smsmith                                    ObjDesc->IndexField.Value))
49477424Smsmith        {
49587031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
49677424Smsmith        }
49787031Smsmith
49887031Smsmith        /* Write the index value to the IndexRegister (itself a RegionField) */
49987031Smsmith
50087031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
50187031Smsmith                                &ObjDesc->IndexField.Value,
50287031Smsmith                                sizeof (ObjDesc->IndexField.Value));
50387031Smsmith        if (ACPI_FAILURE (Status))
50487031Smsmith        {
50587031Smsmith            return_ACPI_STATUS (Status);
50687031Smsmith        }
50787031Smsmith
50887031Smsmith        if (ReadWrite == ACPI_READ)
50987031Smsmith        {
51087031Smsmith            /* Read the datum from the DataRegister */
51187031Smsmith
51287031Smsmith            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
51387031Smsmith                            Value, ObjDesc->CommonField.AccessByteWidth);
51487031Smsmith        }
51587031Smsmith        else
51687031Smsmith        {
51787031Smsmith            /* Write the datum to the Data register */
51887031Smsmith
51987031Smsmith            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
52087031Smsmith                            Value, ObjDesc->CommonField.AccessByteWidth);
52187031Smsmith        }
52277424Smsmith        break;
52377424Smsmith
52477424Smsmith
52577424Smsmith    default:
52677424Smsmith
52787031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",
52877424Smsmith            ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type)));
52977424Smsmith        Status = AE_AML_INTERNAL;
53077424Smsmith        break;
53167754Smsmith    }
53267754Smsmith
53387031Smsmith    if (ACPI_SUCCESS (Status))
53487031Smsmith    {
53587031Smsmith        if (ReadWrite == ACPI_READ)
53687031Smsmith        {
53787031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",
53887031Smsmith                                HIDWORD(*Value), LODWORD(*Value)));
53987031Smsmith        }
54087031Smsmith        else
54187031Smsmith        {
54287031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",
54387031Smsmith                                HIDWORD(*Value), LODWORD(*Value)));
54487031Smsmith        }
54587031Smsmith    }
54677424Smsmith
54787031Smsmith    return_ACPI_STATUS (Status);
54887031Smsmith}
54977424Smsmith
55087031Smsmith
55187031Smsmith/*******************************************************************************
55287031Smsmith *
55387031Smsmith * FUNCTION:    AcpiExWriteWithUpdateRule
55487031Smsmith *
55587031Smsmith * PARAMETERS:  *ObjDesc            - Field to be set
55687031Smsmith *              Value               - Value to store
55787031Smsmith *
55887031Smsmith * RETURN:      Status
55987031Smsmith *
56087031Smsmith * DESCRIPTION: Apply the field update rule to a field write
56187031Smsmith *
56287031Smsmith ******************************************************************************/
56387031Smsmith
56487031SmsmithACPI_STATUS
56587031SmsmithAcpiExWriteWithUpdateRule (
56687031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
56787031Smsmith    ACPI_INTEGER            Mask,
56887031Smsmith    ACPI_INTEGER            FieldValue,
56987031Smsmith    UINT32                  FieldDatumByteOffset)
57087031Smsmith{
57187031Smsmith    ACPI_STATUS             Status = AE_OK;
57287031Smsmith    ACPI_INTEGER            MergedValue;
57387031Smsmith    ACPI_INTEGER            CurrentValue;
57487031Smsmith
57587031Smsmith
57687031Smsmith    FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
57787031Smsmith
57887031Smsmith
57987031Smsmith    /* Start with the new bits  */
58087031Smsmith
58187031Smsmith    MergedValue = FieldValue;
58287031Smsmith
58387031Smsmith    /* If the mask is all ones, we don't need to worry about the update rule */
58487031Smsmith
58587031Smsmith    if (Mask != ACPI_UINT32_MAX)
58687031Smsmith    {
58787031Smsmith        /* Decode the update rule */
58887031Smsmith
58987031Smsmith        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
59087031Smsmith        {
59187031Smsmith        case AML_FIELD_UPDATE_PRESERVE:
59287031Smsmith            /*
59387031Smsmith             * Check if update rule needs to be applied (not if mask is all
59487031Smsmith             * ones)  The left shift drops the bits we want to ignore.
59587031Smsmith             */
59687031Smsmith            if ((~Mask << (sizeof (Mask) * 8 -
59787031Smsmith                            ObjDesc->CommonField.AccessBitWidth)) != 0)
59887031Smsmith            {
59987031Smsmith                /*
60087031Smsmith                 * Read the current contents of the byte/word/dword containing
60187031Smsmith                 * the field, and merge with the new field value.
60287031Smsmith                 */
60387031Smsmith                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
60487031Smsmith                                &CurrentValue, ACPI_READ);
60587031Smsmith                MergedValue |= (CurrentValue & ~Mask);
60687031Smsmith            }
60787031Smsmith            break;
60887031Smsmith
60987031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ONES:
61087031Smsmith
61187031Smsmith            /* Set positions outside the field to all ones */
61287031Smsmith
61387031Smsmith            MergedValue |= ~Mask;
61487031Smsmith            break;
61587031Smsmith
61687031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
61787031Smsmith
61887031Smsmith            /* Set positions outside the field to all zeros */
61987031Smsmith
62087031Smsmith            MergedValue &= Mask;
62187031Smsmith            break;
62287031Smsmith
62387031Smsmith        default:
62487031Smsmith            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
62587031Smsmith                "WriteWithUpdateRule: Unknown UpdateRule setting: %x\n",
62687031Smsmith                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
62787031Smsmith            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
62887031Smsmith            break;
62987031Smsmith        }
63087031Smsmith    }
63187031Smsmith
63287031Smsmith    /* Write the merged value */
63387031Smsmith
63487031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
63587031Smsmith                    &MergedValue, ACPI_WRITE);
63687031Smsmith
63787031Smsmith    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
63887031Smsmith        "Mask %8.8X%8.8X DatumOffset %X Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
63987031Smsmith        HIDWORD(Mask), LODWORD(Mask),
64087031Smsmith        FieldDatumByteOffset,
64187031Smsmith        HIDWORD(FieldValue), LODWORD(FieldValue),
64287031Smsmith        HIDWORD(MergedValue),LODWORD(MergedValue)));
64387031Smsmith
64477424Smsmith    return_ACPI_STATUS (Status);
64577424Smsmith}
64677424Smsmith
64777424Smsmith
64877424Smsmith/*******************************************************************************
64977424Smsmith *
65077424Smsmith * FUNCTION:    AcpiExGetBufferDatum
65177424Smsmith *
65287031Smsmith * PARAMETERS:  Datum               - Where the Datum is returned
65387031Smsmith *              Buffer              - Raw field buffer
65487031Smsmith *              ByteGranularity     - 1/2/4/8 Granularity of the field
65577424Smsmith *                                    (aka Datum Size)
65677424Smsmith *              Offset              - Datum offset into the buffer
65783174Smsmith *
65877424Smsmith * RETURN:      none
65977424Smsmith *
66087031Smsmith * DESCRIPTION: Get a datum from the buffer according to the buffer field
66177424Smsmith *              byte granularity
66277424Smsmith *
66377424Smsmith ******************************************************************************/
66477424Smsmith
66587031Smsmithvoid
66677424SmsmithAcpiExGetBufferDatum(
66787031Smsmith    ACPI_INTEGER            *Datum,
66877424Smsmith    void                    *Buffer,
66977424Smsmith    UINT32                  ByteGranularity,
67077424Smsmith    UINT32                  Offset)
67177424Smsmith{
67277424Smsmith
67383174Smsmith    FUNCTION_ENTRY ();
67483174Smsmith
67583174Smsmith
67677424Smsmith    switch (ByteGranularity)
67767754Smsmith    {
67877424Smsmith    case ACPI_FIELD_BYTE_GRANULARITY:
67977424Smsmith        *Datum = ((UINT8 *) Buffer) [Offset];
68077424Smsmith        break;
68177424Smsmith
68277424Smsmith    case ACPI_FIELD_WORD_GRANULARITY:
68377424Smsmith        MOVE_UNALIGNED16_TO_32 (Datum, &(((UINT16 *) Buffer) [Offset]));
68477424Smsmith        break;
68577424Smsmith
68677424Smsmith    case ACPI_FIELD_DWORD_GRANULARITY:
68777424Smsmith        MOVE_UNALIGNED32_TO_32 (Datum, &(((UINT32 *) Buffer) [Offset]));
68877424Smsmith        break;
68987031Smsmith
69087031Smsmith    case ACPI_FIELD_QWORD_GRANULARITY:
69187031Smsmith        MOVE_UNALIGNED64_TO_64 (Datum, &(((UINT64 *) Buffer) [Offset]));
69287031Smsmith        break;
69367754Smsmith    }
69477424Smsmith}
69567754Smsmith
69667754Smsmith
69777424Smsmith/*******************************************************************************
69877424Smsmith *
69983174Smsmith * FUNCTION:    AcpiExSetBufferDatum
70077424Smsmith *
70177424Smsmith * PARAMETERS:  MergedDatum         - Value to store
70277424Smsmith *              Buffer              - Receiving buffer
70387031Smsmith *              ByteGranularity     - 1/2/4/8 Granularity of the field
70477424Smsmith *                                    (aka Datum Size)
70577424Smsmith *              Offset              - Datum offset into the buffer
70683174Smsmith *
70777424Smsmith * RETURN:      none
70877424Smsmith *
70977424Smsmith * DESCRIPTION: Store the merged datum to the buffer according to the
71077424Smsmith *              byte granularity
71177424Smsmith *
71277424Smsmith ******************************************************************************/
71377424Smsmith
71487031Smsmithvoid
71577424SmsmithAcpiExSetBufferDatum (
71687031Smsmith    ACPI_INTEGER            MergedDatum,
71777424Smsmith    void                    *Buffer,
71877424Smsmith    UINT32                  ByteGranularity,
71977424Smsmith    UINT32                  Offset)
72077424Smsmith{
72177424Smsmith
72283174Smsmith    FUNCTION_ENTRY ();
72383174Smsmith
72483174Smsmith
72577424Smsmith    switch (ByteGranularity)
72677424Smsmith    {
72777424Smsmith    case ACPI_FIELD_BYTE_GRANULARITY:
72877424Smsmith        ((UINT8 *) Buffer) [Offset] = (UINT8) MergedDatum;
72977424Smsmith        break;
73077424Smsmith
73177424Smsmith    case ACPI_FIELD_WORD_GRANULARITY:
73277424Smsmith        MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[Offset]), &MergedDatum);
73377424Smsmith        break;
73477424Smsmith
73577424Smsmith    case ACPI_FIELD_DWORD_GRANULARITY:
73677424Smsmith        MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[Offset]), &MergedDatum);
73777424Smsmith        break;
73887031Smsmith
73987031Smsmith    case ACPI_FIELD_QWORD_GRANULARITY:
74087031Smsmith        MOVE_UNALIGNED64_TO_64 (&(((UINT64 *) Buffer)[Offset]), &MergedDatum);
74187031Smsmith        break;
74277424Smsmith    }
74367754Smsmith}
74467754Smsmith
74567754Smsmith
74667754Smsmith/*******************************************************************************
74767754Smsmith *
74877424Smsmith * FUNCTION:    AcpiExExtractFromField
74967754Smsmith *
75067754Smsmith * PARAMETERS:  *ObjDesc            - Field to be read
75167754Smsmith *              *Value              - Where to store value
75267754Smsmith *
75367754Smsmith * RETURN:      Status
75467754Smsmith *
75567754Smsmith * DESCRIPTION: Retrieve the value of the given field
75667754Smsmith *
75767754Smsmith ******************************************************************************/
75867754Smsmith
75967754SmsmithACPI_STATUS
76077424SmsmithAcpiExExtractFromField (
76167754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
76267754Smsmith    void                    *Buffer,
76377424Smsmith    UINT32                  BufferLength)
76467754Smsmith{
76567754Smsmith    ACPI_STATUS             Status;
76677424Smsmith    UINT32                  FieldDatumByteOffset;
76777424Smsmith    UINT32                  DatumOffset;
76887031Smsmith    ACPI_INTEGER            PreviousRawDatum;
76987031Smsmith    ACPI_INTEGER            ThisRawDatum = 0;
77087031Smsmith    ACPI_INTEGER            MergedDatum = 0;
77177424Smsmith    UINT32                  ByteFieldLength;
77277424Smsmith    UINT32                  DatumCount;
77367754Smsmith
77467754Smsmith
77577424Smsmith    FUNCTION_TRACE ("ExExtractFromField");
77667754Smsmith
77777424Smsmith
77867754Smsmith    /*
77977424Smsmith     * The field must fit within the caller's buffer
78077424Smsmith     */
78177424Smsmith    ByteFieldLength = ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
78277424Smsmith    if (ByteFieldLength > BufferLength)
78377424Smsmith    {
78487031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
78587031Smsmith            "Field size %X (bytes) too large for buffer (%X)\n",
78677424Smsmith            ByteFieldLength, BufferLength));
78777424Smsmith
78877424Smsmith        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
78977424Smsmith    }
79077424Smsmith
79177424Smsmith    /* Convert field byte count to datum count, round up if necessary */
79277424Smsmith
79387031Smsmith    DatumCount = ROUND_UP_TO (ByteFieldLength,
79487031Smsmith                              ObjDesc->CommonField.AccessByteWidth);
79577424Smsmith
79682367Smsmith    ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
79782367Smsmith        "ByteLen=%x, DatumLen=%x, BitGran=%x, ByteGran=%x\n",
79883174Smsmith        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessBitWidth,
79977424Smsmith        ObjDesc->CommonField.AccessByteWidth));
80077424Smsmith
80177424Smsmith    /*
80267754Smsmith     * Clear the caller's buffer (the whole buffer length as given)
80367754Smsmith     * This is very important, especially in the cases where a byte is read,
80467754Smsmith     * but the buffer is really a UINT32 (4 bytes).
80567754Smsmith     */
80667754Smsmith    MEMSET (Buffer, 0, BufferLength);
80767754Smsmith
80867754Smsmith    /* Read the first raw datum to prime the loop */
80967754Smsmith
81077424Smsmith    FieldDatumByteOffset = 0;
81177424Smsmith    DatumOffset= 0;
81267754Smsmith
81387031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
81487031Smsmith                    &PreviousRawDatum, ACPI_READ);
81567754Smsmith    if (ACPI_FAILURE (Status))
81667754Smsmith    {
81777424Smsmith        return_ACPI_STATUS (Status);
81867754Smsmith    }
81967754Smsmith
82077424Smsmith
82167754Smsmith    /* We might actually be done if the request fits in one datum */
82267754Smsmith
82377424Smsmith    if ((DatumCount == 1) &&
82487031Smsmith        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
82567754Smsmith    {
82677424Smsmith        /* 1) Shift the valid data bits down to start at bit 0 */
82767754Smsmith
82877424Smsmith        MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
82967754Smsmith
83077424Smsmith        /* 2) Mask off any upper unused bits (bits not part of the field) */
83177424Smsmith
83277424Smsmith        if (ObjDesc->CommonField.EndBufferValidBits)
83367754Smsmith        {
83477424Smsmith            MergedDatum &= MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
83567754Smsmith        }
83667754Smsmith
83777424Smsmith        /* Store the datum to the caller buffer */
83867754Smsmith
83983174Smsmith        AcpiExSetBufferDatum (MergedDatum, Buffer, ObjDesc->CommonField.AccessByteWidth,
84077424Smsmith                DatumOffset);
84167754Smsmith
84277424Smsmith        return_ACPI_STATUS (AE_OK);
84377424Smsmith    }
84467754Smsmith
84567754Smsmith
84677424Smsmith    /* We need to get more raw data to complete one or more field data */
84767754Smsmith
84877424Smsmith    while (DatumOffset < DatumCount)
84967754Smsmith    {
85077424Smsmith        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
85167754Smsmith
85277424Smsmith        /*
85377424Smsmith         * If the field is aligned on a byte boundary, we don't want
85477424Smsmith         * to perform a final read, since this would potentially read
85577424Smsmith         * past the end of the region.
85677424Smsmith         *
85787031Smsmith         * We could just split the aligned and non-aligned cases since the
85887031Smsmith         * aligned case is so very simple, but this would require more code.
85977424Smsmith         */
86087031Smsmith        if ((ObjDesc->CommonField.StartFieldBitOffset != 0)  ||
86187031Smsmith            ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
86277424Smsmith            (DatumOffset < (DatumCount -1))))
86367754Smsmith        {
86467754Smsmith            /*
86577424Smsmith             * Get the next raw datum, it contains some or all bits
86677424Smsmith             * of the current field datum
86767754Smsmith             */
86887031Smsmith            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
86987031Smsmith                            &ThisRawDatum, ACPI_READ);
87077424Smsmith            if (ACPI_FAILURE (Status))
87167754Smsmith            {
87277424Smsmith                return_ACPI_STATUS (Status);
87367754Smsmith            }
87477424Smsmith        }
87567754Smsmith
87677424Smsmith        /*
87777424Smsmith         * Create the (possibly) merged datum to be stored to the caller buffer
87877424Smsmith         */
87977424Smsmith        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
88077424Smsmith        {
88177424Smsmith            /* Field is not skewed and we can just copy the datum */
88271867Smsmith
88377424Smsmith            MergedDatum = PreviousRawDatum;
88477424Smsmith        }
88577424Smsmith        else
88677424Smsmith        {
88767754Smsmith            /*
88883174Smsmith             * Put together the appropriate bits of the two raw data to make a
88977424Smsmith             * single complete field datum
89077424Smsmith             *
89183174Smsmith             * 1) Normalize the first datum down to bit 0
89267754Smsmith             */
89377424Smsmith            MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
89467754Smsmith
89577424Smsmith            /* 2) Insert the second datum "above" the first datum */
89667754Smsmith
89777424Smsmith            MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
89883174Smsmith
89977424Smsmith            if ((DatumOffset >= (DatumCount -1)))
90067754Smsmith            {
90177424Smsmith                /*
90277424Smsmith                 * This is the last iteration of the loop.  We need to clear
90383174Smsmith                 * any unused bits (bits that are not part of this field) that
90483174Smsmith                 * came from the last raw datum before we store the final
90577424Smsmith                 * merged datum into the caller buffer.
90677424Smsmith                 */
90777424Smsmith                if (ObjDesc->CommonField.EndBufferValidBits)
90877424Smsmith                {
90983174Smsmith                    MergedDatum &=
91077424Smsmith                        MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
91177424Smsmith                }
91267754Smsmith            }
91377424Smsmith        }
91467754Smsmith
91577424Smsmith        /*
91677424Smsmith         * Store the merged field datum in the caller's buffer, according to
91777424Smsmith         * the granularity of the field (size of each datum).
91877424Smsmith         */
91987031Smsmith        AcpiExSetBufferDatum (MergedDatum, Buffer,
92087031Smsmith                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
92167754Smsmith
92277424Smsmith        /*
92383174Smsmith         * Save the raw datum that was just acquired since it may contain bits
92477424Smsmith         * of the *next* field datum.  Update offsets
92577424Smsmith         */
92677424Smsmith        PreviousRawDatum = ThisRawDatum;
92777424Smsmith        DatumOffset++;
92867754Smsmith    }
92967754Smsmith
93077424Smsmith    return_ACPI_STATUS (AE_OK);
93167754Smsmith}
93267754Smsmith
93367754Smsmith
93467754Smsmith/*******************************************************************************
93567754Smsmith *
93677424Smsmith * FUNCTION:    AcpiExInsertIntoField
93767754Smsmith *
93867754Smsmith * PARAMETERS:  *ObjDesc            - Field to be set
93977424Smsmith *              Buffer              - Value to store
94067754Smsmith *
94167754Smsmith * RETURN:      Status
94267754Smsmith *
94367754Smsmith * DESCRIPTION: Store the value into the given field
94467754Smsmith *
94577424Smsmith ******************************************************************************/
94667754Smsmith
94767754SmsmithACPI_STATUS
94877424SmsmithAcpiExInsertIntoField (
94967754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
95067754Smsmith    void                    *Buffer,
95177424Smsmith    UINT32                  BufferLength)
95267754Smsmith{
95367754Smsmith    ACPI_STATUS             Status;
95477424Smsmith    UINT32                  FieldDatumByteOffset;
95577424Smsmith    UINT32                  DatumOffset;
95687031Smsmith    ACPI_INTEGER            Mask;
95787031Smsmith    ACPI_INTEGER            MergedDatum;
95887031Smsmith    ACPI_INTEGER            PreviousRawDatum;
95987031Smsmith    ACPI_INTEGER            ThisRawDatum;
96077424Smsmith    UINT32                  ByteFieldLength;
96177424Smsmith    UINT32                  DatumCount;
96267754Smsmith
96367754Smsmith
96477424Smsmith    FUNCTION_TRACE ("ExInsertIntoField");
96567754Smsmith
96667754Smsmith
96767754Smsmith    /*
96883174Smsmith     * Incoming buffer must be at least as long as the field, we do not
96977424Smsmith     * allow "partial" field writes.  We do not care if the buffer is
97077424Smsmith     * larger than the field, this typically happens when an integer is
97177424Smsmith     * written to a field that is actually smaller than an integer.
97267754Smsmith     */
97377424Smsmith    ByteFieldLength = ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
97477424Smsmith    if (BufferLength < ByteFieldLength)
97577424Smsmith    {
97682367Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Buffer length %X too small for field %X\n",
97777424Smsmith            BufferLength, ByteFieldLength));
97867754Smsmith
97977424Smsmith        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
98077424Smsmith    }
98167754Smsmith
98277424Smsmith    /* Convert byte count to datum count, round up if necessary */
98367754Smsmith
98477424Smsmith    DatumCount = ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
98567754Smsmith
98682367Smsmith    ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
98782367Smsmith        "ByteLen=%x, DatumLen=%x, BitGran=%x, ByteGran=%x\n",
98883174Smsmith        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessBitWidth,
98977424Smsmith        ObjDesc->CommonField.AccessByteWidth));
99067754Smsmith
99177424Smsmith    /*
99277424Smsmith     * Break the request into up to three parts (similar to an I/O request):
99377424Smsmith     * 1) non-aligned part at start
99477424Smsmith     * 2) aligned part in middle
99577424Smsmith     * 3) non-aligned part at the end
99677424Smsmith     */
99777424Smsmith    FieldDatumByteOffset = 0;
99877424Smsmith    DatumOffset= 0;
99967754Smsmith
100077424Smsmith    /* Get a single datum from the caller's buffer */
100177424Smsmith
100283174Smsmith    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer,
100377424Smsmith            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
100477424Smsmith
100567754Smsmith    /*
100677424Smsmith     * Part1:
100767754Smsmith     * Write a partial field datum if field does not begin on a datum boundary
100877424Smsmith     * Note: The code in this section also handles the aligned case
100967754Smsmith     *
101067754Smsmith     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
101177424Smsmith     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
101267754Smsmith     *
101377424Smsmith     * Mask off bits that are "below" the field (if any)
101467754Smsmith     */
101577424Smsmith    Mask = MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
101667754Smsmith
101777424Smsmith    /* If the field fits in one datum, may need to mask upper bits */
101867754Smsmith
101987031Smsmith    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
102077424Smsmith         ObjDesc->CommonField.EndFieldValidBits)
102167754Smsmith    {
102277424Smsmith        /* There are bits above the field, mask them off also */
102367754Smsmith
102477424Smsmith        Mask &= MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
102567754Smsmith    }
102667754Smsmith
102777424Smsmith    /* Shift and mask the value into the field position */
102867754Smsmith
102977424Smsmith    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
103077424Smsmith    MergedDatum &= Mask;
103167754Smsmith
103277424Smsmith    /* Apply the update rule (if necessary) and write the datum to the field */
103377424Smsmith
103487031Smsmith    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
103577424Smsmith                        FieldDatumByteOffset);
103667754Smsmith    if (ACPI_FAILURE (Status))
103767754Smsmith    {
103877424Smsmith        return_ACPI_STATUS (Status);
103967754Smsmith    }
104067754Smsmith
104177424Smsmith    /* If the entire field fits within one datum, we are done. */
104267754Smsmith
104377424Smsmith    if ((DatumCount == 1) &&
104487031Smsmith       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
104567754Smsmith    {
104677424Smsmith        return_ACPI_STATUS (AE_OK);
104767754Smsmith    }
104867754Smsmith
104967754Smsmith    /*
105077424Smsmith     * Part2:
105177424Smsmith     * Write the aligned data.
105277424Smsmith     *
105367754Smsmith     * We don't need to worry about the update rule for these data, because
105477424Smsmith     * all of the bits in each datum are part of the field.
105567754Smsmith     *
105683174Smsmith     * The last datum must be special cased because it might contain bits
105783174Smsmith     * that are not part of the field -- therefore the "update rule" must be
105877424Smsmith     * applied in Part3 below.
105967754Smsmith     */
106077424Smsmith    while (DatumOffset < DatumCount)
106167754Smsmith    {
106277424Smsmith        DatumOffset++;
106377424Smsmith        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
106467754Smsmith
106583174Smsmith        /*
106683174Smsmith         * Get the next raw buffer datum.  It may contain bits of the previous
106777424Smsmith         * field datum
106877424Smsmith         */
106983174Smsmith        AcpiExGetBufferDatum (&ThisRawDatum, Buffer,
107077424Smsmith                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
107167754Smsmith
107277424Smsmith        /* Create the field datum based on the field alignment */
107367754Smsmith
107477424Smsmith        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
107567754Smsmith        {
107677424Smsmith            /*
107783174Smsmith             * Put together appropriate bits of the two raw buffer data to make
107877424Smsmith             * a single complete field datum
107977424Smsmith             */
108083174Smsmith            MergedDatum =
108177424Smsmith                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
108277424Smsmith                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
108367754Smsmith        }
108467754Smsmith        else
108567754Smsmith        {
108677424Smsmith            /* Field began aligned on datum boundary */
108777424Smsmith
108867754Smsmith            MergedDatum = ThisRawDatum;
108967754Smsmith        }
109067754Smsmith
109167754Smsmith        /*
109277424Smsmith         * Special handling for the last datum if the field does NOT end on
109377424Smsmith         * a datum boundary.  Update Rule must be applied to the bits outside
109477424Smsmith         * the field.
109567754Smsmith         */
109685756Smsmith        if (DatumOffset == DatumCount)
109777424Smsmith        {
109883174Smsmith            /*
109985756Smsmith             * If there are dangling non-aligned bits, perform one more merged write
110085756Smsmith             * Else - field is aligned at the end, no need for any more writes
110177424Smsmith             */
110285756Smsmith            if (ObjDesc->CommonField.EndFieldValidBits)
110385756Smsmith            {
110485756Smsmith                /*
110585756Smsmith                 * Part3:
110685756Smsmith                 * This is the last datum and the field does not end on a datum boundary.
110785756Smsmith                 * Build the partial datum and write with the update rule.
110885756Smsmith                 *
110985756Smsmith                 * Mask off the unused bits above (after) the end-of-field
111085756Smsmith                 */
111185756Smsmith                Mask = MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
111285756Smsmith                MergedDatum &= Mask;
111367754Smsmith
111485756Smsmith                /* Write the last datum with the update rule */
111567754Smsmith
111687031Smsmith                Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
111787031Smsmith                                    FieldDatumByteOffset);
111885756Smsmith                if (ACPI_FAILURE (Status))
111985756Smsmith                {
112085756Smsmith                    return_ACPI_STATUS (Status);
112185756Smsmith                }
112277424Smsmith            }
112377424Smsmith        }
112477424Smsmith        else
112567754Smsmith        {
112677424Smsmith            /* Normal case -- write the completed datum */
112767754Smsmith
112887031Smsmith            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
112987031Smsmith                            &MergedDatum, ACPI_WRITE);
113077424Smsmith            if (ACPI_FAILURE (Status))
113177424Smsmith            {
113277424Smsmith                return_ACPI_STATUS (Status);
113377424Smsmith            }
113467754Smsmith        }
113567754Smsmith
113677424Smsmith        /*
113783174Smsmith         * Save the most recent datum since it may contain bits of the *next*
113877424Smsmith         * field datum.  Update current byte offset.
113977424Smsmith         */
114077424Smsmith        PreviousRawDatum = ThisRawDatum;
114167754Smsmith    }
114267754Smsmith
114367754Smsmith    return_ACPI_STATUS (Status);
114467754Smsmith}
114567754Smsmith
114667754Smsmith
1147