exfldio.c revision 128212
195887Sjmallett/******************************************************************************
290744Sjmallett *
390744Sjmallett * Module Name: exfldio - Aml Field I/O
490744Sjmallett *              $Revision: 104 $
590744Sjmallett *
690744Sjmallett *****************************************************************************/
790744Sjmallett
890744Sjmallett/******************************************************************************
990744Sjmallett *
1090744Sjmallett * 1. Copyright Notice
1190744Sjmallett *
1290744Sjmallett * Some or all of this work - Copyright (c) 1999 - 2004, Intel Corp.
1390744Sjmallett * All rights reserved.
1490744Sjmallett *
1590744Sjmallett * 2. License
1690744Sjmallett *
1790744Sjmallett * 2.1. This is your license from Intel Corp. under its intellectual property
1890744Sjmallett * rights.  You may have additional license terms from the party that provided
1990744Sjmallett * you this software, covering your right to use that party's intellectual
2090744Sjmallett * property rights.
2190744Sjmallett *
2290744Sjmallett * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
2390744Sjmallett * copy of the source code appearing in this file ("Covered Code") an
2490744Sjmallett * irrevocable, perpetual, worldwide license under Intel's copyrights in the
2590744Sjmallett * base code distributed originally by Intel ("Original Intel Code") to copy,
2690744Sjmallett * make derivatives, distribute, use and display any portion of the Covered
2790744Sjmallett * Code in any form, with the right to sublicense such rights; and
2895061Sjmallett *
2995061Sjmallett * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
3095061Sjmallett * license (with the right to sublicense), under only those claims of Intel
31100014Sjmallett * patents that are infringed by the Original Intel Code, to make, use, sell,
3290744Sjmallett * offer to sell, and import the Covered Code and derivative works thereof
3390744Sjmallett * solely to the minimum extent necessary to exercise the above copyright
3490744Sjmallett * license, and in no event shall the patent license extend to any additions
3590744Sjmallett * to or modifications of the Original Intel Code.  No other license or right
3690744Sjmallett * is granted directly or by implication, estoppel or otherwise;
3790744Sjmallett *
3890744Sjmallett * The above copyright and patent license is granted only if the following
3990744Sjmallett * conditions are met:
4090744Sjmallett *
4190744Sjmallett * 3. Conditions
4290744Sjmallett *
4390744Sjmallett * 3.1. Redistribution of Source with Rights to Further Distribute Source.
4490744Sjmallett * Redistribution of source code of any substantial portion of the Covered
4590744Sjmallett * Code or modification with rights to further distribute source must include
4690744Sjmallett * the above Copyright Notice, the above License, this list of Conditions,
4790744Sjmallett * and the following Disclaimer and Export Compliance provision.  In addition,
4890744Sjmallett * Licensee must cause all Covered Code to which Licensee contributes to
4990744Sjmallett * contain a file documenting the changes Licensee made to create that Covered
5090744Sjmallett * Code and the date of any change.  Licensee must include in that file the
5190744Sjmallett * documentation of any changes made by any predecessor Licensee.  Licensee
5290744Sjmallett * must include a prominent statement that the modification is derived,
5390744Sjmallett * directly or indirectly, from Original Intel Code.
5490744Sjmallett *
5590744Sjmallett * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
5690744Sjmallett * Redistribution of source code of any substantial portion of the Covered
57218909Sbrucec * Code or modification without rights to further distribute source must
5890744Sjmallett * include the following Disclaimer and Export Compliance provision in the
5990744Sjmallett * documentation and/or other materials provided with distribution.  In
6090744Sjmallett * addition, Licensee may not authorize further sublicense of source of any
6190744Sjmallett * portion of the Covered Code, and must include terms to the effect that the
6290744Sjmallett * license from Licensee to its licensee is limited to the intellectual
6390744Sjmallett * property embodied in the software Licensee provides to its licensee, and
6490744Sjmallett * not to intellectual property embodied in modifications its licensee may
6590744Sjmallett * make.
6690744Sjmallett *
6790744Sjmallett * 3.3. Redistribution of Executable. Redistribution in executable form of any
6890744Sjmallett * substantial portion of the Covered Code or modification must reproduce the
6990744Sjmallett * above Copyright Notice, and the following Disclaimer and Export Compliance
7090744Sjmallett * provision in the documentation and/or other materials provided with the
7190744Sjmallett * distribution.
7290744Sjmallett *
7395887Sjmallett * 3.4. Intel retains all right, title, and interest in and to the Original
7490744Sjmallett * Intel Code.
7590744Sjmallett *
7690744Sjmallett * 3.5. Neither the name Intel nor any other trademark owned or controlled by
7790744Sjmallett * Intel shall be used in advertising or otherwise to promote the sale, use or
7890744Sjmallett * other dealings in products derived from or relating to the Covered Code
7990744Sjmallett * without prior written authorization from Intel.
8090744Sjmallett *
8190744Sjmallett * 4. Disclaimer and Export Compliance
8290744Sjmallett *
8390744Sjmallett * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
8490744Sjmallett * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
8590744Sjmallett * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
86100014Sjmallett * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
87100014Sjmallett * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
8895887Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
8990744Sjmallett * PARTICULAR PURPOSE.
9090744Sjmallett *
9190744Sjmallett * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
9290744Sjmallett * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
9390744Sjmallett * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
9490744Sjmallett * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
9590744Sjmallett * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
9690744Sjmallett * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
9790744Sjmallett * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
9890744Sjmallett * LIMITED REMEDY.
9990744Sjmallett *
10090744Sjmallett * 4.3. Licensee shall not export, either directly or indirectly, any of this
10190744Sjmallett * software or system incorporating such software without first obtaining any
10290744Sjmallett * required license or other approval from the U. S. Department of Commerce or
10399939Sjmallett * any other agency or department of the United States Government.  In the
10490744Sjmallett * event Licensee exports any such software from the United States or
10590744Sjmallett * re-exports any such software from a foreign destination, Licensee shall
10690744Sjmallett * ensure that the distribution and export/re-export of the software is in
10790744Sjmallett * compliance with all laws, regulations, orders, or other restrictions of the
10890744Sjmallett * U.S. Export Administration Regulations. Licensee agrees that neither it nor
10990744Sjmallett * any of its subsidiaries will export/re-export any technical data, process,
11090744Sjmallett * software, or service, directly or indirectly, to any country for which the
11190744Sjmallett * United States government or any agency thereof requires an export license,
11290744Sjmallett * other governmental approval, or letter of assurance, without first obtaining
11390744Sjmallett * such license, approval or letter.
114100014Sjmallett *
11590744Sjmallett *****************************************************************************/
11690744Sjmallett
11790744Sjmallett
11890744Sjmallett#define __EXFLDIO_C__
11990744Sjmallett
120100014Sjmallett#include "acpi.h"
12190744Sjmallett#include "acinterp.h"
12290744Sjmallett#include "amlcode.h"
12390744Sjmallett#include "acevents.h"
12490744Sjmallett#include "acdispat.h"
12590744Sjmallett
12690744Sjmallett
12790744Sjmallett#define _COMPONENT          ACPI_EXECUTER
12895887Sjmallett        ACPI_MODULE_NAME    ("exfldio")
12990744Sjmallett
13090744Sjmallett
13190744Sjmallett/*******************************************************************************
13290744Sjmallett *
13390744Sjmallett * FUNCTION:    AcpiExSetupRegion
13490744Sjmallett *
13590744Sjmallett * PARAMETERS:  *ObjDesc                - Field to be read or written
136172261Skevlo *              FieldDatumByteOffset    - Byte offset of this datum within the
13790744Sjmallett *                                        parent field
13890744Sjmallett *
13990744Sjmallett * RETURN:      Status
14090744Sjmallett *
14190744Sjmallett * DESCRIPTION: Common processing for AcpiExExtractFromField and
14290744Sjmallett *              AcpiExInsertIntoField.  Initialize the Region if necessary and
14390744Sjmallett *              validate the request.
14490744Sjmallett *
14595887Sjmallett ******************************************************************************/
14690744Sjmallett
14790744SjmallettACPI_STATUS
14890744SjmallettAcpiExSetupRegion (
14990744Sjmallett    ACPI_OPERAND_OBJECT     *ObjDesc,
15090744Sjmallett    UINT32                  FieldDatumByteOffset)
15190744Sjmallett{
15290744Sjmallett    ACPI_STATUS             Status = AE_OK;
15390744Sjmallett    ACPI_OPERAND_OBJECT     *RgnDesc;
15490744Sjmallett
15590744Sjmallett
15690744Sjmallett    ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
15790744Sjmallett
15890744Sjmallett
15990744Sjmallett    RgnDesc = ObjDesc->CommonField.RegionObj;
16090744Sjmallett
16190744Sjmallett    /* We must have a valid region */
162100014Sjmallett
16395887Sjmallett    if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
16490744Sjmallett    {
16590744Sjmallett        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
16690744Sjmallett            ACPI_GET_OBJECT_TYPE (RgnDesc),
16790744Sjmallett            AcpiUtGetObjectTypeName (RgnDesc)));
16890744Sjmallett
16990744Sjmallett        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
17090744Sjmallett    }
17190744Sjmallett
17290744Sjmallett    /*
17390744Sjmallett     * If the Region Address and Length have not been previously evaluated,
174100014Sjmallett     * evaluate them now and save the results.
17595887Sjmallett     */
17690744Sjmallett    if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
17790744Sjmallett    {
17890744Sjmallett        Status = AcpiDsGetRegionArguments (RgnDesc);
17990744Sjmallett        if (ACPI_FAILURE (Status))
18090744Sjmallett        {
18190744Sjmallett            return_ACPI_STATUS (Status);
18290744Sjmallett        }
18390744Sjmallett    }
184100014Sjmallett
18590744Sjmallett    if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
18690744Sjmallett    {
18790744Sjmallett        /* SMBus has a non-linear address space */
18890744Sjmallett
18990744Sjmallett        return_ACPI_STATUS (AE_OK);
19090744Sjmallett    }
19190744Sjmallett
19290744Sjmallett#ifdef ACPI_UNDER_DEVELOPMENT
19390744Sjmallett    /*
19495887Sjmallett     * If the Field access is AnyAcc, we can now compute the optimal
19590744Sjmallett     * access (because we know know the length of the parent region)
19690744Sjmallett     */
19790744Sjmallett    if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
19890744Sjmallett    {
19990744Sjmallett        if (ACPI_FAILURE (Status))
20090744Sjmallett        {
20195095Sjmallett            return_ACPI_STATUS (Status);
20290744Sjmallett        }
20390744Sjmallett    }
20490744Sjmallett#endif
205100014Sjmallett
20695887Sjmallett    /*
20790744Sjmallett     * Validate the request.  The entire request from the byte offset for a
20890744Sjmallett     * length of one field datum (access width) must fit within the region.
20990744Sjmallett     * (Region length is specified in bytes)
21090744Sjmallett     */
21190744Sjmallett    if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset
21290744Sjmallett                                    + FieldDatumByteOffset
21390744Sjmallett                                    + ObjDesc->CommonField.AccessByteWidth))
21490744Sjmallett    {
21590744Sjmallett        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
21690744Sjmallett        {
21790744Sjmallett            /*
21890744Sjmallett             * This is the case where the AccessType (AccWord, etc.) is wider
21990744Sjmallett             * than the region itself.  For example, a region of length one
22090744Sjmallett             * byte, and a field with Dword access specified.
22190744Sjmallett             */
22290744Sjmallett            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
223100014Sjmallett                "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
22495887Sjmallett                AcpiUtGetNodeName (ObjDesc->CommonField.Node),
22590744Sjmallett                ObjDesc->CommonField.AccessByteWidth,
22690744Sjmallett                AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
22790744Sjmallett        }
22890744Sjmallett
22990744Sjmallett        /*
23090744Sjmallett         * Offset rounded up to next multiple of field width
23190744Sjmallett         * exceeds region length, indicate an error
23290744Sjmallett         */
23390744Sjmallett        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
23490744Sjmallett            "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
23590744Sjmallett            AcpiUtGetNodeName (ObjDesc->CommonField.Node),
23690744Sjmallett            ObjDesc->CommonField.BaseByteOffset,
23790744Sjmallett            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
23890744Sjmallett            AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
23999939Sjmallett
24090744Sjmallett        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
24190744Sjmallett    }
24290744Sjmallett
24390744Sjmallett    return_ACPI_STATUS (AE_OK);
24490744Sjmallett}
24590744Sjmallett
24690744Sjmallett
247100014Sjmallett/*******************************************************************************
24895887Sjmallett *
24990744Sjmallett * FUNCTION:    AcpiExAccessRegion
25090744Sjmallett *
25190744Sjmallett * PARAMETERS:  *ObjDesc                - Field to be read
25290744Sjmallett *              FieldDatumByteOffset    - Byte offset of this datum within the
25390744Sjmallett *                                        parent field
25490744Sjmallett *              *Value                  - Where to store value (must at least
25590744Sjmallett *                                        the size of ACPI_INTEGER)
25690744Sjmallett *              Function                - Read or Write flag plus other region-
25790744Sjmallett *                                        dependent flags
25890744Sjmallett *
25990744Sjmallett * RETURN:      Status
26095887Sjmallett *
26190744Sjmallett * DESCRIPTION: Read or Write a single field datum to an Operation Region.
26290744Sjmallett *
26395164Sjmallett ******************************************************************************/
26490744Sjmallett
26590744SjmallettACPI_STATUS
26690744SjmallettAcpiExAccessRegion (
26790744Sjmallett    ACPI_OPERAND_OBJECT     *ObjDesc,
26890744Sjmallett    UINT32                  FieldDatumByteOffset,
26990744Sjmallett    ACPI_INTEGER            *Value,
27090744Sjmallett    UINT32                  Function)
27190744Sjmallett{
27290744Sjmallett    ACPI_STATUS             Status;
27390744Sjmallett    ACPI_OPERAND_OBJECT     *RgnDesc;
27490744Sjmallett    ACPI_PHYSICAL_ADDRESS   Address;
27590744Sjmallett
276100014Sjmallett
27795887Sjmallett    ACPI_FUNCTION_TRACE ("ExAccessRegion");
27890744Sjmallett
27990744Sjmallett
28090744Sjmallett    /*
28190744Sjmallett     * Ensure that the region operands are fully evaluated and verify
28290744Sjmallett     * the validity of the request
28390744Sjmallett     */
28490744Sjmallett    Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
28590744Sjmallett    if (ACPI_FAILURE (Status))
28690744Sjmallett    {
28790744Sjmallett        return_ACPI_STATUS (Status);
28890744Sjmallett    }
28990744Sjmallett
29090744Sjmallett    /*
29190744Sjmallett     * The physical address of this field datum is:
29290744Sjmallett     *
29390744Sjmallett     * 1) The base of the region, plus
29490744Sjmallett     * 2) The base offset of the field, plus
29590744Sjmallett     * 3) The current offset into the field
29690744Sjmallett     */
29790744Sjmallett    RgnDesc = ObjDesc->CommonField.RegionObj;
29890744Sjmallett    Address = RgnDesc->Region.Address
29990744Sjmallett                + ObjDesc->CommonField.BaseByteOffset
30090744Sjmallett                + FieldDatumByteOffset;
30190744Sjmallett
30290744Sjmallett    if ((Function & ACPI_IO_MASK) == ACPI_READ)
30390744Sjmallett    {
30490744Sjmallett        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
30590744Sjmallett    }
30690744Sjmallett    else
30790744Sjmallett    {
30890744Sjmallett        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
309100014Sjmallett    }
31095887Sjmallett
31190744Sjmallett    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
31290744Sjmallett        " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
31390744Sjmallett        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
31490744Sjmallett        RgnDesc->Region.SpaceId,
31590744Sjmallett        ObjDesc->CommonField.AccessByteWidth,
31690744Sjmallett        ObjDesc->CommonField.BaseByteOffset,
31790744Sjmallett        FieldDatumByteOffset,
31890744Sjmallett        ACPI_FORMAT_UINT64 (Address)));
31990744Sjmallett
32090744Sjmallett    /* Invoke the appropriate AddressSpace/OpRegion handler */
32190744Sjmallett
32290744Sjmallett    Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function,
32390744Sjmallett                    Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
324100014Sjmallett
32590744Sjmallett    if (ACPI_FAILURE (Status))
326100014Sjmallett    {
32790744Sjmallett        if (Status == AE_NOT_IMPLEMENTED)
328100014Sjmallett        {
32990744Sjmallett            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
33090744Sjmallett                "Region %s(%X) not implemented\n",
33190744Sjmallett                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
33290744Sjmallett                RgnDesc->Region.SpaceId));
33390744Sjmallett        }
33490744Sjmallett        else if (Status == AE_NOT_EXIST)
33590744Sjmallett        {
33690744Sjmallett            ACPI_REPORT_ERROR ((
33790744Sjmallett                "Region %s(%X) has no handler\n",
33890744Sjmallett                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
33990744Sjmallett                RgnDesc->Region.SpaceId));
34090744Sjmallett        }
34190744Sjmallett    }
34290744Sjmallett
34390744Sjmallett    return_ACPI_STATUS (Status);
34490744Sjmallett}
34590744Sjmallett
34690744Sjmallett
34790744Sjmallett/*******************************************************************************
34890744Sjmallett *
349100014Sjmallett * FUNCTION:    AcpiExRegisterOverflow
35095887Sjmallett *
35190744Sjmallett * PARAMETERS:  *ObjDesc                - Register(Field) to be written
35290744Sjmallett *              Value                   - Value to be stored
35390744Sjmallett *
35490744Sjmallett * RETURN:      TRUE if value overflows the field, FALSE otherwise
355100014Sjmallett *
35690744Sjmallett * DESCRIPTION: Check if a value is out of range of the field being written.
35790744Sjmallett *              Used to check if the values written to Index and Bank registers
35890744Sjmallett *              are out of range.  Normally, the value is simply truncated
35990744Sjmallett *              to fit the field, but this case is most likely a serious
36090744Sjmallett *              coding error in the ASL.
36190744Sjmallett *
36290744Sjmallett ******************************************************************************/
36390744Sjmallett
36490744SjmallettBOOLEAN
36590744SjmallettAcpiExRegisterOverflow (
366100014Sjmallett    ACPI_OPERAND_OBJECT     *ObjDesc,
36795887Sjmallett    ACPI_INTEGER            Value)
36890744Sjmallett{
36990744Sjmallett
37090744Sjmallett    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
37190744Sjmallett    {
37290744Sjmallett        /*
37390744Sjmallett         * The field is large enough to hold the maximum integer, so we can
37490744Sjmallett         * never overflow it.
37590744Sjmallett         */
37690744Sjmallett        return (FALSE);
37790744Sjmallett    }
37890744Sjmallett
37990744Sjmallett    if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
38090744Sjmallett    {
38190744Sjmallett        /*
38290744Sjmallett         * The Value is larger than the maximum value that can fit into
38390744Sjmallett         * the register.
38490744Sjmallett         */
38590744Sjmallett        return (TRUE);
38690744Sjmallett    }
38795887Sjmallett
38890744Sjmallett    /* The Value will fit into the field with no truncation */
38990744Sjmallett
39090744Sjmallett    return (FALSE);
39190744Sjmallett}
39290744Sjmallett
39390744Sjmallett
39490744Sjmallett/*******************************************************************************
39590744Sjmallett *
39690744Sjmallett * FUNCTION:    AcpiExFieldDatumIo
39790744Sjmallett *
39890744Sjmallett * PARAMETERS:  *ObjDesc                - Field to be read
39990744Sjmallett *              FieldDatumByteOffset    - Byte offset of this datum within the
40090744Sjmallett *                                        parent field
40190744Sjmallett *              *Value                  - Where to store value (must be 64 bits)
40290744Sjmallett *              ReadWrite               - Read or Write flag
40390744Sjmallett *
40490744Sjmallett * RETURN:      Status
40590744Sjmallett *
40690744Sjmallett * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
40790744Sjmallett *              demultiplexed here to handle the different types of fields
40890744Sjmallett *              (BufferField, RegionField, IndexField, BankField)
40990744Sjmallett *
41090744Sjmallett ******************************************************************************/
41190744Sjmallett
41290744SjmallettACPI_STATUS
41390744SjmallettAcpiExFieldDatumIo (
41490744Sjmallett    ACPI_OPERAND_OBJECT     *ObjDesc,
41590744Sjmallett    UINT32                  FieldDatumByteOffset,
41690744Sjmallett    ACPI_INTEGER            *Value,
41790744Sjmallett    UINT32                  ReadWrite)
41890744Sjmallett{
41990744Sjmallett    ACPI_STATUS             Status;
42090744Sjmallett    ACPI_INTEGER            LocalValue;
42190744Sjmallett
42290744Sjmallett
42390744Sjmallett    ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
42490744Sjmallett
42590744Sjmallett
42690744Sjmallett    if (ReadWrite == ACPI_READ)
42790744Sjmallett    {
42890744Sjmallett        if (!Value)
42990744Sjmallett        {
43090744Sjmallett            LocalValue = 0;
43190744Sjmallett            Value = &LocalValue;  /* To support reads without saving return value */
43295887Sjmallett        }
43390744Sjmallett
43490744Sjmallett        /* Clear the entire return buffer first, [Very Important!] */
43590744Sjmallett
43690744Sjmallett        *Value = 0;
43790744Sjmallett    }
43890744Sjmallett
43990744Sjmallett    /*
44090744Sjmallett     * The four types of fields are:
44190744Sjmallett     *
442100014Sjmallett     * BufferField - Read/write from/to a Buffer
44390744Sjmallett     * RegionField - Read/write from/to a Operation Region.
44490744Sjmallett     * BankField   - Write to a Bank Register, then read/write from/to an OpRegion
44590744Sjmallett     * IndexField  - Write to an Index Register, then read/write from/to a Data Register
446100014Sjmallett     */
44790744Sjmallett    switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
448100014Sjmallett    {
44990744Sjmallett    case ACPI_TYPE_BUFFER_FIELD:
45090744Sjmallett        /*
45190744Sjmallett         * If the BufferField arguments have not been previously evaluated,
45290744Sjmallett         * evaluate them now and save the results.
45390744Sjmallett         */
45490744Sjmallett        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
45590744Sjmallett        {
45695887Sjmallett            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
45790744Sjmallett            if (ACPI_FAILURE (Status))
45890744Sjmallett            {
45990744Sjmallett                return_ACPI_STATUS (Status);
46090744Sjmallett            }
46190744Sjmallett        }
46290744Sjmallett
46390744Sjmallett        if (ReadWrite == ACPI_READ)
46490744Sjmallett        {
46590744Sjmallett            /*
466100014Sjmallett             * Copy the data from the source buffer.
46790744Sjmallett             * Length is the field width in bytes.
46890744Sjmallett             */
46990744Sjmallett            ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
470100014Sjmallett                            + ObjDesc->BufferField.BaseByteOffset
47190744Sjmallett                            + FieldDatumByteOffset,
47290744Sjmallett                            ObjDesc->CommonField.AccessByteWidth);
47390744Sjmallett        }
47490744Sjmallett        else
47590744Sjmallett        {
47690744Sjmallett            /*
47790744Sjmallett             * Copy the data to the target buffer.
47890744Sjmallett             * Length is the field width in bytes.
47990744Sjmallett             */
48090744Sjmallett            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
48195887Sjmallett                    + ObjDesc->BufferField.BaseByteOffset
48290744Sjmallett                    + FieldDatumByteOffset,
48390744Sjmallett                    Value, ObjDesc->CommonField.AccessByteWidth);
48490744Sjmallett        }
48590744Sjmallett
48690744Sjmallett        Status = AE_OK;
48790744Sjmallett        break;
48890744Sjmallett
48990744Sjmallett
49090744Sjmallett    case ACPI_TYPE_LOCAL_BANK_FIELD:
49190744Sjmallett
49290744Sjmallett        /* Ensure that the BankValue is not beyond the capacity of the register */
49390744Sjmallett
49490744Sjmallett        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
49590744Sjmallett                                    (ACPI_INTEGER) ObjDesc->BankField.Value))
49690744Sjmallett        {
49790744Sjmallett            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
49890744Sjmallett        }
49990744Sjmallett
50090744Sjmallett        /*
50190744Sjmallett         * For BankFields, we must write the BankValue to the BankRegister
502129392Sstefanf         * (itself a RegionField) before we can access the data.
50390744Sjmallett         */
50490744Sjmallett        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
50590744Sjmallett                                &ObjDesc->BankField.Value,
50690744Sjmallett                                sizeof (ObjDesc->BankField.Value));
50790744Sjmallett        if (ACPI_FAILURE (Status))
50890744Sjmallett        {
50990744Sjmallett            return_ACPI_STATUS (Status);
51090744Sjmallett        }
51190744Sjmallett
51290744Sjmallett        /*
51390744Sjmallett         * Now that the Bank has been selected, fall through to the
51490744Sjmallett         * RegionField case and write the datum to the Operation Region
51590744Sjmallett         */
51690744Sjmallett
51790744Sjmallett        /*lint -fallthrough */
51890744Sjmallett
51990744Sjmallett
52090744Sjmallett    case ACPI_TYPE_LOCAL_REGION_FIELD:
521        /*
522         * For simple RegionFields, we just directly access the owning
523         * Operation Region.
524         */
525        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
526                        ReadWrite);
527        break;
528
529
530    case ACPI_TYPE_LOCAL_INDEX_FIELD:
531
532
533        /* Ensure that the IndexValue is not beyond the capacity of the register */
534
535        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
536                                    (ACPI_INTEGER) ObjDesc->IndexField.Value))
537        {
538            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
539        }
540
541        /* Write the index value to the IndexRegister (itself a RegionField) */
542
543        FieldDatumByteOffset += ObjDesc->IndexField.Value;
544
545        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
546                "Write to Index Register: Value %8.8X\n",
547                FieldDatumByteOffset));
548
549        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
550                                &FieldDatumByteOffset,
551                                sizeof (FieldDatumByteOffset));
552        if (ACPI_FAILURE (Status))
553        {
554            return_ACPI_STATUS (Status);
555        }
556
557        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
558                "I/O to Data Register: ValuePtr %p\n",
559                Value));
560
561        if (ReadWrite == ACPI_READ)
562        {
563            /* Read the datum from the DataRegister */
564
565            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
566                            Value, sizeof (ACPI_INTEGER));
567        }
568        else
569        {
570            /* Write the datum to the DataRegister */
571
572            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
573                            Value, sizeof (ACPI_INTEGER));
574        }
575        break;
576
577
578    default:
579
580        ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n",
581            ACPI_GET_OBJECT_TYPE (ObjDesc)));
582        Status = AE_AML_INTERNAL;
583        break;
584    }
585
586    if (ACPI_SUCCESS (Status))
587    {
588        if (ReadWrite == ACPI_READ)
589        {
590            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n",
591                                ACPI_FORMAT_UINT64 (*Value),
592                                ObjDesc->CommonField.AccessByteWidth));
593        }
594        else
595        {
596            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n",
597                                ACPI_FORMAT_UINT64 (*Value),
598                                ObjDesc->CommonField.AccessByteWidth));
599        }
600    }
601
602    return_ACPI_STATUS (Status);
603}
604
605
606/*******************************************************************************
607 *
608 * FUNCTION:    AcpiExWriteWithUpdateRule
609 *
610 * PARAMETERS:  *ObjDesc            - Field to be set
611 *              Value               - Value to store
612 *
613 * RETURN:      Status
614 *
615 * DESCRIPTION: Apply the field update rule to a field write
616 *
617 ******************************************************************************/
618
619ACPI_STATUS
620AcpiExWriteWithUpdateRule (
621    ACPI_OPERAND_OBJECT     *ObjDesc,
622    ACPI_INTEGER            Mask,
623    ACPI_INTEGER            FieldValue,
624    UINT32                  FieldDatumByteOffset)
625{
626    ACPI_STATUS             Status = AE_OK;
627    ACPI_INTEGER            MergedValue;
628    ACPI_INTEGER            CurrentValue;
629
630
631    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
632
633
634    /* Start with the new bits  */
635
636    MergedValue = FieldValue;
637
638    /* If the mask is all ones, we don't need to worry about the update rule */
639
640    if (Mask != ACPI_INTEGER_MAX)
641    {
642        /* Decode the update rule */
643
644        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
645        {
646        case AML_FIELD_UPDATE_PRESERVE:
647            /*
648             * Check if update rule needs to be applied (not if mask is all
649             * ones)  The left shift drops the bits we want to ignore.
650             */
651            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
652                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
653            {
654                /*
655                 * Read the current contents of the byte/word/dword containing
656                 * the field, and merge with the new field value.
657                 */
658                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
659                                &CurrentValue, ACPI_READ);
660                if (ACPI_FAILURE (Status))
661                {
662                    return_ACPI_STATUS (Status);
663                }
664
665                MergedValue |= (CurrentValue & ~Mask);
666            }
667            break;
668
669        case AML_FIELD_UPDATE_WRITE_AS_ONES:
670
671            /* Set positions outside the field to all ones */
672
673            MergedValue |= ~Mask;
674            break;
675
676        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
677
678            /* Set positions outside the field to all zeros */
679
680            MergedValue &= Mask;
681            break;
682
683        default:
684
685            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
686                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
687                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
688            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
689        }
690    }
691
692    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
693        "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
694        ACPI_FORMAT_UINT64 (Mask),
695        FieldDatumByteOffset,
696        ObjDesc->CommonField.AccessByteWidth,
697        ACPI_FORMAT_UINT64 (FieldValue),
698        ACPI_FORMAT_UINT64 (MergedValue)));
699
700    /* Write the merged value */
701
702    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
703                    &MergedValue, ACPI_WRITE);
704
705    return_ACPI_STATUS (Status);
706}
707
708
709/*******************************************************************************
710 *
711 * FUNCTION:    AcpiExGetBufferDatum
712 *
713 * PARAMETERS:  Datum               - Where the Datum is returned
714 *              Buffer              - Raw field buffer
715 *              BufferLength        - Entire length (used for big-endian only)
716 *              ByteGranularity     - 1/2/4/8 Granularity of the field
717 *                                    (aka Datum Size)
718 *              BufferOffset        - Datum offset into the buffer
719 *
720 * RETURN:      none
721 *
722 * DESCRIPTION: Get a datum from the buffer according to the buffer field
723 *              byte granularity
724 *
725 ******************************************************************************/
726
727void
728AcpiExGetBufferDatum (
729    ACPI_INTEGER            *Datum,
730    void                    *Buffer,
731    UINT32                  BufferLength,
732    UINT32                  ByteGranularity,
733    UINT32                  BufferOffset)
734{
735    UINT32                  Index;
736
737
738    ACPI_FUNCTION_TRACE_U32 ("ExGetBufferDatum", ByteGranularity);
739
740
741    /* Get proper index into buffer (handles big/little endian) */
742
743    Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
744
745    /* Move the requested number of bytes */
746
747    switch (ByteGranularity)
748    {
749    case ACPI_FIELD_BYTE_GRANULARITY:
750
751        *Datum = ((UINT8 *) Buffer) [Index];
752        break;
753
754    case ACPI_FIELD_WORD_GRANULARITY:
755
756        ACPI_MOVE_16_TO_64 (Datum, &(((UINT16 *) Buffer) [Index]));
757        break;
758
759    case ACPI_FIELD_DWORD_GRANULARITY:
760
761        ACPI_MOVE_32_TO_64 (Datum, &(((UINT32 *) Buffer) [Index]));
762        break;
763
764    case ACPI_FIELD_QWORD_GRANULARITY:
765
766        ACPI_MOVE_64_TO_64 (Datum, &(((UINT64 *) Buffer) [Index]));
767        break;
768
769    default:
770        /* Should not get here */
771        break;
772    }
773
774    return_VOID;
775}
776
777
778/*******************************************************************************
779 *
780 * FUNCTION:    AcpiExSetBufferDatum
781 *
782 * PARAMETERS:  MergedDatum         - Value to store
783 *              Buffer              - Receiving buffer
784 *              BufferLength        - Entire length (used for big-endian only)
785 *              ByteGranularity     - 1/2/4/8 Granularity of the field
786 *                                    (aka Datum Size)
787 *              BufferOffset        - Datum offset into the buffer
788 *
789 * RETURN:      none
790 *
791 * DESCRIPTION: Store the merged datum to the buffer according to the
792 *              byte granularity
793 *
794 ******************************************************************************/
795
796void
797AcpiExSetBufferDatum (
798    ACPI_INTEGER            MergedDatum,
799    void                    *Buffer,
800    UINT32                  BufferLength,
801    UINT32                  ByteGranularity,
802    UINT32                  BufferOffset)
803{
804    UINT32                  Index;
805
806
807    ACPI_FUNCTION_TRACE_U32 ("ExSetBufferDatum", ByteGranularity);
808
809
810    /* Get proper index into buffer (handles big/little endian) */
811
812    Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
813
814    /* Move the requested number of bytes */
815
816    switch (ByteGranularity)
817    {
818    case ACPI_FIELD_BYTE_GRANULARITY:
819
820        ((UINT8 *) Buffer) [Index] = (UINT8) MergedDatum;
821        break;
822
823    case ACPI_FIELD_WORD_GRANULARITY:
824
825        ACPI_MOVE_64_TO_16 (&(((UINT16 *) Buffer)[Index]), &MergedDatum);
826        break;
827
828    case ACPI_FIELD_DWORD_GRANULARITY:
829
830        ACPI_MOVE_64_TO_32 (&(((UINT32 *) Buffer)[Index]), &MergedDatum);
831        break;
832
833    case ACPI_FIELD_QWORD_GRANULARITY:
834
835        ACPI_MOVE_64_TO_64 (&(((UINT64 *) Buffer)[Index]), &MergedDatum);
836        break;
837
838    default:
839        /* Should not get here */
840        break;
841    }
842
843    return_VOID;
844}
845
846
847/*******************************************************************************
848 *
849 * FUNCTION:    AcpiExExtractFromField
850 *
851 * PARAMETERS:  *ObjDesc            - Field to be read
852 *              *Value              - Where to store value
853 *
854 * RETURN:      Status
855 *
856 * DESCRIPTION: Retrieve the value of the given field
857 *
858 ******************************************************************************/
859
860ACPI_STATUS
861AcpiExExtractFromField (
862    ACPI_OPERAND_OBJECT     *ObjDesc,
863    void                    *Buffer,
864    UINT32                  BufferLength)
865{
866    ACPI_STATUS             Status;
867    UINT32                  FieldDatumByteOffset;
868    UINT32                  BufferDatumOffset;
869    ACPI_INTEGER            PreviousRawDatum = 0;
870    ACPI_INTEGER            ThisRawDatum = 0;
871    ACPI_INTEGER            MergedDatum = 0;
872    UINT32                  ByteFieldLength;
873    UINT32                  DatumCount;
874    UINT32                  i;
875
876
877    ACPI_FUNCTION_TRACE ("ExExtractFromField");
878
879
880    /*
881     * The field must fit within the caller's buffer
882     */
883    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
884    if (ByteFieldLength > BufferLength)
885    {
886        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
887            "Field size %X (bytes) too large for buffer (%X)\n",
888            ByteFieldLength, BufferLength));
889
890        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
891    }
892
893    /* Convert field byte count to datum count, round up if necessary */
894
895    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
896                              ObjDesc->CommonField.AccessByteWidth);
897
898    /*
899     * If the field is not aligned on a datum boundary and does not
900     * fit within a single datum, we must read an extra datum.
901     *
902     * We could just split the aligned and non-aligned cases since the
903     * aligned case is so very simple, but this would require more code.
904     */
905    if ((ObjDesc->CommonField.EndFieldValidBits != 0)         &&
906        (!(ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)))
907    {
908        DatumCount++;
909    }
910
911    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
912        "ByteLen %X, DatumLen %X, ByteGran %X\n",
913        ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth));
914
915    /*
916     * Clear the caller's buffer (the whole buffer length as given)
917     * This is very important, especially in the cases where the buffer
918     * is longer than the size of the field.
919     */
920    ACPI_MEMSET (Buffer, 0, BufferLength);
921
922    FieldDatumByteOffset = 0;
923    BufferDatumOffset= 0;
924
925    /* Read the entire field */
926
927    for (i = 0; i < DatumCount; i++)
928    {
929        Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
930                        &ThisRawDatum, ACPI_READ);
931        if (ACPI_FAILURE (Status))
932        {
933            return_ACPI_STATUS (Status);
934        }
935
936        /* We might actually be done if the request fits in one datum */
937
938        if ((DatumCount == 1) &&
939            (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
940        {
941            /* 1) Shift the valid data bits down to start at bit 0 */
942
943            MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
944
945            /* 2) Mask off any upper unused bits (bits not part of the field) */
946
947            if (ObjDesc->CommonField.EndBufferValidBits)
948            {
949                MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
950            }
951
952            /* Store the datum to the caller buffer */
953
954            AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
955                    ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
956
957            return_ACPI_STATUS (AE_OK);
958        }
959
960        /* Special handling for the last datum to ignore extra bits */
961
962        if ((i >= (DatumCount -1))           &&
963            (ObjDesc->CommonField.EndFieldValidBits))
964        {
965            /*
966             * This is the last iteration of the loop.  We need to clear
967             * any unused bits (bits that are not part of this field) before
968             * we store the final merged datum into the caller buffer.
969             */
970            ThisRawDatum &=
971                ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
972        }
973
974        /*
975         * Create the (possibly) merged datum to be stored to the caller buffer
976         */
977        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
978        {
979            /* Field is not skewed and we can just copy the datum */
980
981            AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength,
982                    ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
983            BufferDatumOffset++;
984        }
985        else
986        {
987            /* Not aligned -- on the first iteration, just save the datum */
988
989            if (i != 0)
990            {
991                /*
992                 * Put together the appropriate bits of the two raw data to make a
993                 * single complete field datum
994                 *
995                 * 1) Normalize the first datum down to bit 0
996                 */
997                MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
998
999                /* 2) Insert the second datum "above" the first datum */
1000
1001                MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
1002
1003                AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1004                        ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1005                BufferDatumOffset++;
1006            }
1007
1008            /*
1009             * Save the raw datum that was just acquired since it may contain bits
1010             * of the *next* field datum
1011             */
1012            PreviousRawDatum = ThisRawDatum;
1013        }
1014
1015        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1016    }
1017
1018    /* For non-aligned case, there is one last datum to insert */
1019
1020    if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1021    {
1022        MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1023
1024        AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1025                ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1026    }
1027
1028    return_ACPI_STATUS (AE_OK);
1029}
1030
1031
1032/*******************************************************************************
1033 *
1034 * FUNCTION:    AcpiExInsertIntoField
1035 *
1036 * PARAMETERS:  *ObjDesc            - Field to be set
1037 *              Buffer              - Value to store
1038 *
1039 * RETURN:      Status
1040 *
1041 * DESCRIPTION: Store the value into the given field
1042 *
1043 ******************************************************************************/
1044
1045ACPI_STATUS
1046AcpiExInsertIntoField (
1047    ACPI_OPERAND_OBJECT     *ObjDesc,
1048    void                    *Buffer,
1049    UINT32                  BufferLength)
1050{
1051    ACPI_STATUS             Status;
1052    UINT32                  FieldDatumByteOffset;
1053    UINT32                  DatumOffset;
1054    ACPI_INTEGER            Mask;
1055    ACPI_INTEGER            MergedDatum;
1056    ACPI_INTEGER            PreviousRawDatum;
1057    ACPI_INTEGER            ThisRawDatum;
1058    UINT32                  ByteFieldLength;
1059    UINT32                  DatumCount;
1060
1061
1062    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
1063
1064
1065    /*
1066     * Incoming buffer must be at least as long as the field, we do not
1067     * allow "partial" field writes.  We do not care if the buffer is
1068     * larger than the field, this typically happens when an integer is
1069     * written to a field that is actually smaller than an integer.
1070     */
1071    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
1072                            ObjDesc->CommonField.BitLength);
1073    if (BufferLength < ByteFieldLength)
1074    {
1075        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
1076            "Buffer length %X too small for field %X\n",
1077            BufferLength, ByteFieldLength));
1078
1079        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
1080    }
1081
1082    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
1083                            ObjDesc->CommonField.StartFieldBitOffset +
1084                            ObjDesc->CommonField.BitLength);
1085
1086    /* Convert byte count to datum count, round up if necessary */
1087
1088    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
1089                                   ObjDesc->CommonField.AccessByteWidth);
1090
1091    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
1092        "Bytes %X, Datums %X, ByteGran %X\n",
1093        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth));
1094
1095    /*
1096     * Break the request into up to three parts (similar to an I/O request):
1097     * 1) non-aligned part at start
1098     * 2) aligned part in middle
1099     * 3) non-aligned part at the end
1100     */
1101    FieldDatumByteOffset = 0;
1102    DatumOffset= 0;
1103
1104    /* Get a single datum from the caller's buffer */
1105
1106    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength,
1107            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1108
1109    /*
1110     * Part1:
1111     * Write a partial field datum if field does not begin on a datum boundary
1112     * Note: The code in this section also handles the aligned case
1113     *
1114     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1115     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1116     *
1117     * Mask off bits that are "below" the field (if any)
1118     */
1119    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1120
1121    /* If the field fits in one datum, may need to mask upper bits */
1122
1123    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1124         ObjDesc->CommonField.EndFieldValidBits)
1125    {
1126        /* There are bits above the field, mask them off also */
1127
1128        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1129    }
1130
1131    /* Shift and mask the value into the field position */
1132
1133    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1134    MergedDatum &= Mask;
1135
1136    /* Apply the update rule (if necessary) and write the datum to the field */
1137
1138    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1139                        FieldDatumByteOffset);
1140    if (ACPI_FAILURE (Status))
1141    {
1142        return_ACPI_STATUS (Status);
1143    }
1144
1145    /* We just wrote the first datum */
1146
1147    DatumOffset++;
1148
1149    /* If the entire field fits within one datum, we are done. */
1150
1151    if ((DatumCount == 1) &&
1152       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1153    {
1154        return_ACPI_STATUS (AE_OK);
1155    }
1156
1157    /*
1158     * Part2:
1159     * Write the aligned data.
1160     *
1161     * We don't need to worry about the update rule for these data, because
1162     * all of the bits in each datum are part of the field.
1163     *
1164     * The last datum must be special cased because it might contain bits
1165     * that are not part of the field -- therefore the "update rule" must be
1166     * applied in Part3 below.
1167     */
1168    while (DatumOffset < DatumCount)
1169    {
1170        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1171
1172        /*
1173         * Get the next raw buffer datum.  It may contain bits of the previous
1174         * field datum
1175         */
1176        AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength,
1177                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1178
1179        /* Create the field datum based on the field alignment */
1180
1181        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1182        {
1183            /*
1184             * Put together appropriate bits of the two raw buffer data to make
1185             * a single complete field datum
1186             */
1187            MergedDatum =
1188                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1189                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1190        }
1191        else
1192        {
1193            /* Field began aligned on datum boundary */
1194
1195            MergedDatum = ThisRawDatum;
1196        }
1197
1198        /*
1199         * Special handling for the last datum if the field does NOT end on
1200         * a datum boundary.  Update Rule must be applied to the bits outside
1201         * the field.
1202         */
1203        DatumOffset++;
1204        if ((DatumOffset == DatumCount) &&
1205            (ObjDesc->CommonField.EndFieldValidBits))
1206        {
1207            /*
1208             * If there are dangling non-aligned bits, perform one more merged write
1209             * Else - field is aligned at the end, no need for any more writes
1210             */
1211
1212            /*
1213             * Part3:
1214             * This is the last datum and the field does not end on a datum boundary.
1215             * Build the partial datum and write with the update rule.
1216             *
1217             * Mask off the unused bits above (after) the end-of-field
1218             */
1219            Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1220            MergedDatum &= Mask;
1221
1222            /* Write the last datum with the update rule */
1223
1224            Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1225                                FieldDatumByteOffset);
1226            if (ACPI_FAILURE (Status))
1227            {
1228                return_ACPI_STATUS (Status);
1229            }
1230        }
1231        else
1232        {
1233            /* Normal (aligned) case -- write the completed datum */
1234
1235            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1236                            &MergedDatum, ACPI_WRITE);
1237            if (ACPI_FAILURE (Status))
1238            {
1239                return_ACPI_STATUS (Status);
1240            }
1241        }
1242
1243        /*
1244         * Save the most recent datum since it may contain bits of the *next*
1245         * field datum.  Update current byte offset.
1246         */
1247        PreviousRawDatum = ThisRawDatum;
1248    }
1249
1250    return_ACPI_STATUS (Status);
1251}
1252
1253
1254