exfldio.c revision 122944
1/******************************************************************************
2 *
3 * Module Name: exfldio - Aml Field I/O
4 *              $Revision: 96 $
5 *
6 *****************************************************************************/
7
8/******************************************************************************
9 *
10 * 1. Copyright Notice
11 *
12 * Some or all of this work - Copyright (c) 1999 - 2003, Intel Corp.
13 * All rights reserved.
14 *
15 * 2. License
16 *
17 * 2.1. This is your license from Intel Corp. under its intellectual property
18 * rights.  You may have additional license terms from the party that provided
19 * you this software, covering your right to use that party's intellectual
20 * property rights.
21 *
22 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
23 * copy of the source code appearing in this file ("Covered Code") an
24 * irrevocable, perpetual, worldwide license under Intel's copyrights in the
25 * base code distributed originally by Intel ("Original Intel Code") to copy,
26 * 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     * BufferField - Read/write from/to a Buffer
426     * RegionField - Read/write from/to a Operation Region.
427     * BankField   - Write to a Bank Register, then read/write from/to an OpRegion
428     * IndexField  - 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        FieldDatumByteOffset += ObjDesc->IndexField.Value;
527
528        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
529                "Write to Index Register: Value %8.8X\n",
530                FieldDatumByteOffset));
531
532        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
533                                &FieldDatumByteOffset,
534                                sizeof (FieldDatumByteOffset));
535        if (ACPI_FAILURE (Status))
536        {
537            return_ACPI_STATUS (Status);
538        }
539
540        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
541                "I/O to Data Register: ValuePtr %p\n",
542                Value));
543
544        if (ReadWrite == ACPI_READ)
545        {
546            /* Read the datum from the DataRegister */
547
548            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
549                            Value, sizeof (ACPI_INTEGER));
550        }
551        else
552        {
553            /* Write the datum to the DataRegister */
554
555            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
556                            Value, sizeof (ACPI_INTEGER));
557        }
558        break;
559
560
561    default:
562
563        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",
564            ObjDesc, AcpiUtGetObjectTypeName (ObjDesc)));
565        Status = AE_AML_INTERNAL;
566        break;
567    }
568
569    if (ACPI_SUCCESS (Status))
570    {
571        if (ReadWrite == ACPI_READ)
572        {
573            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",
574                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
575        }
576        else
577        {
578            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",
579                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
580        }
581    }
582
583    return_ACPI_STATUS (Status);
584}
585
586
587/*******************************************************************************
588 *
589 * FUNCTION:    AcpiExWriteWithUpdateRule
590 *
591 * PARAMETERS:  *ObjDesc            - Field to be set
592 *              Value               - Value to store
593 *
594 * RETURN:      Status
595 *
596 * DESCRIPTION: Apply the field update rule to a field write
597 *
598 ******************************************************************************/
599
600ACPI_STATUS
601AcpiExWriteWithUpdateRule (
602    ACPI_OPERAND_OBJECT     *ObjDesc,
603    ACPI_INTEGER            Mask,
604    ACPI_INTEGER            FieldValue,
605    UINT32                  FieldDatumByteOffset)
606{
607    ACPI_STATUS             Status = AE_OK;
608    ACPI_INTEGER            MergedValue;
609    ACPI_INTEGER            CurrentValue;
610
611
612    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
613
614
615    /* Start with the new bits  */
616
617    MergedValue = FieldValue;
618
619    /* If the mask is all ones, we don't need to worry about the update rule */
620
621    if (Mask != ACPI_INTEGER_MAX)
622    {
623        /* Decode the update rule */
624
625        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
626        {
627        case AML_FIELD_UPDATE_PRESERVE:
628            /*
629             * Check if update rule needs to be applied (not if mask is all
630             * ones)  The left shift drops the bits we want to ignore.
631             */
632            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
633                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
634            {
635                /*
636                 * Read the current contents of the byte/word/dword containing
637                 * the field, and merge with the new field value.
638                 */
639                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
640                                &CurrentValue, ACPI_READ);
641                MergedValue |= (CurrentValue & ~Mask);
642            }
643            break;
644
645        case AML_FIELD_UPDATE_WRITE_AS_ONES:
646
647            /* Set positions outside the field to all ones */
648
649            MergedValue |= ~Mask;
650            break;
651
652        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
653
654            /* Set positions outside the field to all zeros */
655
656            MergedValue &= Mask;
657            break;
658
659        default:
660            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
661                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
662                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
663            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
664        }
665    }
666
667    /* Write the merged value */
668
669    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
670                    &MergedValue, ACPI_WRITE);
671
672    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
673        "Mask %8.8X%8.8X DatumOffset %X Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
674        ACPI_HIDWORD (Mask), ACPI_LODWORD (Mask),
675        FieldDatumByteOffset,
676        ACPI_HIDWORD (FieldValue), ACPI_LODWORD (FieldValue),
677        ACPI_HIDWORD (MergedValue),ACPI_LODWORD (MergedValue)));
678
679    return_ACPI_STATUS (Status);
680}
681
682
683/*******************************************************************************
684 *
685 * FUNCTION:    AcpiExGetBufferDatum
686 *
687 * PARAMETERS:  Datum               - Where the Datum is returned
688 *              Buffer              - Raw field buffer
689 *              BufferLength        - Entire length (used for big-endian only)
690 *              ByteGranularity     - 1/2/4/8 Granularity of the field
691 *                                    (aka Datum Size)
692 *              BufferOffset        - Datum offset into the buffer
693 *
694 * RETURN:      none
695 *
696 * DESCRIPTION: Get a datum from the buffer according to the buffer field
697 *              byte granularity
698 *
699 ******************************************************************************/
700
701void
702AcpiExGetBufferDatum (
703    ACPI_INTEGER            *Datum,
704    void                    *Buffer,
705    UINT32                  BufferLength,
706    UINT32                  ByteGranularity,
707    UINT32                  BufferOffset)
708{
709    UINT32                  Index;
710
711
712    ACPI_FUNCTION_ENTRY ();
713
714
715    /* Get proper index into buffer (handles big/little endian) */
716
717    Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
718
719    /* Move the requested number of bytes */
720
721    switch (ByteGranularity)
722    {
723    case ACPI_FIELD_BYTE_GRANULARITY:
724
725        *Datum = ((UINT8 *) Buffer) [Index];
726        break;
727
728    case ACPI_FIELD_WORD_GRANULARITY:
729
730        ACPI_MOVE_16_TO_64 (Datum, &(((UINT16 *) Buffer) [Index]));
731        break;
732
733    case ACPI_FIELD_DWORD_GRANULARITY:
734
735        ACPI_MOVE_32_TO_64 (Datum, &(((UINT32 *) Buffer) [Index]));
736        break;
737
738    case ACPI_FIELD_QWORD_GRANULARITY:
739
740        ACPI_MOVE_64_TO_64 (Datum, &(((UINT64 *) Buffer) [Index]));
741        break;
742
743    default:
744        /* Should not get here */
745        break;
746    }
747}
748
749
750/*******************************************************************************
751 *
752 * FUNCTION:    AcpiExSetBufferDatum
753 *
754 * PARAMETERS:  MergedDatum         - Value to store
755 *              Buffer              - Receiving buffer
756 *              BufferLength        - Entire length (used for big-endian only)
757 *              ByteGranularity     - 1/2/4/8 Granularity of the field
758 *                                    (aka Datum Size)
759 *              BufferOffset        - Datum offset into the buffer
760 *
761 * RETURN:      none
762 *
763 * DESCRIPTION: Store the merged datum to the buffer according to the
764 *              byte granularity
765 *
766 ******************************************************************************/
767
768void
769AcpiExSetBufferDatum (
770    ACPI_INTEGER            MergedDatum,
771    void                    *Buffer,
772    UINT32                  BufferLength,
773    UINT32                  ByteGranularity,
774    UINT32                  BufferOffset)
775{
776    UINT32                  Index;
777
778    ACPI_FUNCTION_ENTRY ();
779
780
781    /* Get proper index into buffer (handles big/little endian) */
782
783    Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
784
785    /* Move the requested number of bytes */
786
787    switch (ByteGranularity)
788    {
789    case ACPI_FIELD_BYTE_GRANULARITY:
790
791        ((UINT8 *) Buffer) [Index] = (UINT8) MergedDatum;
792        break;
793
794    case ACPI_FIELD_WORD_GRANULARITY:
795
796        ACPI_MOVE_64_TO_16 (&(((UINT16 *) Buffer)[Index]), &MergedDatum);
797        break;
798
799    case ACPI_FIELD_DWORD_GRANULARITY:
800
801        ACPI_MOVE_64_TO_32 (&(((UINT32 *) Buffer)[Index]), &MergedDatum);
802        break;
803
804    case ACPI_FIELD_QWORD_GRANULARITY:
805
806        ACPI_MOVE_64_TO_64 (&(((UINT64 *) Buffer)[Index]), &MergedDatum);
807        break;
808
809    default:
810        /* Should not get here */
811        break;
812    }
813}
814
815
816/*******************************************************************************
817 *
818 * FUNCTION:    AcpiExExtractFromField
819 *
820 * PARAMETERS:  *ObjDesc            - Field to be read
821 *              *Value              - Where to store value
822 *
823 * RETURN:      Status
824 *
825 * DESCRIPTION: Retrieve the value of the given field
826 *
827 ******************************************************************************/
828
829ACPI_STATUS
830AcpiExExtractFromField (
831    ACPI_OPERAND_OBJECT     *ObjDesc,
832    void                    *Buffer,
833    UINT32                  BufferLength)
834{
835    ACPI_STATUS             Status;
836    UINT32                  FieldDatumByteOffset;
837    UINT32                  DatumOffset;
838    ACPI_INTEGER            PreviousRawDatum;
839    ACPI_INTEGER            ThisRawDatum = 0;
840    ACPI_INTEGER            MergedDatum = 0;
841    UINT32                  ByteFieldLength;
842    UINT32                  DatumCount;
843
844
845    ACPI_FUNCTION_TRACE ("ExExtractFromField");
846
847
848    /*
849     * The field must fit within the caller's buffer
850     */
851    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
852    if (ByteFieldLength > BufferLength)
853    {
854        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
855            "Field size %X (bytes) too large for buffer (%X)\n",
856            ByteFieldLength, BufferLength));
857
858        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
859    }
860
861    /* Convert field byte count to datum count, round up if necessary */
862
863    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
864                              ObjDesc->CommonField.AccessByteWidth);
865
866    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
867        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
868        ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth));
869
870    /*
871     * Clear the caller's buffer (the whole buffer length as given)
872     * This is very important, especially in the cases where a byte is read,
873     * but the buffer is really a UINT32 (4 bytes).
874     */
875    ACPI_MEMSET (Buffer, 0, BufferLength);
876
877    /* Read the first raw datum to prime the loop */
878
879    FieldDatumByteOffset = 0;
880    DatumOffset= 0;
881
882    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
883                    &PreviousRawDatum, ACPI_READ);
884    if (ACPI_FAILURE (Status))
885    {
886        return_ACPI_STATUS (Status);
887    }
888
889
890    /* We might actually be done if the request fits in one datum */
891
892    if ((DatumCount == 1) &&
893        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
894    {
895        /* 1) Shift the valid data bits down to start at bit 0 */
896
897        MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
898
899        /* 2) Mask off any upper unused bits (bits not part of the field) */
900
901        if (ObjDesc->CommonField.EndBufferValidBits)
902        {
903            MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
904        }
905
906        /* Store the datum to the caller buffer */
907
908        AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
909                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
910
911        return_ACPI_STATUS (AE_OK);
912    }
913
914
915    /* We need to get more raw data to complete one or more field data */
916
917    while (DatumOffset < DatumCount)
918    {
919        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
920
921        /*
922         * If the field is aligned on a byte boundary, we don't want
923         * to perform a final read, since this would potentially read
924         * past the end of the region.
925         *
926         * We could just split the aligned and non-aligned cases since the
927         * aligned case is so very simple, but this would require more code.
928         */
929        if ((ObjDesc->CommonField.StartFieldBitOffset != 0)  ||
930            ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
931            (DatumOffset < (DatumCount -1))))
932        {
933            /*
934             * Get the next raw datum, it contains some or all bits
935             * of the current field datum
936             */
937            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
938                            &ThisRawDatum, ACPI_READ);
939            if (ACPI_FAILURE (Status))
940            {
941                return_ACPI_STATUS (Status);
942            }
943        }
944
945        /*
946         * Create the (possibly) merged datum to be stored to the caller buffer
947         */
948        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
949        {
950            /* Field is not skewed and we can just copy the datum */
951
952            MergedDatum = PreviousRawDatum;
953        }
954        else
955        {
956            /*
957             * Put together the appropriate bits of the two raw data to make a
958             * single complete field datum
959             *
960             * 1) Normalize the first datum down to bit 0
961             */
962            MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
963
964            /* 2) Insert the second datum "above" the first datum */
965
966            MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
967
968            if ((DatumOffset >= (DatumCount -1)))
969            {
970                /*
971                 * This is the last iteration of the loop.  We need to clear
972                 * any unused bits (bits that are not part of this field) that
973                 * came from the last raw datum before we store the final
974                 * merged datum into the caller buffer.
975                 */
976                if (ObjDesc->CommonField.EndBufferValidBits)
977                {
978                    MergedDatum &=
979                        ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
980                }
981            }
982        }
983
984        /*
985         * Store the merged field datum in the caller's buffer, according to
986         * the granularity of the field (size of each datum).
987         */
988        AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
989                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
990
991        /*
992         * Save the raw datum that was just acquired since it may contain bits
993         * of the *next* field datum.  Update offsets
994         */
995        PreviousRawDatum = ThisRawDatum;
996        DatumOffset++;
997    }
998
999    return_ACPI_STATUS (AE_OK);
1000}
1001
1002
1003/*******************************************************************************
1004 *
1005 * FUNCTION:    AcpiExInsertIntoField
1006 *
1007 * PARAMETERS:  *ObjDesc            - Field to be set
1008 *              Buffer              - Value to store
1009 *
1010 * RETURN:      Status
1011 *
1012 * DESCRIPTION: Store the value into the given field
1013 *
1014 ******************************************************************************/
1015
1016ACPI_STATUS
1017AcpiExInsertIntoField (
1018    ACPI_OPERAND_OBJECT     *ObjDesc,
1019    void                    *Buffer,
1020    UINT32                  BufferLength)
1021{
1022    ACPI_STATUS             Status;
1023    UINT32                  FieldDatumByteOffset;
1024    UINT32                  DatumOffset;
1025    ACPI_INTEGER            Mask;
1026    ACPI_INTEGER            MergedDatum;
1027    ACPI_INTEGER            PreviousRawDatum;
1028    ACPI_INTEGER            ThisRawDatum;
1029    UINT32                  ByteFieldLength;
1030    UINT32                  DatumCount;
1031
1032
1033    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
1034
1035
1036    /*
1037     * Incoming buffer must be at least as long as the field, we do not
1038     * allow "partial" field writes.  We do not care if the buffer is
1039     * larger than the field, this typically happens when an integer is
1040     * written to a field that is actually smaller than an integer.
1041     */
1042    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
1043    if (BufferLength < ByteFieldLength)
1044    {
1045        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n",
1046            BufferLength, ByteFieldLength));
1047
1048        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
1049    }
1050
1051    /* Convert byte count to datum count, round up if necessary */
1052
1053    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
1054
1055    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
1056        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
1057        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth));
1058
1059    /*
1060     * Break the request into up to three parts (similar to an I/O request):
1061     * 1) non-aligned part at start
1062     * 2) aligned part in middle
1063     * 3) non-aligned part at the end
1064     */
1065    FieldDatumByteOffset = 0;
1066    DatumOffset= 0;
1067
1068    /* Get a single datum from the caller's buffer */
1069
1070    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength,
1071            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1072
1073    /*
1074     * Part1:
1075     * Write a partial field datum if field does not begin on a datum boundary
1076     * Note: The code in this section also handles the aligned case
1077     *
1078     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1079     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1080     *
1081     * Mask off bits that are "below" the field (if any)
1082     */
1083    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1084
1085    /* If the field fits in one datum, may need to mask upper bits */
1086
1087    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1088         ObjDesc->CommonField.EndFieldValidBits)
1089    {
1090        /* There are bits above the field, mask them off also */
1091
1092        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1093    }
1094
1095    /* Shift and mask the value into the field position */
1096
1097    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1098    MergedDatum &= Mask;
1099
1100    /* Apply the update rule (if necessary) and write the datum to the field */
1101
1102    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1103                        FieldDatumByteOffset);
1104    if (ACPI_FAILURE (Status))
1105    {
1106        return_ACPI_STATUS (Status);
1107    }
1108
1109    /* If the entire field fits within one datum, we are done. */
1110
1111    if ((DatumCount == 1) &&
1112       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1113    {
1114        return_ACPI_STATUS (AE_OK);
1115    }
1116
1117    /*
1118     * Part2:
1119     * Write the aligned data.
1120     *
1121     * We don't need to worry about the update rule for these data, because
1122     * all of the bits in each datum are part of the field.
1123     *
1124     * The last datum must be special cased because it might contain bits
1125     * that are not part of the field -- therefore the "update rule" must be
1126     * applied in Part3 below.
1127     */
1128    while (DatumOffset < DatumCount)
1129    {
1130        DatumOffset++;
1131        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1132
1133        /*
1134         * Get the next raw buffer datum.  It may contain bits of the previous
1135         * field datum
1136         */
1137        AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength,
1138                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1139
1140        /* Create the field datum based on the field alignment */
1141
1142        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1143        {
1144            /*
1145             * Put together appropriate bits of the two raw buffer data to make
1146             * a single complete field datum
1147             */
1148            MergedDatum =
1149                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1150                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1151        }
1152        else
1153        {
1154            /* Field began aligned on datum boundary */
1155
1156            MergedDatum = ThisRawDatum;
1157        }
1158
1159        /*
1160         * Special handling for the last datum if the field does NOT end on
1161         * a datum boundary.  Update Rule must be applied to the bits outside
1162         * the field.
1163         */
1164        if (DatumOffset == DatumCount)
1165        {
1166            /*
1167             * If there are dangling non-aligned bits, perform one more merged write
1168             * Else - field is aligned at the end, no need for any more writes
1169             */
1170            if (ObjDesc->CommonField.EndFieldValidBits)
1171            {
1172                /*
1173                 * Part3:
1174                 * This is the last datum and the field does not end on a datum boundary.
1175                 * Build the partial datum and write with the update rule.
1176                 *
1177                 * Mask off the unused bits above (after) the end-of-field
1178                 */
1179                Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1180                MergedDatum &= Mask;
1181
1182                /* Write the last datum with the update rule */
1183
1184                Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1185                                    FieldDatumByteOffset);
1186                if (ACPI_FAILURE (Status))
1187                {
1188                    return_ACPI_STATUS (Status);
1189                }
1190            }
1191        }
1192        else
1193        {
1194            /* Normal case -- write the completed datum */
1195
1196            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1197                            &MergedDatum, ACPI_WRITE);
1198            if (ACPI_FAILURE (Status))
1199            {
1200                return_ACPI_STATUS (Status);
1201            }
1202        }
1203
1204        /*
1205         * Save the most recent datum since it may contain bits of the *next*
1206         * field datum.  Update current byte offset.
1207         */
1208        PreviousRawDatum = ThisRawDatum;
1209    }
1210
1211    return_ACPI_STATUS (Status);
1212}
1213
1214
1215