exfldio.c revision 107325
1169689Skan/******************************************************************************
2169689Skan *
3169689Skan * Module Name: exfldio - Aml Field I/O
4169689Skan *              $Revision: 90 $
5169689Skan *
6169689Skan *****************************************************************************/
7169689Skan
8169689Skan/******************************************************************************
9169689Skan *
10169689Skan * 1. Copyright Notice
11169689Skan *
12169689Skan * Some or all of this work - Copyright (c) 1999 - 2002, Intel Corp.
13169689Skan * All rights reserved.
14169689Skan *
15169689Skan * 2. License
16169689Skan *
17169689Skan * 2.1. This is your license from Intel Corp. under its intellectual property
18169689Skan * rights.  You may have additional license terms from the party that provided
19169689Skan * you this software, covering your right to use that party's intellectual
20169689Skan * property rights.
21169689Skan *
22169689Skan * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
23169689Skan * copy of the source code appearing in this file ("Covered Code") an
24169689Skan * irrevocable, perpetual, worldwide license under Intel's copyrights in the
25169689Skan * base code distributed originally by Intel ("Original Intel Code") to copy,
26169689Skan * make derivatives, distribute, use and display any portion of the Covered
27 * Code in any form, with the right to sublicense such rights; and
28 *
29 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
30 * license (with the right to sublicense), under only those claims of Intel
31 * patents that are infringed by the Original Intel Code, to make, use, sell,
32 * offer to sell, and import the Covered Code and derivative works thereof
33 * solely to the minimum extent necessary to exercise the above copyright
34 * license, and in no event shall the patent license extend to any additions
35 * to or modifications of the Original Intel Code.  No other license or right
36 * is granted directly or by implication, estoppel or otherwise;
37 *
38 * The above copyright and patent license is granted only if the following
39 * conditions are met:
40 *
41 * 3. Conditions
42 *
43 * 3.1. Redistribution of Source with Rights to Further Distribute Source.
44 * Redistribution of source code of any substantial portion of the Covered
45 * Code or modification with rights to further distribute source must include
46 * the above Copyright Notice, the above License, this list of Conditions,
47 * and the following Disclaimer and Export Compliance provision.  In addition,
48 * Licensee must cause all Covered Code to which Licensee contributes to
49 * contain a file documenting the changes Licensee made to create that Covered
50 * Code and the date of any change.  Licensee must include in that file the
51 * documentation of any changes made by any predecessor Licensee.  Licensee
52 * must include a prominent statement that the modification is derived,
53 * directly or indirectly, from Original Intel Code.
54 *
55 * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
56 * Redistribution of source code of any substantial portion of the Covered
57 * Code or modification without rights to further distribute source must
58 * include the following Disclaimer and Export Compliance provision in the
59 * documentation and/or other materials provided with distribution.  In
60 * addition, Licensee may not authorize further sublicense of source of any
61 * portion of the Covered Code, and must include terms to the effect that the
62 * license from Licensee to its licensee is limited to the intellectual
63 * property embodied in the software Licensee provides to its licensee, and
64 * not to intellectual property embodied in modifications its licensee may
65 * make.
66 *
67 * 3.3. Redistribution of Executable. Redistribution in executable form of any
68 * substantial portion of the Covered Code or modification must reproduce the
69 * above Copyright Notice, and the following Disclaimer and Export Compliance
70 * provision in the documentation and/or other materials provided with the
71 * distribution.
72 *
73 * 3.4. Intel retains all right, title, and interest in and to the Original
74 * Intel Code.
75 *
76 * 3.5. Neither the name Intel nor any other trademark owned or controlled by
77 * Intel shall be used in advertising or otherwise to promote the sale, use or
78 * other dealings in products derived from or relating to the Covered Code
79 * without prior written authorization from Intel.
80 *
81 * 4. Disclaimer and Export Compliance
82 *
83 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
84 * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
85 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
86 * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
87 * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
88 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
89 * PARTICULAR PURPOSE.
90 *
91 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
92 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
93 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
94 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
95 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
96 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
97 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
98 * LIMITED REMEDY.
99 *
100 * 4.3. Licensee shall not export, either directly or indirectly, any of this
101 * software or system incorporating such software without first obtaining any
102 * required license or other approval from the U. S. Department of Commerce or
103 * any other agency or department of the United States Government.  In the
104 * event Licensee exports any such software from the United States or
105 * re-exports any such software from a foreign destination, Licensee shall
106 * ensure that the distribution and export/re-export of the software is in
107 * compliance with all laws, regulations, orders, or other restrictions of the
108 * U.S. Export Administration Regulations. Licensee agrees that neither it nor
109 * any of its subsidiaries will export/re-export any technical data, process,
110 * software, or service, directly or indirectly, to any country for which the
111 * United States government or any agency thereof requires an export license,
112 * other governmental approval, or letter of assurance, without first obtaining
113 * such license, approval or letter.
114 *
115 *****************************************************************************/
116
117
118#define __EXFLDIO_C__
119
120#include "acpi.h"
121#include "acinterp.h"
122#include "amlcode.h"
123#include "acevents.h"
124#include "acdispat.h"
125
126
127#define _COMPONENT          ACPI_EXECUTER
128        ACPI_MODULE_NAME    ("exfldio")
129
130
131/*******************************************************************************
132 *
133 * FUNCTION:    AcpiExSetupRegion
134 *
135 * PARAMETERS:  *ObjDesc                - Field to be read or written
136 *              FieldDatumByteOffset    - Byte offset of this datum within the
137 *                                        parent field
138 *
139 * RETURN:      Status
140 *
141 * DESCRIPTION: Common processing for AcpiExExtractFromField and
142 *              AcpiExInsertIntoField.  Initialize the
143 *
144 ******************************************************************************/
145
146ACPI_STATUS
147AcpiExSetupRegion (
148    ACPI_OPERAND_OBJECT     *ObjDesc,
149    UINT32                  FieldDatumByteOffset)
150{
151    ACPI_STATUS             Status = AE_OK;
152    ACPI_OPERAND_OBJECT     *RgnDesc;
153
154
155    ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
156
157
158    RgnDesc = ObjDesc->CommonField.RegionObj;
159
160    /* We must have a valid region */
161
162    if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
163    {
164        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
165            ACPI_GET_OBJECT_TYPE (RgnDesc),
166            AcpiUtGetObjectTypeName (RgnDesc)));
167
168        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
169    }
170
171    /*
172     * If the Region Address and Length have not been previously evaluated,
173     * evaluate them now and save the results.
174     */
175    if (!(RgnDesc->Region.Flags & AOPOBJ_DATA_VALID))
176    {
177        Status = AcpiDsGetRegionArguments (RgnDesc);
178        if (ACPI_FAILURE (Status))
179        {
180            return_ACPI_STATUS (Status);
181        }
182    }
183
184    if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
185    {
186        /* SMBus has a non-linear address space */
187
188        return_ACPI_STATUS (AE_OK);
189    }
190
191    /*
192     * Validate the request.  The entire request from the byte offset for a
193     * length of one field datum (access width) must fit within the region.
194     * (Region length is specified in bytes)
195     */
196    if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset
197                                    + FieldDatumByteOffset
198                                    + ObjDesc->CommonField.AccessByteWidth))
199    {
200        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
201        {
202            /*
203             * This is the case where the AccessType (AccWord, etc.) is wider
204             * than the region itself.  For example, a region of length one
205             * byte, and a field with Dword access specified.
206             */
207            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
208                "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
209                ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.AccessByteWidth,
210                RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length));
211        }
212
213        /*
214         * Offset rounded up to next multiple of field width
215         * exceeds region length, indicate an error
216         */
217        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
218            "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
219            ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.BaseByteOffset,
220            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
221            RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length));
222
223        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
224    }
225
226    return_ACPI_STATUS (AE_OK);
227}
228
229
230/*******************************************************************************
231 *
232 * FUNCTION:    AcpiExAccessRegion
233 *
234 * PARAMETERS:  *ObjDesc                - Field to be read
235 *              FieldDatumByteOffset    - Byte offset of this datum within the
236 *                                        parent field
237 *              *Value                  - Where to store value (must at least
238 *                                        the size of ACPI_INTEGER)
239 *              Function                - Read or Write flag plus other region-
240 *                                        dependent flags
241 *
242 * RETURN:      Status
243 *
244 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
245 *
246 ******************************************************************************/
247
248ACPI_STATUS
249AcpiExAccessRegion (
250    ACPI_OPERAND_OBJECT     *ObjDesc,
251    UINT32                  FieldDatumByteOffset,
252    ACPI_INTEGER            *Value,
253    UINT32                  Function)
254{
255    ACPI_STATUS             Status;
256    ACPI_OPERAND_OBJECT     *RgnDesc;
257    ACPI_PHYSICAL_ADDRESS   Address;
258
259
260    ACPI_FUNCTION_TRACE ("ExAccessRegion");
261
262
263    /*
264     * Ensure that the region operands are fully evaluated and verify
265     * the validity of the request
266     */
267    Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
268    if (ACPI_FAILURE (Status))
269    {
270        return_ACPI_STATUS (Status);
271    }
272
273    /*
274     * The physical address of this field datum is:
275     *
276     * 1) The base of the region, plus
277     * 2) The base offset of the field, plus
278     * 3) The current offset into the field
279     */
280    RgnDesc = ObjDesc->CommonField.RegionObj;
281    Address = RgnDesc->Region.Address
282                + ObjDesc->CommonField.BaseByteOffset
283                + FieldDatumByteOffset;
284
285    if ((Function & ACPI_IO_MASK) == ACPI_READ)
286    {
287        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
288    }
289    else
290    {
291        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
292    }
293
294    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
295        " Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n",
296        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
297        RgnDesc->Region.SpaceId,
298        ObjDesc->CommonField.AccessByteWidth,
299        ObjDesc->CommonField.BaseByteOffset,
300        FieldDatumByteOffset,
301        ACPI_HIDWORD (Address), ACPI_LODWORD (Address)));
302
303    /* Invoke the appropriate AddressSpace/OpRegion handler */
304
305    Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function,
306                    Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
307
308    if (ACPI_FAILURE (Status))
309    {
310        if (Status == AE_NOT_IMPLEMENTED)
311        {
312            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
313                "Region %s(%X) not implemented\n",
314                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
315                RgnDesc->Region.SpaceId));
316        }
317        else if (Status == AE_NOT_EXIST)
318        {
319            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
320                "Region %s(%X) has no handler\n",
321                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
322                RgnDesc->Region.SpaceId));
323        }
324    }
325
326    return_ACPI_STATUS (Status);
327}
328
329
330/*******************************************************************************
331 *
332 * FUNCTION:    AcpiExRegisterOverflow
333 *
334 * PARAMETERS:  *ObjDesc                - Register(Field) to be written
335 *              Value                   - Value to be stored
336 *
337 * RETURN:      TRUE if value overflows the field, FALSE otherwise
338 *
339 * DESCRIPTION: Check if a value is out of range of the field being written.
340 *              Used to check if the values written to Index and Bank registers
341 *              are out of range.  Normally, the value is simply truncated
342 *              to fit the field, but this case is most likely a serious
343 *              coding error in the ASL.
344 *
345 ******************************************************************************/
346
347BOOLEAN
348AcpiExRegisterOverflow (
349    ACPI_OPERAND_OBJECT     *ObjDesc,
350    ACPI_INTEGER            Value)
351{
352
353    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
354    {
355        /*
356         * The field is large enough to hold the maximum integer, so we can
357         * never overflow it.
358         */
359        return (FALSE);
360    }
361
362    if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
363    {
364        /*
365         * The Value is larger than the maximum value that can fit into
366         * the register.
367         */
368        return (TRUE);
369    }
370
371    /* The Value will fit into the field with no truncation */
372
373    return (FALSE);
374}
375
376
377/*******************************************************************************
378 *
379 * FUNCTION:    AcpiExFieldDatumIo
380 *
381 * PARAMETERS:  *ObjDesc                - Field to be read
382 *              FieldDatumByteOffset    - Byte offset of this datum within the
383 *                                        parent field
384 *              *Value                  - Where to store value (must be 64 bits)
385 *              ReadWrite               - Read or Write flag
386 *
387 * RETURN:      Status
388 *
389 * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
390 *              demultiplexed here to handle the different types of fields
391 *              (BufferField, RegionField, IndexField, BankField)
392 *
393 ******************************************************************************/
394
395ACPI_STATUS
396AcpiExFieldDatumIo (
397    ACPI_OPERAND_OBJECT     *ObjDesc,
398    UINT32                  FieldDatumByteOffset,
399    ACPI_INTEGER            *Value,
400    UINT32                  ReadWrite)
401{
402    ACPI_STATUS             Status;
403    ACPI_INTEGER            LocalValue;
404
405
406    ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
407
408
409    if (ReadWrite == ACPI_READ)
410    {
411        if (!Value)
412        {
413            LocalValue = 0;
414            Value = &LocalValue;  /* To support reads without saving return value */
415        }
416
417        /* Clear the entire return buffer first, [Very Important!] */
418
419        *Value = 0;
420    }
421
422    /*
423     * The four types of fields are:
424     *
425     * BufferFields - Read/write from/to a Buffer
426     * RegionFields - Read/write from/to a Operation Region.
427     * BankFields   - Write to a Bank Register, then read/write from/to an OpRegion
428     * IndexFields  - Write to an Index Register, then read/write from/to a Data Register
429     */
430    switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
431    {
432    case ACPI_TYPE_BUFFER_FIELD:
433        /*
434         * If the BufferField arguments have not been previously evaluated,
435         * evaluate them now and save the results.
436         */
437        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
438        {
439            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
440            if (ACPI_FAILURE (Status))
441            {
442                return_ACPI_STATUS (Status);
443            }
444        }
445
446        if (ReadWrite == ACPI_READ)
447        {
448            /*
449             * Copy the data from the source buffer.
450             * Length is the field width in bytes.
451             */
452            ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
453                            + ObjDesc->BufferField.BaseByteOffset
454                            + FieldDatumByteOffset,
455                            ObjDesc->CommonField.AccessByteWidth);
456        }
457        else
458        {
459            /*
460             * Copy the data to the target buffer.
461             * Length is the field width in bytes.
462             */
463            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
464                    + ObjDesc->BufferField.BaseByteOffset
465                    + FieldDatumByteOffset,
466                    Value, ObjDesc->CommonField.AccessByteWidth);
467        }
468
469        Status = AE_OK;
470        break;
471
472
473    case ACPI_TYPE_LOCAL_BANK_FIELD:
474
475        /* Ensure that the BankValue is not beyond the capacity of the register */
476
477        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
478                                    (ACPI_INTEGER) ObjDesc->BankField.Value))
479        {
480            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
481        }
482
483        /*
484         * For BankFields, we must write the BankValue to the BankRegister
485         * (itself a RegionField) before we can access the data.
486         */
487        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
488                                &ObjDesc->BankField.Value,
489                                sizeof (ObjDesc->BankField.Value));
490        if (ACPI_FAILURE (Status))
491        {
492            return_ACPI_STATUS (Status);
493        }
494
495        /*
496         * Now that the Bank has been selected, fall through to the
497         * RegionField case and write the datum to the Operation Region
498         */
499
500        /*lint -fallthrough */
501
502
503    case ACPI_TYPE_LOCAL_REGION_FIELD:
504        /*
505         * For simple RegionFields, we just directly access the owning
506         * Operation Region.
507         */
508        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
509                        ReadWrite);
510        break;
511
512
513    case ACPI_TYPE_LOCAL_INDEX_FIELD:
514
515
516        /* Ensure that the IndexValue is not beyond the capacity of the register */
517
518        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
519                                    (ACPI_INTEGER) ObjDesc->IndexField.Value))
520        {
521            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
522        }
523
524        /* Write the index value to the IndexRegister (itself a RegionField) */
525
526        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
527                                &ObjDesc->IndexField.Value,
528                                sizeof (ObjDesc->IndexField.Value));
529        if (ACPI_FAILURE (Status))
530        {
531            return_ACPI_STATUS (Status);
532        }
533
534        if (ReadWrite == ACPI_READ)
535        {
536            /* Read the datum from the DataRegister */
537
538            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
539                            Value, ObjDesc->CommonField.AccessByteWidth);
540        }
541        else
542        {
543            /* Write the datum to the Data register */
544
545            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
546                            Value, ObjDesc->CommonField.AccessByteWidth);
547        }
548        break;
549
550
551    default:
552
553        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",
554            ObjDesc, AcpiUtGetObjectTypeName (ObjDesc)));
555        Status = AE_AML_INTERNAL;
556        break;
557    }
558
559    if (ACPI_SUCCESS (Status))
560    {
561        if (ReadWrite == ACPI_READ)
562        {
563            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",
564                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
565        }
566        else
567        {
568            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",
569                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
570        }
571    }
572
573    return_ACPI_STATUS (Status);
574}
575
576
577/*******************************************************************************
578 *
579 * FUNCTION:    AcpiExWriteWithUpdateRule
580 *
581 * PARAMETERS:  *ObjDesc            - Field to be set
582 *              Value               - Value to store
583 *
584 * RETURN:      Status
585 *
586 * DESCRIPTION: Apply the field update rule to a field write
587 *
588 ******************************************************************************/
589
590ACPI_STATUS
591AcpiExWriteWithUpdateRule (
592    ACPI_OPERAND_OBJECT     *ObjDesc,
593    ACPI_INTEGER            Mask,
594    ACPI_INTEGER            FieldValue,
595    UINT32                  FieldDatumByteOffset)
596{
597    ACPI_STATUS             Status = AE_OK;
598    ACPI_INTEGER            MergedValue;
599    ACPI_INTEGER            CurrentValue;
600
601
602    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
603
604
605    /* Start with the new bits  */
606
607    MergedValue = FieldValue;
608
609    /* If the mask is all ones, we don't need to worry about the update rule */
610
611    if (Mask != ACPI_INTEGER_MAX)
612    {
613        /* Decode the update rule */
614
615        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
616        {
617        case AML_FIELD_UPDATE_PRESERVE:
618            /*
619             * Check if update rule needs to be applied (not if mask is all
620             * ones)  The left shift drops the bits we want to ignore.
621             */
622            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
623                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
624            {
625                /*
626                 * Read the current contents of the byte/word/dword containing
627                 * the field, and merge with the new field value.
628                 */
629                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
630                                &CurrentValue, ACPI_READ);
631                MergedValue |= (CurrentValue & ~Mask);
632            }
633            break;
634
635        case AML_FIELD_UPDATE_WRITE_AS_ONES:
636
637            /* Set positions outside the field to all ones */
638
639            MergedValue |= ~Mask;
640            break;
641
642        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
643
644            /* Set positions outside the field to all zeros */
645
646            MergedValue &= Mask;
647            break;
648
649        default:
650            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
651                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
652                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
653            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
654        }
655    }
656
657    /* Write the merged value */
658
659    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
660                    &MergedValue, ACPI_WRITE);
661
662    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
663        "Mask %8.8X%8.8X DatumOffset %X Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
664        ACPI_HIDWORD (Mask), ACPI_LODWORD (Mask),
665        FieldDatumByteOffset,
666        ACPI_HIDWORD (FieldValue), ACPI_LODWORD (FieldValue),
667        ACPI_HIDWORD (MergedValue),ACPI_LODWORD (MergedValue)));
668
669    return_ACPI_STATUS (Status);
670}
671
672
673/*******************************************************************************
674 *
675 * FUNCTION:    AcpiExGetBufferDatum
676 *
677 * PARAMETERS:  Datum               - Where the Datum is returned
678 *              Buffer              - Raw field buffer
679 *              ByteGranularity     - 1/2/4/8 Granularity of the field
680 *                                    (aka Datum Size)
681 *              Offset              - Datum offset into the buffer
682 *
683 * RETURN:      none
684 *
685 * DESCRIPTION: Get a datum from the buffer according to the buffer field
686 *              byte granularity
687 *
688 ******************************************************************************/
689
690void
691AcpiExGetBufferDatum(
692    ACPI_INTEGER            *Datum,
693    void                    *Buffer,
694    UINT32                  ByteGranularity,
695    UINT32                  Offset)
696{
697
698    ACPI_FUNCTION_ENTRY ();
699
700
701    switch (ByteGranularity)
702    {
703    case ACPI_FIELD_BYTE_GRANULARITY:
704
705        *Datum = ((UINT8 *) Buffer) [Offset];
706        break;
707
708    case ACPI_FIELD_WORD_GRANULARITY:
709
710        ACPI_MOVE_UNALIGNED16_TO_32 (Datum, &(((UINT16 *) Buffer) [Offset]));
711        break;
712
713    case ACPI_FIELD_DWORD_GRANULARITY:
714
715        ACPI_MOVE_UNALIGNED32_TO_32 (Datum, &(((UINT32 *) Buffer) [Offset]));
716        break;
717
718    case ACPI_FIELD_QWORD_GRANULARITY:
719
720        ACPI_MOVE_UNALIGNED64_TO_64 (Datum, &(((UINT64 *) Buffer) [Offset]));
721        break;
722
723    default:
724        /* Should not get here */
725        break;
726    }
727}
728
729
730/*******************************************************************************
731 *
732 * FUNCTION:    AcpiExSetBufferDatum
733 *
734 * PARAMETERS:  MergedDatum         - Value to store
735 *              Buffer              - Receiving buffer
736 *              ByteGranularity     - 1/2/4/8 Granularity of the field
737 *                                    (aka Datum Size)
738 *              Offset              - Datum offset into the buffer
739 *
740 * RETURN:      none
741 *
742 * DESCRIPTION: Store the merged datum to the buffer according to the
743 *              byte granularity
744 *
745 ******************************************************************************/
746
747void
748AcpiExSetBufferDatum (
749    ACPI_INTEGER            MergedDatum,
750    void                    *Buffer,
751    UINT32                  ByteGranularity,
752    UINT32                  Offset)
753{
754
755    ACPI_FUNCTION_ENTRY ();
756
757
758    switch (ByteGranularity)
759    {
760    case ACPI_FIELD_BYTE_GRANULARITY:
761
762        ((UINT8 *) Buffer) [Offset] = (UINT8) MergedDatum;
763        break;
764
765    case ACPI_FIELD_WORD_GRANULARITY:
766
767        ACPI_MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[Offset]), &MergedDatum);
768        break;
769
770    case ACPI_FIELD_DWORD_GRANULARITY:
771
772        ACPI_MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[Offset]), &MergedDatum);
773        break;
774
775    case ACPI_FIELD_QWORD_GRANULARITY:
776
777        ACPI_MOVE_UNALIGNED64_TO_64 (&(((UINT64 *) Buffer)[Offset]), &MergedDatum);
778        break;
779
780    default:
781        /* Should not get here */
782        break;
783    }
784}
785
786
787/*******************************************************************************
788 *
789 * FUNCTION:    AcpiExExtractFromField
790 *
791 * PARAMETERS:  *ObjDesc            - Field to be read
792 *              *Value              - Where to store value
793 *
794 * RETURN:      Status
795 *
796 * DESCRIPTION: Retrieve the value of the given field
797 *
798 ******************************************************************************/
799
800ACPI_STATUS
801AcpiExExtractFromField (
802    ACPI_OPERAND_OBJECT     *ObjDesc,
803    void                    *Buffer,
804    UINT32                  BufferLength)
805{
806    ACPI_STATUS             Status;
807    UINT32                  FieldDatumByteOffset;
808    UINT32                  DatumOffset;
809    ACPI_INTEGER            PreviousRawDatum;
810    ACPI_INTEGER            ThisRawDatum = 0;
811    ACPI_INTEGER            MergedDatum = 0;
812    UINT32                  ByteFieldLength;
813    UINT32                  DatumCount;
814
815
816    ACPI_FUNCTION_TRACE ("ExExtractFromField");
817
818
819    /*
820     * The field must fit within the caller's buffer
821     */
822    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
823    if (ByteFieldLength > BufferLength)
824    {
825        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
826            "Field size %X (bytes) too large for buffer (%X)\n",
827            ByteFieldLength, BufferLength));
828
829        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
830    }
831
832    /* Convert field byte count to datum count, round up if necessary */
833
834    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
835                              ObjDesc->CommonField.AccessByteWidth);
836
837    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
838        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
839        ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth));
840
841    /*
842     * Clear the caller's buffer (the whole buffer length as given)
843     * This is very important, especially in the cases where a byte is read,
844     * but the buffer is really a UINT32 (4 bytes).
845     */
846    ACPI_MEMSET (Buffer, 0, BufferLength);
847
848    /* Read the first raw datum to prime the loop */
849
850    FieldDatumByteOffset = 0;
851    DatumOffset= 0;
852
853    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
854                    &PreviousRawDatum, ACPI_READ);
855    if (ACPI_FAILURE (Status))
856    {
857        return_ACPI_STATUS (Status);
858    }
859
860
861    /* We might actually be done if the request fits in one datum */
862
863    if ((DatumCount == 1) &&
864        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
865    {
866        /* 1) Shift the valid data bits down to start at bit 0 */
867
868        MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
869
870        /* 2) Mask off any upper unused bits (bits not part of the field) */
871
872        if (ObjDesc->CommonField.EndBufferValidBits)
873        {
874            MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
875        }
876
877        /* Store the datum to the caller buffer */
878
879        AcpiExSetBufferDatum (MergedDatum, Buffer, ObjDesc->CommonField.AccessByteWidth,
880                DatumOffset);
881
882        return_ACPI_STATUS (AE_OK);
883    }
884
885
886    /* We need to get more raw data to complete one or more field data */
887
888    while (DatumOffset < DatumCount)
889    {
890        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
891
892        /*
893         * If the field is aligned on a byte boundary, we don't want
894         * to perform a final read, since this would potentially read
895         * past the end of the region.
896         *
897         * We could just split the aligned and non-aligned cases since the
898         * aligned case is so very simple, but this would require more code.
899         */
900        if ((ObjDesc->CommonField.StartFieldBitOffset != 0)  ||
901            ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
902            (DatumOffset < (DatumCount -1))))
903        {
904            /*
905             * Get the next raw datum, it contains some or all bits
906             * of the current field datum
907             */
908            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
909                            &ThisRawDatum, ACPI_READ);
910            if (ACPI_FAILURE (Status))
911            {
912                return_ACPI_STATUS (Status);
913            }
914        }
915
916        /*
917         * Create the (possibly) merged datum to be stored to the caller buffer
918         */
919        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
920        {
921            /* Field is not skewed and we can just copy the datum */
922
923            MergedDatum = PreviousRawDatum;
924        }
925        else
926        {
927            /*
928             * Put together the appropriate bits of the two raw data to make a
929             * single complete field datum
930             *
931             * 1) Normalize the first datum down to bit 0
932             */
933            MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
934
935            /* 2) Insert the second datum "above" the first datum */
936
937            MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
938
939            if ((DatumOffset >= (DatumCount -1)))
940            {
941                /*
942                 * This is the last iteration of the loop.  We need to clear
943                 * any unused bits (bits that are not part of this field) that
944                 * came from the last raw datum before we store the final
945                 * merged datum into the caller buffer.
946                 */
947                if (ObjDesc->CommonField.EndBufferValidBits)
948                {
949                    MergedDatum &=
950                        ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
951                }
952            }
953        }
954
955        /*
956         * Store the merged field datum in the caller's buffer, according to
957         * the granularity of the field (size of each datum).
958         */
959        AcpiExSetBufferDatum (MergedDatum, Buffer,
960                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
961
962        /*
963         * Save the raw datum that was just acquired since it may contain bits
964         * of the *next* field datum.  Update offsets
965         */
966        PreviousRawDatum = ThisRawDatum;
967        DatumOffset++;
968    }
969
970    return_ACPI_STATUS (AE_OK);
971}
972
973
974/*******************************************************************************
975 *
976 * FUNCTION:    AcpiExInsertIntoField
977 *
978 * PARAMETERS:  *ObjDesc            - Field to be set
979 *              Buffer              - Value to store
980 *
981 * RETURN:      Status
982 *
983 * DESCRIPTION: Store the value into the given field
984 *
985 ******************************************************************************/
986
987ACPI_STATUS
988AcpiExInsertIntoField (
989    ACPI_OPERAND_OBJECT     *ObjDesc,
990    void                    *Buffer,
991    UINT32                  BufferLength)
992{
993    ACPI_STATUS             Status;
994    UINT32                  FieldDatumByteOffset;
995    UINT32                  DatumOffset;
996    ACPI_INTEGER            Mask;
997    ACPI_INTEGER            MergedDatum;
998    ACPI_INTEGER            PreviousRawDatum;
999    ACPI_INTEGER            ThisRawDatum;
1000    UINT32                  ByteFieldLength;
1001    UINT32                  DatumCount;
1002
1003
1004    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
1005
1006
1007    /*
1008     * Incoming buffer must be at least as long as the field, we do not
1009     * allow "partial" field writes.  We do not care if the buffer is
1010     * larger than the field, this typically happens when an integer is
1011     * written to a field that is actually smaller than an integer.
1012     */
1013    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
1014    if (BufferLength < ByteFieldLength)
1015    {
1016        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n",
1017            BufferLength, ByteFieldLength));
1018
1019        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
1020    }
1021
1022    /* Convert byte count to datum count, round up if necessary */
1023
1024    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
1025
1026    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
1027        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
1028        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth));
1029
1030    /*
1031     * Break the request into up to three parts (similar to an I/O request):
1032     * 1) non-aligned part at start
1033     * 2) aligned part in middle
1034     * 3) non-aligned part at the end
1035     */
1036    FieldDatumByteOffset = 0;
1037    DatumOffset= 0;
1038
1039    /* Get a single datum from the caller's buffer */
1040
1041    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer,
1042            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1043
1044    /*
1045     * Part1:
1046     * Write a partial field datum if field does not begin on a datum boundary
1047     * Note: The code in this section also handles the aligned case
1048     *
1049     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1050     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1051     *
1052     * Mask off bits that are "below" the field (if any)
1053     */
1054    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1055
1056    /* If the field fits in one datum, may need to mask upper bits */
1057
1058    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1059         ObjDesc->CommonField.EndFieldValidBits)
1060    {
1061        /* There are bits above the field, mask them off also */
1062
1063        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1064    }
1065
1066    /* Shift and mask the value into the field position */
1067
1068    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1069    MergedDatum &= Mask;
1070
1071    /* Apply the update rule (if necessary) and write the datum to the field */
1072
1073    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1074                        FieldDatumByteOffset);
1075    if (ACPI_FAILURE (Status))
1076    {
1077        return_ACPI_STATUS (Status);
1078    }
1079
1080    /* If the entire field fits within one datum, we are done. */
1081
1082    if ((DatumCount == 1) &&
1083       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1084    {
1085        return_ACPI_STATUS (AE_OK);
1086    }
1087
1088    /*
1089     * Part2:
1090     * Write the aligned data.
1091     *
1092     * We don't need to worry about the update rule for these data, because
1093     * all of the bits in each datum are part of the field.
1094     *
1095     * The last datum must be special cased because it might contain bits
1096     * that are not part of the field -- therefore the "update rule" must be
1097     * applied in Part3 below.
1098     */
1099    while (DatumOffset < DatumCount)
1100    {
1101        DatumOffset++;
1102        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1103
1104        /*
1105         * Get the next raw buffer datum.  It may contain bits of the previous
1106         * field datum
1107         */
1108        AcpiExGetBufferDatum (&ThisRawDatum, Buffer,
1109                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1110
1111        /* Create the field datum based on the field alignment */
1112
1113        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1114        {
1115            /*
1116             * Put together appropriate bits of the two raw buffer data to make
1117             * a single complete field datum
1118             */
1119            MergedDatum =
1120                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1121                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1122        }
1123        else
1124        {
1125            /* Field began aligned on datum boundary */
1126
1127            MergedDatum = ThisRawDatum;
1128        }
1129
1130        /*
1131         * Special handling for the last datum if the field does NOT end on
1132         * a datum boundary.  Update Rule must be applied to the bits outside
1133         * the field.
1134         */
1135        if (DatumOffset == DatumCount)
1136        {
1137            /*
1138             * If there are dangling non-aligned bits, perform one more merged write
1139             * Else - field is aligned at the end, no need for any more writes
1140             */
1141            if (ObjDesc->CommonField.EndFieldValidBits)
1142            {
1143                /*
1144                 * Part3:
1145                 * This is the last datum and the field does not end on a datum boundary.
1146                 * Build the partial datum and write with the update rule.
1147                 *
1148                 * Mask off the unused bits above (after) the end-of-field
1149                 */
1150                Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1151                MergedDatum &= Mask;
1152
1153                /* Write the last datum with the update rule */
1154
1155                Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1156                                    FieldDatumByteOffset);
1157                if (ACPI_FAILURE (Status))
1158                {
1159                    return_ACPI_STATUS (Status);
1160                }
1161            }
1162        }
1163        else
1164        {
1165            /* Normal case -- write the completed datum */
1166
1167            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1168                            &MergedDatum, ACPI_WRITE);
1169            if (ACPI_FAILURE (Status))
1170            {
1171                return_ACPI_STATUS (Status);
1172            }
1173        }
1174
1175        /*
1176         * Save the most recent datum since it may contain bits of the *next*
1177         * field datum.  Update current byte offset.
1178         */
1179        PreviousRawDatum = ThisRawDatum;
1180    }
1181
1182    return_ACPI_STATUS (Status);
1183}
1184
1185
1186