exfldio.c revision 209746
167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exfldio - Aml Field I/O
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
767754Smsmith/******************************************************************************
867754Smsmith *
967754Smsmith * 1. Copyright Notice
1067754Smsmith *
11202771Sjkim * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp.
1270243Smsmith * All rights reserved.
1367754Smsmith *
1467754Smsmith * 2. License
1567754Smsmith *
1667754Smsmith * 2.1. This is your license from Intel Corp. under its intellectual property
1767754Smsmith * rights.  You may have additional license terms from the party that provided
1867754Smsmith * you this software, covering your right to use that party's intellectual
1967754Smsmith * property rights.
2067754Smsmith *
2167754Smsmith * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
2267754Smsmith * copy of the source code appearing in this file ("Covered Code") an
2367754Smsmith * irrevocable, perpetual, worldwide license under Intel's copyrights in the
2467754Smsmith * base code distributed originally by Intel ("Original Intel Code") to copy,
2567754Smsmith * make derivatives, distribute, use and display any portion of the Covered
2667754Smsmith * Code in any form, with the right to sublicense such rights; and
2767754Smsmith *
2867754Smsmith * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
2967754Smsmith * license (with the right to sublicense), under only those claims of Intel
3067754Smsmith * patents that are infringed by the Original Intel Code, to make, use, sell,
3167754Smsmith * offer to sell, and import the Covered Code and derivative works thereof
3267754Smsmith * solely to the minimum extent necessary to exercise the above copyright
3367754Smsmith * license, and in no event shall the patent license extend to any additions
3467754Smsmith * to or modifications of the Original Intel Code.  No other license or right
3567754Smsmith * is granted directly or by implication, estoppel or otherwise;
3667754Smsmith *
3767754Smsmith * The above copyright and patent license is granted only if the following
3867754Smsmith * conditions are met:
3967754Smsmith *
4067754Smsmith * 3. Conditions
4167754Smsmith *
4267754Smsmith * 3.1. Redistribution of Source with Rights to Further Distribute Source.
4367754Smsmith * Redistribution of source code of any substantial portion of the Covered
4467754Smsmith * Code or modification with rights to further distribute source must include
4567754Smsmith * the above Copyright Notice, the above License, this list of Conditions,
4667754Smsmith * and the following Disclaimer and Export Compliance provision.  In addition,
4767754Smsmith * Licensee must cause all Covered Code to which Licensee contributes to
4867754Smsmith * contain a file documenting the changes Licensee made to create that Covered
4967754Smsmith * Code and the date of any change.  Licensee must include in that file the
5067754Smsmith * documentation of any changes made by any predecessor Licensee.  Licensee
5167754Smsmith * must include a prominent statement that the modification is derived,
5267754Smsmith * directly or indirectly, from Original Intel Code.
5367754Smsmith *
5467754Smsmith * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
5567754Smsmith * Redistribution of source code of any substantial portion of the Covered
5667754Smsmith * Code or modification without rights to further distribute source must
5767754Smsmith * include the following Disclaimer and Export Compliance provision in the
5867754Smsmith * documentation and/or other materials provided with distribution.  In
5967754Smsmith * addition, Licensee may not authorize further sublicense of source of any
6067754Smsmith * portion of the Covered Code, and must include terms to the effect that the
6167754Smsmith * license from Licensee to its licensee is limited to the intellectual
6267754Smsmith * property embodied in the software Licensee provides to its licensee, and
6367754Smsmith * not to intellectual property embodied in modifications its licensee may
6467754Smsmith * make.
6567754Smsmith *
6667754Smsmith * 3.3. Redistribution of Executable. Redistribution in executable form of any
6767754Smsmith * substantial portion of the Covered Code or modification must reproduce the
6867754Smsmith * above Copyright Notice, and the following Disclaimer and Export Compliance
6967754Smsmith * provision in the documentation and/or other materials provided with the
7067754Smsmith * distribution.
7167754Smsmith *
7267754Smsmith * 3.4. Intel retains all right, title, and interest in and to the Original
7367754Smsmith * Intel Code.
7467754Smsmith *
7567754Smsmith * 3.5. Neither the name Intel nor any other trademark owned or controlled by
7667754Smsmith * Intel shall be used in advertising or otherwise to promote the sale, use or
7767754Smsmith * other dealings in products derived from or relating to the Covered Code
7867754Smsmith * without prior written authorization from Intel.
7967754Smsmith *
8067754Smsmith * 4. Disclaimer and Export Compliance
8167754Smsmith *
8267754Smsmith * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
8367754Smsmith * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
8467754Smsmith * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
8567754Smsmith * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
8667754Smsmith * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
8767754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
8867754Smsmith * PARTICULAR PURPOSE.
8967754Smsmith *
9067754Smsmith * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
9167754Smsmith * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
9267754Smsmith * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
9367754Smsmith * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
9467754Smsmith * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
9567754Smsmith * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
9667754Smsmith * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
9767754Smsmith * LIMITED REMEDY.
9867754Smsmith *
9967754Smsmith * 4.3. Licensee shall not export, either directly or indirectly, any of this
10067754Smsmith * software or system incorporating such software without first obtaining any
10167754Smsmith * required license or other approval from the U. S. Department of Commerce or
10267754Smsmith * any other agency or department of the United States Government.  In the
10367754Smsmith * event Licensee exports any such software from the United States or
10467754Smsmith * re-exports any such software from a foreign destination, Licensee shall
10567754Smsmith * ensure that the distribution and export/re-export of the software is in
10667754Smsmith * compliance with all laws, regulations, orders, or other restrictions of the
10767754Smsmith * U.S. Export Administration Regulations. Licensee agrees that neither it nor
10867754Smsmith * any of its subsidiaries will export/re-export any technical data, process,
10967754Smsmith * software, or service, directly or indirectly, to any country for which the
11067754Smsmith * United States government or any agency thereof requires an export license,
11167754Smsmith * other governmental approval, or letter of assurance, without first obtaining
11267754Smsmith * such license, approval or letter.
11367754Smsmith *
11467754Smsmith *****************************************************************************/
11567754Smsmith
11667754Smsmith
11777424Smsmith#define __EXFLDIO_C__
11867754Smsmith
119193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
120193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
121193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
122193341Sjkim#include <contrib/dev/acpica/include/amlcode.h>
123193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
124193341Sjkim#include <contrib/dev/acpica/include/acdispat.h>
12567754Smsmith
12667754Smsmith
12777424Smsmith#define _COMPONENT          ACPI_EXECUTER
12891116Smsmith        ACPI_MODULE_NAME    ("exfldio")
12967754Smsmith
130151937Sjkim/* Local prototypes */
13167754Smsmith
132151937Sjkimstatic ACPI_STATUS
133151937SjkimAcpiExFieldDatumIo (
134151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
135151937Sjkim    UINT32                  FieldDatumByteOffset,
136202771Sjkim    UINT64                  *Value,
137151937Sjkim    UINT32                  ReadWrite);
138151937Sjkim
139151937Sjkimstatic BOOLEAN
140151937SjkimAcpiExRegisterOverflow (
141151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
142202771Sjkim    UINT64                  Value);
143151937Sjkim
144151937Sjkimstatic ACPI_STATUS
145151937SjkimAcpiExSetupRegion (
146151937Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
147151937Sjkim    UINT32                  FieldDatumByteOffset);
148151937Sjkim
149151937Sjkim
15067754Smsmith/*******************************************************************************
15167754Smsmith *
15287031Smsmith * FUNCTION:    AcpiExSetupRegion
15367754Smsmith *
154151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be read or written
15587031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
15687031Smsmith *                                        parent field
15767754Smsmith *
15867754Smsmith * RETURN:      Status
15967754Smsmith *
16077424Smsmith * DESCRIPTION: Common processing for AcpiExExtractFromField and
161123315Snjl *              AcpiExInsertIntoField.  Initialize the Region if necessary and
162123315Snjl *              validate the request.
16367754Smsmith *
16467754Smsmith ******************************************************************************/
16567754Smsmith
166151937Sjkimstatic ACPI_STATUS
16787031SmsmithAcpiExSetupRegion (
16867754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
16977424Smsmith    UINT32                  FieldDatumByteOffset)
17067754Smsmith{
17177424Smsmith    ACPI_STATUS             Status = AE_OK;
17277424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
17367754Smsmith
17467754Smsmith
175167802Sjkim    ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
17667754Smsmith
17783174Smsmith
17877424Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
17967754Smsmith
180107325Siwasaki    /* We must have a valid region */
181107325Siwasaki
182193267Sjkim    if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
18377424Smsmith    {
184204773Sjkim        ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
185193267Sjkim            RgnDesc->Common.Type,
18699679Siwasaki            AcpiUtGetObjectTypeName (RgnDesc)));
18799679Siwasaki
18877424Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
18977424Smsmith    }
19067754Smsmith
19177424Smsmith    /*
19277424Smsmith     * If the Region Address and Length have not been previously evaluated,
19377424Smsmith     * evaluate them now and save the results.
19477424Smsmith     */
195123315Snjl    if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
19667754Smsmith    {
19777424Smsmith        Status = AcpiDsGetRegionArguments (RgnDesc);
19877424Smsmith        if (ACPI_FAILURE (Status))
19977424Smsmith        {
20077424Smsmith            return_ACPI_STATUS (Status);
20177424Smsmith        }
20267754Smsmith    }
20367754Smsmith
204167802Sjkim    /*
205197104Sjkim     * Exit now for SMBus or IPMI address space, it has a non-linear address space
206167802Sjkim     * and the request cannot be directly validated
207167802Sjkim     */
208197104Sjkim    if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
209197104Sjkim        RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI)
210107325Siwasaki    {
211197104Sjkim        /* SMBus or IPMI has a non-linear address space */
212107325Siwasaki
213107325Siwasaki        return_ACPI_STATUS (AE_OK);
214107325Siwasaki    }
215107325Siwasaki
216123315Snjl#ifdef ACPI_UNDER_DEVELOPMENT
21777424Smsmith    /*
218123315Snjl     * If the Field access is AnyAcc, we can now compute the optimal
219123315Snjl     * access (because we know know the length of the parent region)
220123315Snjl     */
221123315Snjl    if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
222123315Snjl    {
223123315Snjl        if (ACPI_FAILURE (Status))
224123315Snjl        {
225123315Snjl            return_ACPI_STATUS (Status);
226123315Snjl        }
227123315Snjl    }
228123315Snjl#endif
229123315Snjl
230123315Snjl    /*
23177424Smsmith     * Validate the request.  The entire request from the byte offset for a
23277424Smsmith     * length of one field datum (access width) must fit within the region.
23377424Smsmith     * (Region length is specified in bytes)
23477424Smsmith     */
235167802Sjkim    if (RgnDesc->Region.Length <
236167802Sjkim            (ObjDesc->CommonField.BaseByteOffset +
237167802Sjkim            FieldDatumByteOffset +
238167802Sjkim            ObjDesc->CommonField.AccessByteWidth))
23977424Smsmith    {
240138287Smarks        if (AcpiGbl_EnableInterpreterSlack)
241138287Smarks        {
242138287Smarks            /*
243138287Smarks             * Slack mode only:  We will go ahead and allow access to this
244138287Smarks             * field if it is within the region length rounded up to the next
245193267Sjkim             * access width boundary. ACPI_SIZE cast for 64-bit compile.
246138287Smarks             */
247138287Smarks            if (ACPI_ROUND_UP (RgnDesc->Region.Length,
248167802Sjkim                    ObjDesc->CommonField.AccessByteWidth) >=
249193267Sjkim                ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
250193267Sjkim                    ObjDesc->CommonField.AccessByteWidth +
251193267Sjkim                    FieldDatumByteOffset))
252138287Smarks            {
253138287Smarks                return_ACPI_STATUS (AE_OK);
254138287Smarks            }
255138287Smarks        }
256138287Smarks
25777424Smsmith        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
25877424Smsmith        {
25983174Smsmith            /*
26077424Smsmith             * This is the case where the AccessType (AccWord, etc.) is wider
26177424Smsmith             * than the region itself.  For example, a region of length one
26277424Smsmith             * byte, and a field with Dword access specified.
26377424Smsmith             */
264167802Sjkim            ACPI_ERROR ((AE_INFO,
265204773Sjkim                "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
266123315Snjl                AcpiUtGetNodeName (ObjDesc->CommonField.Node),
267123315Snjl                ObjDesc->CommonField.AccessByteWidth,
268151937Sjkim                AcpiUtGetNodeName (RgnDesc->Region.Node),
269151937Sjkim                RgnDesc->Region.Length));
27077424Smsmith        }
27177424Smsmith
27277424Smsmith        /*
27377424Smsmith         * Offset rounded up to next multiple of field width
27477424Smsmith         * exceeds region length, indicate an error
27577424Smsmith         */
276167802Sjkim        ACPI_ERROR ((AE_INFO,
277204773Sjkim            "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)",
278123315Snjl            AcpiUtGetNodeName (ObjDesc->CommonField.Node),
279123315Snjl            ObjDesc->CommonField.BaseByteOffset,
28091116Smsmith            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
281151937Sjkim            AcpiUtGetNodeName (RgnDesc->Region.Node),
282151937Sjkim            RgnDesc->Region.Length));
28377424Smsmith
28477424Smsmith        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
28577424Smsmith    }
28677424Smsmith
28777424Smsmith    return_ACPI_STATUS (AE_OK);
28877424Smsmith}
28977424Smsmith
29077424Smsmith
29177424Smsmith/*******************************************************************************
29277424Smsmith *
29387031Smsmith * FUNCTION:    AcpiExAccessRegion
29477424Smsmith *
295151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be read
29687031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
29787031Smsmith *                                        parent field
298151937Sjkim *              Value                   - Where to store value (must at least
299202771Sjkim *                                        64 bits)
300107325Siwasaki *              Function                - Read or Write flag plus other region-
301107325Siwasaki *                                        dependent flags
30277424Smsmith *
30377424Smsmith * RETURN:      Status
30477424Smsmith *
30587031Smsmith * DESCRIPTION: Read or Write a single field datum to an Operation Region.
30677424Smsmith *
30777424Smsmith ******************************************************************************/
30877424Smsmith
30977424SmsmithACPI_STATUS
31087031SmsmithAcpiExAccessRegion (
31177424Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
31277424Smsmith    UINT32                  FieldDatumByteOffset,
313202771Sjkim    UINT64                  *Value,
314107325Siwasaki    UINT32                  Function)
31577424Smsmith{
31677424Smsmith    ACPI_STATUS             Status;
31777424Smsmith    ACPI_OPERAND_OBJECT     *RgnDesc;
318193267Sjkim    UINT32                  RegionOffset;
31977424Smsmith
32077424Smsmith
321167802Sjkim    ACPI_FUNCTION_TRACE (ExAccessRegion);
32277424Smsmith
32377424Smsmith
324114237Snjl    /*
325107325Siwasaki     * Ensure that the region operands are fully evaluated and verify
326107325Siwasaki     * the validity of the request
327107325Siwasaki     */
328107325Siwasaki    Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
329107325Siwasaki    if (ACPI_FAILURE (Status))
330107325Siwasaki    {
331107325Siwasaki        return_ACPI_STATUS (Status);
332107325Siwasaki    }
333107325Siwasaki
33487031Smsmith    /*
33587031Smsmith     * The physical address of this field datum is:
33687031Smsmith     *
33787031Smsmith     * 1) The base of the region, plus
33887031Smsmith     * 2) The base offset of the field, plus
33987031Smsmith     * 3) The current offset into the field
34087031Smsmith     */
34187031Smsmith    RgnDesc = ObjDesc->CommonField.RegionObj;
342193267Sjkim    RegionOffset =
343193267Sjkim        ObjDesc->CommonField.BaseByteOffset +
344193267Sjkim        FieldDatumByteOffset;
34587031Smsmith
346107325Siwasaki    if ((Function & ACPI_IO_MASK) == ACPI_READ)
34767754Smsmith    {
34887031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
34967754Smsmith    }
35087031Smsmith    else
35187031Smsmith    {
35287031Smsmith        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
35387031Smsmith    }
35467754Smsmith
35587031Smsmith    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
356167802Sjkim        " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
35787031Smsmith        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
35887031Smsmith        RgnDesc->Region.SpaceId,
35991116Smsmith        ObjDesc->CommonField.AccessByteWidth,
36087031Smsmith        ObjDesc->CommonField.BaseByteOffset,
36187031Smsmith        FieldDatumByteOffset,
362193267Sjkim        ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset))));
36367754Smsmith
36487031Smsmith    /* Invoke the appropriate AddressSpace/OpRegion handler */
36577424Smsmith
366193267Sjkim    Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, RegionOffset,
367151937Sjkim                ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
36887031Smsmith
36987031Smsmith    if (ACPI_FAILURE (Status))
37087031Smsmith    {
37187031Smsmith        if (Status == AE_NOT_IMPLEMENTED)
37287031Smsmith        {
373167802Sjkim            ACPI_ERROR ((AE_INFO,
374204773Sjkim                "Region %s(0x%X) not implemented",
37587031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
37687031Smsmith                RgnDesc->Region.SpaceId));
37787031Smsmith        }
37887031Smsmith        else if (Status == AE_NOT_EXIST)
37987031Smsmith        {
380167802Sjkim            ACPI_ERROR ((AE_INFO,
381204773Sjkim                "Region %s(0x%X) has no handler",
38287031Smsmith                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
38387031Smsmith                RgnDesc->Region.SpaceId));
38487031Smsmith        }
38587031Smsmith    }
38687031Smsmith
38787031Smsmith    return_ACPI_STATUS (Status);
38887031Smsmith}
38987031Smsmith
39087031Smsmith
39187031Smsmith/*******************************************************************************
39287031Smsmith *
39387031Smsmith * FUNCTION:    AcpiExRegisterOverflow
39487031Smsmith *
395151937Sjkim * PARAMETERS:  ObjDesc                 - Register(Field) to be written
39687031Smsmith *              Value                   - Value to be stored
39787031Smsmith *
39887031Smsmith * RETURN:      TRUE if value overflows the field, FALSE otherwise
39987031Smsmith *
40087031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written.
40187031Smsmith *              Used to check if the values written to Index and Bank registers
40287031Smsmith *              are out of range.  Normally, the value is simply truncated
40387031Smsmith *              to fit the field, but this case is most likely a serious
40487031Smsmith *              coding error in the ASL.
40587031Smsmith *
40687031Smsmith ******************************************************************************/
40787031Smsmith
408151937Sjkimstatic BOOLEAN
40987031SmsmithAcpiExRegisterOverflow (
41087031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
411202771Sjkim    UINT64                  Value)
41287031Smsmith{
41387031Smsmith
41491116Smsmith    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
41591116Smsmith    {
41691116Smsmith        /*
41791116Smsmith         * The field is large enough to hold the maximum integer, so we can
41891116Smsmith         * never overflow it.
41991116Smsmith         */
42091116Smsmith        return (FALSE);
42191116Smsmith    }
42291116Smsmith
423202771Sjkim    if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
42487031Smsmith    {
42591116Smsmith        /*
42691116Smsmith         * The Value is larger than the maximum value that can fit into
42791116Smsmith         * the register.
42891116Smsmith         */
42987031Smsmith        return (TRUE);
43087031Smsmith    }
43187031Smsmith
43291116Smsmith    /* The Value will fit into the field with no truncation */
43391116Smsmith
43487031Smsmith    return (FALSE);
43587031Smsmith}
43687031Smsmith
43787031Smsmith
43887031Smsmith/*******************************************************************************
43987031Smsmith *
44087031Smsmith * FUNCTION:    AcpiExFieldDatumIo
44187031Smsmith *
442151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be read
44387031Smsmith *              FieldDatumByteOffset    - Byte offset of this datum within the
44487031Smsmith *                                        parent field
445151937Sjkim *              Value                   - Where to store value (must be 64 bits)
44687031Smsmith *              ReadWrite               - Read or Write flag
44787031Smsmith *
44887031Smsmith * RETURN:      Status
44987031Smsmith *
45087031Smsmith * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
45187031Smsmith *              demultiplexed here to handle the different types of fields
45287031Smsmith *              (BufferField, RegionField, IndexField, BankField)
45387031Smsmith *
45487031Smsmith ******************************************************************************/
45587031Smsmith
456151937Sjkimstatic ACPI_STATUS
45787031SmsmithAcpiExFieldDatumIo (
45887031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
45987031Smsmith    UINT32                  FieldDatumByteOffset,
460202771Sjkim    UINT64                  *Value,
46187031Smsmith    UINT32                  ReadWrite)
46287031Smsmith{
46387031Smsmith    ACPI_STATUS             Status;
464202771Sjkim    UINT64                  LocalValue;
46587031Smsmith
46687031Smsmith
467167802Sjkim    ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
46887031Smsmith
46987031Smsmith
47087031Smsmith    if (ReadWrite == ACPI_READ)
47187031Smsmith    {
47287031Smsmith        if (!Value)
47387031Smsmith        {
47487031Smsmith            LocalValue = 0;
475151937Sjkim
476151937Sjkim            /* To support reads without saving return value */
477151937Sjkim            Value = &LocalValue;
47887031Smsmith        }
47987031Smsmith
48087031Smsmith        /* Clear the entire return buffer first, [Very Important!] */
48187031Smsmith
48287031Smsmith        *Value = 0;
48387031Smsmith    }
48487031Smsmith
48587031Smsmith    /*
48687031Smsmith     * The four types of fields are:
48787031Smsmith     *
488122944Snjl     * BufferField - Read/write from/to a Buffer
489122944Snjl     * RegionField - Read/write from/to a Operation Region.
490151937Sjkim     * BankField   - Write to a Bank Register, then read/write from/to an
491151937Sjkim     *               OperationRegion
492151937Sjkim     * IndexField  - Write to an Index Register, then read/write from/to a
493151937Sjkim     *               Data Register
49487031Smsmith     */
495193267Sjkim    switch (ObjDesc->Common.Type)
49677424Smsmith    {
49777424Smsmith    case ACPI_TYPE_BUFFER_FIELD:
49877424Smsmith        /*
49987031Smsmith         * If the BufferField arguments have not been previously evaluated,
50087031Smsmith         * evaluate them now and save the results.
50177424Smsmith         */
50287031Smsmith        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
50387031Smsmith        {
50487031Smsmith            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
50587031Smsmith            if (ACPI_FAILURE (Status))
50687031Smsmith            {
50787031Smsmith                return_ACPI_STATUS (Status);
50887031Smsmith            }
50987031Smsmith        }
51087031Smsmith
51187031Smsmith        if (ReadWrite == ACPI_READ)
51287031Smsmith        {
51387031Smsmith            /*
51487031Smsmith             * Copy the data from the source buffer.
51587031Smsmith             * Length is the field width in bytes.
51687031Smsmith             */
517151937Sjkim            ACPI_MEMCPY (Value,
518151937Sjkim                (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
519151937Sjkim                    ObjDesc->BufferField.BaseByteOffset +
520151937Sjkim                    FieldDatumByteOffset,
521151937Sjkim                ObjDesc->CommonField.AccessByteWidth);
52287031Smsmith        }
52387031Smsmith        else
52487031Smsmith        {
52587031Smsmith            /*
52687031Smsmith             * Copy the data to the target buffer.
52787031Smsmith             * Length is the field width in bytes.
52887031Smsmith             */
529151937Sjkim            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
530167802Sjkim                ObjDesc->BufferField.BaseByteOffset +
531167802Sjkim                FieldDatumByteOffset,
532167802Sjkim                Value, ObjDesc->CommonField.AccessByteWidth);
53387031Smsmith        }
53487031Smsmith
53577424Smsmith        Status = AE_OK;
53677424Smsmith        break;
53767754Smsmith
53867754Smsmith
539107325Siwasaki    case ACPI_TYPE_LOCAL_BANK_FIELD:
54067754Smsmith
541151937Sjkim        /*
542151937Sjkim         * Ensure that the BankValue is not beyond the capacity of
543151937Sjkim         * the register
544151937Sjkim         */
54587031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
546202771Sjkim                (UINT64) ObjDesc->BankField.Value))
54787031Smsmith        {
54887031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
54987031Smsmith        }
55087031Smsmith
55177424Smsmith        /*
55287031Smsmith         * For BankFields, we must write the BankValue to the BankRegister
55387031Smsmith         * (itself a RegionField) before we can access the data.
55477424Smsmith         */
55587031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
556167802Sjkim                    &ObjDesc->BankField.Value,
557167802Sjkim                    sizeof (ObjDesc->BankField.Value));
55877424Smsmith        if (ACPI_FAILURE (Status))
55977424Smsmith        {
56077424Smsmith            return_ACPI_STATUS (Status);
56177424Smsmith        }
56267754Smsmith
56377424Smsmith        /*
56487031Smsmith         * Now that the Bank has been selected, fall through to the
56587031Smsmith         * RegionField case and write the datum to the Operation Region
56677424Smsmith         */
56777424Smsmith
56899679Siwasaki        /*lint -fallthrough */
56977424Smsmith
57077424Smsmith
571107325Siwasaki    case ACPI_TYPE_LOCAL_REGION_FIELD:
57287031Smsmith        /*
57387031Smsmith         * For simple RegionFields, we just directly access the owning
57487031Smsmith         * Operation Region.
57587031Smsmith         */
57687031Smsmith        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
577167802Sjkim                    ReadWrite);
57887031Smsmith        break;
57987031Smsmith
58087031Smsmith
581107325Siwasaki    case ACPI_TYPE_LOCAL_INDEX_FIELD:
58287031Smsmith
58387031Smsmith
584151937Sjkim        /*
585151937Sjkim         * Ensure that the IndexValue is not beyond the capacity of
586151937Sjkim         * the register
587151937Sjkim         */
58887031Smsmith        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
589202771Sjkim                (UINT64) ObjDesc->IndexField.Value))
59077424Smsmith        {
59187031Smsmith            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
59277424Smsmith        }
59387031Smsmith
59487031Smsmith        /* Write the index value to the IndexRegister (itself a RegionField) */
59587031Smsmith
596122944Snjl        FieldDatumByteOffset += ObjDesc->IndexField.Value;
597122944Snjl
598122944Snjl        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
599167802Sjkim            "Write to Index Register: Value %8.8X\n",
600167802Sjkim            FieldDatumByteOffset));
601122944Snjl
60287031Smsmith        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
603167802Sjkim                    &FieldDatumByteOffset,
604167802Sjkim                    sizeof (FieldDatumByteOffset));
60587031Smsmith        if (ACPI_FAILURE (Status))
60687031Smsmith        {
60787031Smsmith            return_ACPI_STATUS (Status);
60887031Smsmith        }
60987031Smsmith
61087031Smsmith        if (ReadWrite == ACPI_READ)
61187031Smsmith        {
61287031Smsmith            /* Read the datum from the DataRegister */
61387031Smsmith
614193267Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
615193267Sjkim                "Read from Data Register\n"));
616193267Sjkim
61787031Smsmith            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
618202771Sjkim                        Value, sizeof (UINT64));
61987031Smsmith        }
62087031Smsmith        else
62187031Smsmith        {
622122944Snjl            /* Write the datum to the DataRegister */
62387031Smsmith
624193267Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
625193267Sjkim                "Write to Data Register: Value %8.8X%8.8X\n",
626193267Sjkim                ACPI_FORMAT_UINT64 (*Value)));
627193267Sjkim
62887031Smsmith            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
629202771Sjkim                        Value, sizeof (UINT64));
63087031Smsmith        }
63177424Smsmith        break;
63277424Smsmith
63377424Smsmith
63477424Smsmith    default:
63577424Smsmith
636204773Sjkim        ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
637193267Sjkim            ObjDesc->Common.Type));
63877424Smsmith        Status = AE_AML_INTERNAL;
63977424Smsmith        break;
64067754Smsmith    }
64167754Smsmith
64287031Smsmith    if (ACPI_SUCCESS (Status))
64387031Smsmith    {
64487031Smsmith        if (ReadWrite == ACPI_READ)
64587031Smsmith        {
646151937Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
647209746Sjkim                "Value Read %8.8X%8.8X, Width %u\n",
648151937Sjkim                ACPI_FORMAT_UINT64 (*Value),
649151937Sjkim                ObjDesc->CommonField.AccessByteWidth));
65087031Smsmith        }
65187031Smsmith        else
65287031Smsmith        {
653151937Sjkim            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
654209746Sjkim                "Value Written %8.8X%8.8X, Width %u\n",
655151937Sjkim                ACPI_FORMAT_UINT64 (*Value),
656151937Sjkim                ObjDesc->CommonField.AccessByteWidth));
65787031Smsmith        }
65887031Smsmith    }
65977424Smsmith
66087031Smsmith    return_ACPI_STATUS (Status);
66187031Smsmith}
66277424Smsmith
66387031Smsmith
66487031Smsmith/*******************************************************************************
66587031Smsmith *
66687031Smsmith * FUNCTION:    AcpiExWriteWithUpdateRule
66787031Smsmith *
668151937Sjkim * PARAMETERS:  ObjDesc                 - Field to be written
669151937Sjkim *              Mask                    - bitmask within field datum
670151937Sjkim *              FieldValue              - Value to write
671151937Sjkim *              FieldDatumByteOffset    - Offset of datum within field
67287031Smsmith *
67387031Smsmith * RETURN:      Status
67487031Smsmith *
67587031Smsmith * DESCRIPTION: Apply the field update rule to a field write
67687031Smsmith *
67787031Smsmith ******************************************************************************/
67887031Smsmith
67987031SmsmithACPI_STATUS
68087031SmsmithAcpiExWriteWithUpdateRule (
68187031Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
682202771Sjkim    UINT64                  Mask,
683202771Sjkim    UINT64                  FieldValue,
68487031Smsmith    UINT32                  FieldDatumByteOffset)
68587031Smsmith{
68687031Smsmith    ACPI_STATUS             Status = AE_OK;
687202771Sjkim    UINT64                  MergedValue;
688202771Sjkim    UINT64                  CurrentValue;
68987031Smsmith
69087031Smsmith
691167802Sjkim    ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
69287031Smsmith
69387031Smsmith
69487031Smsmith    /* Start with the new bits  */
69587031Smsmith
69687031Smsmith    MergedValue = FieldValue;
69787031Smsmith
69887031Smsmith    /* If the mask is all ones, we don't need to worry about the update rule */
69987031Smsmith
700202771Sjkim    if (Mask != ACPI_UINT64_MAX)
70187031Smsmith    {
70287031Smsmith        /* Decode the update rule */
70387031Smsmith
70487031Smsmith        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
70587031Smsmith        {
70687031Smsmith        case AML_FIELD_UPDATE_PRESERVE:
70787031Smsmith            /*
70887031Smsmith             * Check if update rule needs to be applied (not if mask is all
70987031Smsmith             * ones)  The left shift drops the bits we want to ignore.
71087031Smsmith             */
71191116Smsmith            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
71291116Smsmith                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
71387031Smsmith            {
71487031Smsmith                /*
71587031Smsmith                 * Read the current contents of the byte/word/dword containing
71687031Smsmith                 * the field, and merge with the new field value.
71787031Smsmith                 */
71887031Smsmith                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
719167802Sjkim                            &CurrentValue, ACPI_READ);
720123315Snjl                if (ACPI_FAILURE (Status))
721123315Snjl                {
722123315Snjl                    return_ACPI_STATUS (Status);
723123315Snjl                }
724123315Snjl
72587031Smsmith                MergedValue |= (CurrentValue & ~Mask);
72687031Smsmith            }
72787031Smsmith            break;
72887031Smsmith
72987031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ONES:
73087031Smsmith
73187031Smsmith            /* Set positions outside the field to all ones */
73287031Smsmith
73387031Smsmith            MergedValue |= ~Mask;
73487031Smsmith            break;
73587031Smsmith
73687031Smsmith        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
73787031Smsmith
73887031Smsmith            /* Set positions outside the field to all zeros */
73987031Smsmith
74087031Smsmith            MergedValue &= Mask;
74187031Smsmith            break;
74287031Smsmith
74387031Smsmith        default:
744123315Snjl
745167802Sjkim            ACPI_ERROR ((AE_INFO,
746204773Sjkim                "Unknown UpdateRule value: 0x%X",
74787031Smsmith                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
74887031Smsmith            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
74987031Smsmith        }
75087031Smsmith    }
75187031Smsmith
752123315Snjl    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
753123315Snjl        "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
754123315Snjl        ACPI_FORMAT_UINT64 (Mask),
755123315Snjl        FieldDatumByteOffset,
756123315Snjl        ObjDesc->CommonField.AccessByteWidth,
757123315Snjl        ACPI_FORMAT_UINT64 (FieldValue),
758123315Snjl        ACPI_FORMAT_UINT64 (MergedValue)));
759123315Snjl
76087031Smsmith    /* Write the merged value */
76187031Smsmith
76287031Smsmith    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
763167802Sjkim                &MergedValue, ACPI_WRITE);
76487031Smsmith
76577424Smsmith    return_ACPI_STATUS (Status);
76677424Smsmith}
76777424Smsmith
76877424Smsmith
76977424Smsmith/*******************************************************************************
77077424Smsmith *
77177424Smsmith * FUNCTION:    AcpiExExtractFromField
77267754Smsmith *
773131440Smarks * PARAMETERS:  ObjDesc             - Field to be read
774131440Smarks *              Buffer              - Where to store the field data
775131440Smarks *              BufferLength        - Length of Buffer
77667754Smsmith *
77767754Smsmith * RETURN:      Status
77867754Smsmith *
779131440Smarks * DESCRIPTION: Retrieve the current value of the given field
78067754Smsmith *
78167754Smsmith ******************************************************************************/
78267754Smsmith
78367754SmsmithACPI_STATUS
78477424SmsmithAcpiExExtractFromField (
78567754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
78667754Smsmith    void                    *Buffer,
78777424Smsmith    UINT32                  BufferLength)
78867754Smsmith{
78967754Smsmith    ACPI_STATUS             Status;
790202771Sjkim    UINT64                  RawDatum;
791202771Sjkim    UINT64                  MergedDatum;
792151937Sjkim    UINT32                  FieldOffset = 0;
793151937Sjkim    UINT32                  BufferOffset = 0;
794151937Sjkim    UINT32                  BufferTailBits;
79577424Smsmith    UINT32                  DatumCount;
796151937Sjkim    UINT32                  FieldDatumCount;
797123315Snjl    UINT32                  i;
79867754Smsmith
79967754Smsmith
800167802Sjkim    ACPI_FUNCTION_TRACE (ExExtractFromField);
80167754Smsmith
80277424Smsmith
803151937Sjkim    /* Validate target buffer and clear it */
80477424Smsmith
805167802Sjkim    if (BufferLength <
806167802Sjkim            ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
807151937Sjkim    {
808167802Sjkim        ACPI_ERROR ((AE_INFO,
809204773Sjkim            "Field size %u (bits) is too large for buffer (%u)",
810151937Sjkim            ObjDesc->CommonField.BitLength, BufferLength));
811151937Sjkim
812151937Sjkim        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
813151937Sjkim    }
814151937Sjkim    ACPI_MEMSET (Buffer, 0, BufferLength);
815151937Sjkim
816151937Sjkim    /* Compute the number of datums (access width data items) */
817151937Sjkim
818151937Sjkim    DatumCount = ACPI_ROUND_UP_TO (
819151937Sjkim                        ObjDesc->CommonField.BitLength,
820151937Sjkim                        ObjDesc->CommonField.AccessBitWidth);
821151937Sjkim    FieldDatumCount = ACPI_ROUND_UP_TO (
822151937Sjkim                        ObjDesc->CommonField.BitLength +
823151937Sjkim                        ObjDesc->CommonField.StartFieldBitOffset,
824151937Sjkim                        ObjDesc->CommonField.AccessBitWidth);
825151937Sjkim
826151937Sjkim    /* Priming read from the field */
827151937Sjkim
828151937Sjkim    Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
829131440Smarks    if (ACPI_FAILURE (Status))
830123315Snjl    {
831131440Smarks        return_ACPI_STATUS (Status);
832123315Snjl    }
833151937Sjkim    MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
834123315Snjl
835151937Sjkim    /* Read the rest of the field */
83667754Smsmith
837151937Sjkim    for (i = 1; i < FieldDatumCount; i++)
838151937Sjkim    {
839151937Sjkim        /* Get next input datum from the field */
84067754Smsmith
841151937Sjkim        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
842151937Sjkim        Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
843167802Sjkim                    &RawDatum, ACPI_READ);
844123315Snjl        if (ACPI_FAILURE (Status))
845123315Snjl        {
846123315Snjl            return_ACPI_STATUS (Status);
847123315Snjl        }
84867754Smsmith
849167802Sjkim        /*
850167802Sjkim         * Merge with previous datum if necessary.
851167802Sjkim         *
852167802Sjkim         * Note: Before the shift, check if the shift value will be larger than
853167802Sjkim         * the integer size. If so, there is no need to perform the operation.
854167802Sjkim         * This avoids the differences in behavior between different compilers
855167802Sjkim         * concerning shift values larger than the target data width.
856167802Sjkim         */
857167802Sjkim        if ((ObjDesc->CommonField.AccessBitWidth -
858167802Sjkim            ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE)
859167802Sjkim        {
860167802Sjkim            MergedDatum |= RawDatum <<
861167802Sjkim                (ObjDesc->CommonField.AccessBitWidth -
862167802Sjkim                    ObjDesc->CommonField.StartFieldBitOffset);
863167802Sjkim        }
86467754Smsmith
865151937Sjkim        if (i == DatumCount)
86667754Smsmith        {
867151937Sjkim            break;
86877424Smsmith        }
86967754Smsmith
870151937Sjkim        /* Write merged datum to target buffer */
87171867Smsmith
872151937Sjkim        ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
873151937Sjkim            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
874167802Sjkim                BufferLength - BufferOffset));
87567754Smsmith
876151937Sjkim        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
877151937Sjkim        MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
878151937Sjkim    }
879123315Snjl
880151937Sjkim    /* Mask off any extra bits in the last datum */
881123315Snjl
882151937Sjkim    BufferTailBits = ObjDesc->CommonField.BitLength %
883151937Sjkim                        ObjDesc->CommonField.AccessBitWidth;
884151937Sjkim    if (BufferTailBits)
885151937Sjkim    {
886151937Sjkim        MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
887123315Snjl    }
888123315Snjl
889151937Sjkim    /* Write the last datum to the buffer */
890123315Snjl
891151937Sjkim    ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
892151937Sjkim        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
893167802Sjkim            BufferLength - BufferOffset));
894123315Snjl
89577424Smsmith    return_ACPI_STATUS (AE_OK);
89667754Smsmith}
89767754Smsmith
89867754Smsmith
89967754Smsmith/*******************************************************************************
90067754Smsmith *
90177424Smsmith * FUNCTION:    AcpiExInsertIntoField
90267754Smsmith *
903131440Smarks * PARAMETERS:  ObjDesc             - Field to be written
904131440Smarks *              Buffer              - Data to be written
905131440Smarks *              BufferLength        - Length of Buffer
90667754Smsmith *
90767754Smsmith * RETURN:      Status
90867754Smsmith *
909131440Smarks * DESCRIPTION: Store the Buffer contents into the given field
91067754Smsmith *
91177424Smsmith ******************************************************************************/
91267754Smsmith
91367754SmsmithACPI_STATUS
91477424SmsmithAcpiExInsertIntoField (
91567754Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
91667754Smsmith    void                    *Buffer,
91777424Smsmith    UINT32                  BufferLength)
91867754Smsmith{
91967754Smsmith    ACPI_STATUS             Status;
920202771Sjkim    UINT64                  Mask;
921202771Sjkim    UINT64                  WidthMask;
922202771Sjkim    UINT64                  MergedDatum;
923202771Sjkim    UINT64                  RawDatum = 0;
924151937Sjkim    UINT32                  FieldOffset = 0;
925151937Sjkim    UINT32                  BufferOffset = 0;
926151937Sjkim    UINT32                  BufferTailBits;
92777424Smsmith    UINT32                  DatumCount;
928151937Sjkim    UINT32                  FieldDatumCount;
929151937Sjkim    UINT32                  i;
930193267Sjkim    UINT32                  RequiredLength;
931193267Sjkim    void                    *NewBuffer;
93267754Smsmith
93367754Smsmith
934167802Sjkim    ACPI_FUNCTION_TRACE (ExInsertIntoField);
93567754Smsmith
93667754Smsmith
937151937Sjkim    /* Validate input buffer */
938131440Smarks
939193267Sjkim    NewBuffer = NULL;
940193267Sjkim    RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
941193267Sjkim                        ObjDesc->CommonField.BitLength);
942193267Sjkim    /*
943193267Sjkim     * We must have a buffer that is at least as long as the field
944193267Sjkim     * we are writing to.  This is because individual fields are
945193267Sjkim     * indivisible and partial writes are not supported -- as per
946193267Sjkim     * the ACPI specification.
947193267Sjkim     */
948193267Sjkim    if (BufferLength < RequiredLength)
94977424Smsmith    {
950193267Sjkim        /* We need to create a new buffer */
951151937Sjkim
952193267Sjkim        NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
953193267Sjkim        if (!NewBuffer)
954193267Sjkim        {
955193267Sjkim            return_ACPI_STATUS (AE_NO_MEMORY);
956193267Sjkim        }
957193267Sjkim
958193267Sjkim        /*
959193267Sjkim         * Copy the original data to the new buffer, starting
960193267Sjkim         * at Byte zero.  All unused (upper) bytes of the
961193267Sjkim         * buffer will be 0.
962193267Sjkim         */
963193267Sjkim        ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
964193267Sjkim        Buffer = NewBuffer;
965193267Sjkim        BufferLength = RequiredLength;
96677424Smsmith    }
96767754Smsmith
968167802Sjkim    /*
969167802Sjkim     * Create the bitmasks used for bit insertion.
970167802Sjkim     * Note: This if/else is used to bypass compiler differences with the
971167802Sjkim     * shift operator
972167802Sjkim     */
973167802Sjkim    if (ObjDesc->CommonField.AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
974167802Sjkim    {
975202771Sjkim        WidthMask = ACPI_UINT64_MAX;
976167802Sjkim    }
977167802Sjkim    else
978167802Sjkim    {
979167802Sjkim        WidthMask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.AccessBitWidth);
980167802Sjkim    }
981167802Sjkim
982167802Sjkim    Mask = WidthMask &
983167802Sjkim            ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
984167802Sjkim
985151937Sjkim    /* Compute the number of datums (access width data items) */
98667754Smsmith
987151937Sjkim    DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
988151937Sjkim                    ObjDesc->CommonField.AccessBitWidth);
989167802Sjkim
990151937Sjkim    FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
991151937Sjkim                        ObjDesc->CommonField.StartFieldBitOffset,
992151937Sjkim                        ObjDesc->CommonField.AccessBitWidth);
99367754Smsmith
994151937Sjkim    /* Get initial Datum from the input buffer */
99567754Smsmith
996151937Sjkim    ACPI_MEMCPY (&RawDatum, Buffer,
997151937Sjkim        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
998167802Sjkim            BufferLength - BufferOffset));
99967754Smsmith
1000151937Sjkim    MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
100167754Smsmith
1002151937Sjkim    /* Write the entire field */
100367754Smsmith
1004151937Sjkim    for (i = 1; i < FieldDatumCount; i++)
100567754Smsmith    {
1006151937Sjkim        /* Write merged datum to the target field */
100767754Smsmith
1008151937Sjkim        MergedDatum &= Mask;
1009151937Sjkim        Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
1010151937Sjkim                    MergedDatum, FieldOffset);
1011151937Sjkim        if (ACPI_FAILURE (Status))
1012151937Sjkim        {
1013193267Sjkim            goto Exit;
1014151937Sjkim        }
1015123315Snjl
1016151937Sjkim        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
101767754Smsmith
1018167802Sjkim        /*
1019167802Sjkim         * Start new output datum by merging with previous input datum
1020167802Sjkim         * if necessary.
1021167802Sjkim         *
1022167802Sjkim         * Note: Before the shift, check if the shift value will be larger than
1023167802Sjkim         * the integer size. If so, there is no need to perform the operation.
1024167802Sjkim         * This avoids the differences in behavior between different compilers
1025167802Sjkim         * concerning shift values larger than the target data width.
1026167802Sjkim         */
1027167802Sjkim        if ((ObjDesc->CommonField.AccessBitWidth -
1028167802Sjkim            ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE)
1029167802Sjkim        {
1030167802Sjkim            MergedDatum = RawDatum >>
1031167802Sjkim                (ObjDesc->CommonField.AccessBitWidth -
1032167802Sjkim                    ObjDesc->CommonField.StartFieldBitOffset);
1033167802Sjkim        }
1034167802Sjkim        else
1035167802Sjkim        {
1036167802Sjkim            MergedDatum = 0;
1037167802Sjkim        }
1038167802Sjkim
1039167802Sjkim        Mask = WidthMask;
1040167802Sjkim
1041151937Sjkim        if (i == DatumCount)
104267754Smsmith        {
1043151937Sjkim            break;
104467754Smsmith        }
104577424Smsmith
1046151937Sjkim        /* Get the next input datum from the buffer */
104767754Smsmith
1048151937Sjkim        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1049151937Sjkim        ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
1050151937Sjkim            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1051151937Sjkim                     BufferLength - BufferOffset));
1052151937Sjkim        MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1053151937Sjkim    }
105467754Smsmith
1055151937Sjkim    /* Mask off any extra bits in the last datum */
105667754Smsmith
1057151937Sjkim    BufferTailBits = (ObjDesc->CommonField.BitLength +
1058151937Sjkim            ObjDesc->CommonField.StartFieldBitOffset) %
1059151937Sjkim                ObjDesc->CommonField.AccessBitWidth;
1060151937Sjkim    if (BufferTailBits)
1061151937Sjkim    {
1062151937Sjkim        Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1063151937Sjkim    }
1064123315Snjl
1065151937Sjkim    /* Write the last datum to the field */
106667754Smsmith
1067151937Sjkim    MergedDatum &= Mask;
1068151937Sjkim    Status = AcpiExWriteWithUpdateRule (ObjDesc,
1069151937Sjkim                Mask, MergedDatum, FieldOffset);
107067754Smsmith
1071193267SjkimExit:
1072193267Sjkim    /* Free temporary buffer if we used one */
1073193267Sjkim
1074193267Sjkim    if (NewBuffer)
1075193267Sjkim    {
1076193267Sjkim        ACPI_FREE (NewBuffer);
1077193267Sjkim    }
107867754Smsmith    return_ACPI_STATUS (Status);
107967754Smsmith}
108067754Smsmith
108167754Smsmith
1082