exfldio.c revision 151937
1/******************************************************************************
2 *
3 * Module Name: exfldio - Aml Field I/O
4 *              $Revision: 1.116 $
5 *
6 *****************************************************************************/
7
8/******************************************************************************
9 *
10 * 1. Copyright Notice
11 *
12 * Some or all of this work - Copyright (c) 1999 - 2005, 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 <contrib/dev/acpica/acpi.h>
121#include <contrib/dev/acpica/acinterp.h>
122#include <contrib/dev/acpica/amlcode.h>
123#include <contrib/dev/acpica/acevents.h>
124#include <contrib/dev/acpica/acdispat.h>
125
126
127#define _COMPONENT          ACPI_EXECUTER
128        ACPI_MODULE_NAME    ("exfldio")
129
130/* Local prototypes */
131
132static ACPI_STATUS
133AcpiExFieldDatumIo (
134    ACPI_OPERAND_OBJECT     *ObjDesc,
135    UINT32                  FieldDatumByteOffset,
136    ACPI_INTEGER            *Value,
137    UINT32                  ReadWrite);
138
139static BOOLEAN
140AcpiExRegisterOverflow (
141    ACPI_OPERAND_OBJECT     *ObjDesc,
142    ACPI_INTEGER            Value);
143
144static ACPI_STATUS
145AcpiExSetupRegion (
146    ACPI_OPERAND_OBJECT     *ObjDesc,
147    UINT32                  FieldDatumByteOffset);
148
149
150/*******************************************************************************
151 *
152 * FUNCTION:    AcpiExSetupRegion
153 *
154 * PARAMETERS:  ObjDesc                 - Field to be read or written
155 *              FieldDatumByteOffset    - Byte offset of this datum within the
156 *                                        parent field
157 *
158 * RETURN:      Status
159 *
160 * DESCRIPTION: Common processing for AcpiExExtractFromField and
161 *              AcpiExInsertIntoField.  Initialize the Region if necessary and
162 *              validate the request.
163 *
164 ******************************************************************************/
165
166static ACPI_STATUS
167AcpiExSetupRegion (
168    ACPI_OPERAND_OBJECT     *ObjDesc,
169    UINT32                  FieldDatumByteOffset)
170{
171    ACPI_STATUS             Status = AE_OK;
172    ACPI_OPERAND_OBJECT     *RgnDesc;
173
174
175    ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
176
177
178    RgnDesc = ObjDesc->CommonField.RegionObj;
179
180    /* We must have a valid region */
181
182    if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
183    {
184        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
185            ACPI_GET_OBJECT_TYPE (RgnDesc),
186            AcpiUtGetObjectTypeName (RgnDesc)));
187
188        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
189    }
190
191    /*
192     * If the Region Address and Length have not been previously evaluated,
193     * evaluate them now and save the results.
194     */
195    if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
196    {
197        Status = AcpiDsGetRegionArguments (RgnDesc);
198        if (ACPI_FAILURE (Status))
199        {
200            return_ACPI_STATUS (Status);
201        }
202    }
203
204    if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
205    {
206        /* SMBus has a non-linear address space */
207
208        return_ACPI_STATUS (AE_OK);
209    }
210
211#ifdef ACPI_UNDER_DEVELOPMENT
212    /*
213     * If the Field access is AnyAcc, we can now compute the optimal
214     * access (because we know know the length of the parent region)
215     */
216    if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
217    {
218        if (ACPI_FAILURE (Status))
219        {
220            return_ACPI_STATUS (Status);
221        }
222    }
223#endif
224
225    /*
226     * Validate the request.  The entire request from the byte offset for a
227     * length of one field datum (access width) must fit within the region.
228     * (Region length is specified in bytes)
229     */
230    if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset +
231                                    FieldDatumByteOffset +
232                                    ObjDesc->CommonField.AccessByteWidth))
233    {
234        if (AcpiGbl_EnableInterpreterSlack)
235        {
236            /*
237             * Slack mode only:  We will go ahead and allow access to this
238             * field if it is within the region length rounded up to the next
239             * access width boundary.
240             */
241            if (ACPI_ROUND_UP (RgnDesc->Region.Length,
242                                ObjDesc->CommonField.AccessByteWidth) >=
243                (ObjDesc->CommonField.BaseByteOffset +
244                 (ACPI_NATIVE_UINT) ObjDesc->CommonField.AccessByteWidth +
245                 FieldDatumByteOffset))
246            {
247                return_ACPI_STATUS (AE_OK);
248            }
249        }
250
251        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
252        {
253            /*
254             * This is the case where the AccessType (AccWord, etc.) is wider
255             * than the region itself.  For example, a region of length one
256             * byte, and a field with Dword access specified.
257             */
258            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
259                "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
260                AcpiUtGetNodeName (ObjDesc->CommonField.Node),
261                ObjDesc->CommonField.AccessByteWidth,
262                AcpiUtGetNodeName (RgnDesc->Region.Node),
263                RgnDesc->Region.Length));
264        }
265
266        /*
267         * Offset rounded up to next multiple of field width
268         * exceeds region length, indicate an error
269         */
270        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
271            "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
272            AcpiUtGetNodeName (ObjDesc->CommonField.Node),
273            ObjDesc->CommonField.BaseByteOffset,
274            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
275            AcpiUtGetNodeName (RgnDesc->Region.Node),
276            RgnDesc->Region.Length));
277
278        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
279    }
280
281    return_ACPI_STATUS (AE_OK);
282}
283
284
285/*******************************************************************************
286 *
287 * FUNCTION:    AcpiExAccessRegion
288 *
289 * PARAMETERS:  ObjDesc                 - Field to be read
290 *              FieldDatumByteOffset    - Byte offset of this datum within the
291 *                                        parent field
292 *              Value                   - Where to store value (must at least
293 *                                        the size of ACPI_INTEGER)
294 *              Function                - Read or Write flag plus other region-
295 *                                        dependent flags
296 *
297 * RETURN:      Status
298 *
299 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
300 *
301 ******************************************************************************/
302
303ACPI_STATUS
304AcpiExAccessRegion (
305    ACPI_OPERAND_OBJECT     *ObjDesc,
306    UINT32                  FieldDatumByteOffset,
307    ACPI_INTEGER            *Value,
308    UINT32                  Function)
309{
310    ACPI_STATUS             Status;
311    ACPI_OPERAND_OBJECT     *RgnDesc;
312    ACPI_PHYSICAL_ADDRESS   Address;
313
314
315    ACPI_FUNCTION_TRACE ("ExAccessRegion");
316
317
318    /*
319     * Ensure that the region operands are fully evaluated and verify
320     * the validity of the request
321     */
322    Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
323    if (ACPI_FAILURE (Status))
324    {
325        return_ACPI_STATUS (Status);
326    }
327
328    /*
329     * The physical address of this field datum is:
330     *
331     * 1) The base of the region, plus
332     * 2) The base offset of the field, plus
333     * 3) The current offset into the field
334     */
335    RgnDesc = ObjDesc->CommonField.RegionObj;
336    Address = RgnDesc->Region.Address +
337                ObjDesc->CommonField.BaseByteOffset +
338                FieldDatumByteOffset;
339
340    if ((Function & ACPI_IO_MASK) == ACPI_READ)
341    {
342        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
343    }
344    else
345    {
346        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
347    }
348
349    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
350        " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
351        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
352        RgnDesc->Region.SpaceId,
353        ObjDesc->CommonField.AccessByteWidth,
354        ObjDesc->CommonField.BaseByteOffset,
355        FieldDatumByteOffset,
356        ACPI_FORMAT_UINT64 (Address)));
357
358    /* Invoke the appropriate AddressSpace/OpRegion handler */
359
360    Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function,
361                Address,
362                ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
363
364    if (ACPI_FAILURE (Status))
365    {
366        if (Status == AE_NOT_IMPLEMENTED)
367        {
368            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
369                "Region %s(%X) not implemented\n",
370                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
371                RgnDesc->Region.SpaceId));
372        }
373        else if (Status == AE_NOT_EXIST)
374        {
375            ACPI_REPORT_ERROR ((
376                "Region %s(%X) has no handler\n",
377                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
378                RgnDesc->Region.SpaceId));
379        }
380    }
381
382    return_ACPI_STATUS (Status);
383}
384
385
386/*******************************************************************************
387 *
388 * FUNCTION:    AcpiExRegisterOverflow
389 *
390 * PARAMETERS:  ObjDesc                 - Register(Field) to be written
391 *              Value                   - Value to be stored
392 *
393 * RETURN:      TRUE if value overflows the field, FALSE otherwise
394 *
395 * DESCRIPTION: Check if a value is out of range of the field being written.
396 *              Used to check if the values written to Index and Bank registers
397 *              are out of range.  Normally, the value is simply truncated
398 *              to fit the field, but this case is most likely a serious
399 *              coding error in the ASL.
400 *
401 ******************************************************************************/
402
403static BOOLEAN
404AcpiExRegisterOverflow (
405    ACPI_OPERAND_OBJECT     *ObjDesc,
406    ACPI_INTEGER            Value)
407{
408
409    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
410    {
411        /*
412         * The field is large enough to hold the maximum integer, so we can
413         * never overflow it.
414         */
415        return (FALSE);
416    }
417
418    if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
419    {
420        /*
421         * The Value is larger than the maximum value that can fit into
422         * the register.
423         */
424        return (TRUE);
425    }
426
427    /* The Value will fit into the field with no truncation */
428
429    return (FALSE);
430}
431
432
433/*******************************************************************************
434 *
435 * FUNCTION:    AcpiExFieldDatumIo
436 *
437 * PARAMETERS:  ObjDesc                 - Field to be read
438 *              FieldDatumByteOffset    - Byte offset of this datum within the
439 *                                        parent field
440 *              Value                   - Where to store value (must be 64 bits)
441 *              ReadWrite               - Read or Write flag
442 *
443 * RETURN:      Status
444 *
445 * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
446 *              demultiplexed here to handle the different types of fields
447 *              (BufferField, RegionField, IndexField, BankField)
448 *
449 ******************************************************************************/
450
451static ACPI_STATUS
452AcpiExFieldDatumIo (
453    ACPI_OPERAND_OBJECT     *ObjDesc,
454    UINT32                  FieldDatumByteOffset,
455    ACPI_INTEGER            *Value,
456    UINT32                  ReadWrite)
457{
458    ACPI_STATUS             Status;
459    ACPI_INTEGER            LocalValue;
460
461
462    ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
463
464
465    if (ReadWrite == ACPI_READ)
466    {
467        if (!Value)
468        {
469            LocalValue = 0;
470
471            /* To support reads without saving return value */
472            Value = &LocalValue;
473        }
474
475        /* Clear the entire return buffer first, [Very Important!] */
476
477        *Value = 0;
478    }
479
480    /*
481     * The four types of fields are:
482     *
483     * BufferField - Read/write from/to a Buffer
484     * RegionField - Read/write from/to a Operation Region.
485     * BankField   - Write to a Bank Register, then read/write from/to an
486     *               OperationRegion
487     * IndexField  - Write to an Index Register, then read/write from/to a
488     *               Data Register
489     */
490    switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
491    {
492    case ACPI_TYPE_BUFFER_FIELD:
493        /*
494         * If the BufferField arguments have not been previously evaluated,
495         * evaluate them now and save the results.
496         */
497        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
498        {
499            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
500            if (ACPI_FAILURE (Status))
501            {
502                return_ACPI_STATUS (Status);
503            }
504        }
505
506        if (ReadWrite == ACPI_READ)
507        {
508            /*
509             * Copy the data from the source buffer.
510             * Length is the field width in bytes.
511             */
512            ACPI_MEMCPY (Value,
513                (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
514                    ObjDesc->BufferField.BaseByteOffset +
515                    FieldDatumByteOffset,
516                ObjDesc->CommonField.AccessByteWidth);
517        }
518        else
519        {
520            /*
521             * Copy the data to the target buffer.
522             * Length is the field width in bytes.
523             */
524            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
525                    ObjDesc->BufferField.BaseByteOffset +
526                    FieldDatumByteOffset,
527                    Value, ObjDesc->CommonField.AccessByteWidth);
528        }
529
530        Status = AE_OK;
531        break;
532
533
534    case ACPI_TYPE_LOCAL_BANK_FIELD:
535
536        /*
537         * Ensure that the BankValue is not beyond the capacity of
538         * the register
539         */
540        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
541                                    (ACPI_INTEGER) ObjDesc->BankField.Value))
542        {
543            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
544        }
545
546        /*
547         * For BankFields, we must write the BankValue to the BankRegister
548         * (itself a RegionField) before we can access the data.
549         */
550        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
551                                &ObjDesc->BankField.Value,
552                                sizeof (ObjDesc->BankField.Value));
553        if (ACPI_FAILURE (Status))
554        {
555            return_ACPI_STATUS (Status);
556        }
557
558        /*
559         * Now that the Bank has been selected, fall through to the
560         * RegionField case and write the datum to the Operation Region
561         */
562
563        /*lint -fallthrough */
564
565
566    case ACPI_TYPE_LOCAL_REGION_FIELD:
567        /*
568         * For simple RegionFields, we just directly access the owning
569         * Operation Region.
570         */
571        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
572                        ReadWrite);
573        break;
574
575
576    case ACPI_TYPE_LOCAL_INDEX_FIELD:
577
578
579        /*
580         * Ensure that the IndexValue is not beyond the capacity of
581         * the register
582         */
583        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
584                                    (ACPI_INTEGER) ObjDesc->IndexField.Value))
585        {
586            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
587        }
588
589        /* Write the index value to the IndexRegister (itself a RegionField) */
590
591        FieldDatumByteOffset += ObjDesc->IndexField.Value;
592
593        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
594                "Write to Index Register: Value %8.8X\n",
595                FieldDatumByteOffset));
596
597        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
598                                &FieldDatumByteOffset,
599                                sizeof (FieldDatumByteOffset));
600        if (ACPI_FAILURE (Status))
601        {
602            return_ACPI_STATUS (Status);
603        }
604
605        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
606                "I/O to Data Register: ValuePtr %p\n",
607                Value));
608
609        if (ReadWrite == ACPI_READ)
610        {
611            /* Read the datum from the DataRegister */
612
613            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
614                            Value, sizeof (ACPI_INTEGER));
615        }
616        else
617        {
618            /* Write the datum to the DataRegister */
619
620            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
621                            Value, sizeof (ACPI_INTEGER));
622        }
623        break;
624
625
626    default:
627
628        ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n",
629            ACPI_GET_OBJECT_TYPE (ObjDesc)));
630        Status = AE_AML_INTERNAL;
631        break;
632    }
633
634    if (ACPI_SUCCESS (Status))
635    {
636        if (ReadWrite == ACPI_READ)
637        {
638            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
639                "Value Read %8.8X%8.8X, Width %d\n",
640                ACPI_FORMAT_UINT64 (*Value),
641                ObjDesc->CommonField.AccessByteWidth));
642        }
643        else
644        {
645            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
646                "Value Written %8.8X%8.8X, Width %d\n",
647                ACPI_FORMAT_UINT64 (*Value),
648                ObjDesc->CommonField.AccessByteWidth));
649        }
650    }
651
652    return_ACPI_STATUS (Status);
653}
654
655
656/*******************************************************************************
657 *
658 * FUNCTION:    AcpiExWriteWithUpdateRule
659 *
660 * PARAMETERS:  ObjDesc                 - Field to be written
661 *              Mask                    - bitmask within field datum
662 *              FieldValue              - Value to write
663 *              FieldDatumByteOffset    - Offset of datum within field
664 *
665 * RETURN:      Status
666 *
667 * DESCRIPTION: Apply the field update rule to a field write
668 *
669 ******************************************************************************/
670
671ACPI_STATUS
672AcpiExWriteWithUpdateRule (
673    ACPI_OPERAND_OBJECT     *ObjDesc,
674    ACPI_INTEGER            Mask,
675    ACPI_INTEGER            FieldValue,
676    UINT32                  FieldDatumByteOffset)
677{
678    ACPI_STATUS             Status = AE_OK;
679    ACPI_INTEGER            MergedValue;
680    ACPI_INTEGER            CurrentValue;
681
682
683    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
684
685
686    /* Start with the new bits  */
687
688    MergedValue = FieldValue;
689
690    /* If the mask is all ones, we don't need to worry about the update rule */
691
692    if (Mask != ACPI_INTEGER_MAX)
693    {
694        /* Decode the update rule */
695
696        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
697        {
698        case AML_FIELD_UPDATE_PRESERVE:
699            /*
700             * Check if update rule needs to be applied (not if mask is all
701             * ones)  The left shift drops the bits we want to ignore.
702             */
703            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
704                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
705            {
706                /*
707                 * Read the current contents of the byte/word/dword containing
708                 * the field, and merge with the new field value.
709                 */
710                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
711                                &CurrentValue, ACPI_READ);
712                if (ACPI_FAILURE (Status))
713                {
714                    return_ACPI_STATUS (Status);
715                }
716
717                MergedValue |= (CurrentValue & ~Mask);
718            }
719            break;
720
721        case AML_FIELD_UPDATE_WRITE_AS_ONES:
722
723            /* Set positions outside the field to all ones */
724
725            MergedValue |= ~Mask;
726            break;
727
728        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
729
730            /* Set positions outside the field to all zeros */
731
732            MergedValue &= Mask;
733            break;
734
735        default:
736
737            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
738                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
739                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
740            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
741        }
742    }
743
744    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
745        "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
746        ACPI_FORMAT_UINT64 (Mask),
747        FieldDatumByteOffset,
748        ObjDesc->CommonField.AccessByteWidth,
749        ACPI_FORMAT_UINT64 (FieldValue),
750        ACPI_FORMAT_UINT64 (MergedValue)));
751
752    /* Write the merged value */
753
754    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
755                    &MergedValue, ACPI_WRITE);
756
757    return_ACPI_STATUS (Status);
758}
759
760
761/*******************************************************************************
762 *
763 * FUNCTION:    AcpiExExtractFromField
764 *
765 * PARAMETERS:  ObjDesc             - Field to be read
766 *              Buffer              - Where to store the field data
767 *              BufferLength        - Length of Buffer
768 *
769 * RETURN:      Status
770 *
771 * DESCRIPTION: Retrieve the current value of the given field
772 *
773 ******************************************************************************/
774
775ACPI_STATUS
776AcpiExExtractFromField (
777    ACPI_OPERAND_OBJECT     *ObjDesc,
778    void                    *Buffer,
779    UINT32                  BufferLength)
780{
781    ACPI_STATUS             Status;
782    ACPI_INTEGER            RawDatum;
783    ACPI_INTEGER            MergedDatum;
784    UINT32                  FieldOffset = 0;
785    UINT32                  BufferOffset = 0;
786    UINT32                  BufferTailBits;
787    UINT32                  DatumCount;
788    UINT32                  FieldDatumCount;
789    UINT32                  i;
790
791
792    ACPI_FUNCTION_TRACE ("ExExtractFromField");
793
794
795    /* Validate target buffer and clear it */
796
797    if (BufferLength < ACPI_ROUND_BITS_UP_TO_BYTES (
798                            ObjDesc->CommonField.BitLength))
799    {
800        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
801            "Field size %X (bits) is too large for buffer (%X)\n",
802            ObjDesc->CommonField.BitLength, BufferLength));
803
804        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
805    }
806    ACPI_MEMSET (Buffer, 0, BufferLength);
807
808    /* Compute the number of datums (access width data items) */
809
810    DatumCount = ACPI_ROUND_UP_TO (
811                        ObjDesc->CommonField.BitLength,
812                        ObjDesc->CommonField.AccessBitWidth);
813    FieldDatumCount = ACPI_ROUND_UP_TO (
814                        ObjDesc->CommonField.BitLength +
815                        ObjDesc->CommonField.StartFieldBitOffset,
816                        ObjDesc->CommonField.AccessBitWidth);
817
818    /* Priming read from the field */
819
820    Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
821    if (ACPI_FAILURE (Status))
822    {
823        return_ACPI_STATUS (Status);
824    }
825    MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
826
827    /* Read the rest of the field */
828
829    for (i = 1; i < FieldDatumCount; i++)
830    {
831        /* Get next input datum from the field */
832
833        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
834        Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
835                        &RawDatum, ACPI_READ);
836        if (ACPI_FAILURE (Status))
837        {
838            return_ACPI_STATUS (Status);
839        }
840
841        /* Merge with previous datum if necessary */
842
843        MergedDatum |= RawDatum <<
844            (ObjDesc->CommonField.AccessBitWidth -
845                ObjDesc->CommonField.StartFieldBitOffset);
846
847        if (i == DatumCount)
848        {
849            break;
850        }
851
852        /* Write merged datum to target buffer */
853
854        ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
855            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
856                     BufferLength - BufferOffset));
857
858        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
859        MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
860    }
861
862    /* Mask off any extra bits in the last datum */
863
864    BufferTailBits = ObjDesc->CommonField.BitLength %
865                        ObjDesc->CommonField.AccessBitWidth;
866    if (BufferTailBits)
867    {
868        MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
869    }
870
871    /* Write the last datum to the buffer */
872
873    ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
874        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
875                 BufferLength - BufferOffset));
876
877    return_ACPI_STATUS (AE_OK);
878}
879
880
881/*******************************************************************************
882 *
883 * FUNCTION:    AcpiExInsertIntoField
884 *
885 * PARAMETERS:  ObjDesc             - Field to be written
886 *              Buffer              - Data to be written
887 *              BufferLength        - Length of Buffer
888 *
889 * RETURN:      Status
890 *
891 * DESCRIPTION: Store the Buffer contents into the given field
892 *
893 ******************************************************************************/
894
895ACPI_STATUS
896AcpiExInsertIntoField (
897    ACPI_OPERAND_OBJECT     *ObjDesc,
898    void                    *Buffer,
899    UINT32                  BufferLength)
900{
901    ACPI_STATUS             Status;
902    ACPI_INTEGER            Mask;
903    ACPI_INTEGER            MergedDatum;
904    ACPI_INTEGER            RawDatum = 0;
905    UINT32                  FieldOffset = 0;
906    UINT32                  BufferOffset = 0;
907    UINT32                  BufferTailBits;
908    UINT32                  DatumCount;
909    UINT32                  FieldDatumCount;
910    UINT32                  i;
911
912
913    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
914
915
916    /* Validate input buffer */
917
918    if (BufferLength < ACPI_ROUND_BITS_UP_TO_BYTES (
919                            ObjDesc->CommonField.BitLength))
920    {
921        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
922            "Field size %X (bits) is too large for buffer (%X)\n",
923            ObjDesc->CommonField.BitLength, BufferLength));
924
925        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
926    }
927
928    /* Compute the number of datums (access width data items) */
929
930    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
931    DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
932                    ObjDesc->CommonField.AccessBitWidth);
933    FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
934                        ObjDesc->CommonField.StartFieldBitOffset,
935                        ObjDesc->CommonField.AccessBitWidth);
936
937    /* Get initial Datum from the input buffer */
938
939    ACPI_MEMCPY (&RawDatum, Buffer,
940        ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
941                 BufferLength - BufferOffset));
942
943    MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
944
945    /* Write the entire field */
946
947    for (i = 1; i < FieldDatumCount; i++)
948    {
949        /* Write merged datum to the target field */
950
951        MergedDatum &= Mask;
952        Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
953                    MergedDatum, FieldOffset);
954        if (ACPI_FAILURE (Status))
955        {
956            return_ACPI_STATUS (Status);
957        }
958
959        /* Start new output datum by merging with previous input datum */
960
961        FieldOffset += ObjDesc->CommonField.AccessByteWidth;
962        MergedDatum = RawDatum >>
963            (ObjDesc->CommonField.AccessBitWidth -
964                ObjDesc->CommonField.StartFieldBitOffset);
965        Mask = ACPI_INTEGER_MAX;
966
967        if (i == DatumCount)
968        {
969            break;
970        }
971
972        /* Get the next input datum from the buffer */
973
974        BufferOffset += ObjDesc->CommonField.AccessByteWidth;
975        ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
976            ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
977                     BufferLength - BufferOffset));
978        MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
979    }
980
981    /* Mask off any extra bits in the last datum */
982
983    BufferTailBits = (ObjDesc->CommonField.BitLength +
984            ObjDesc->CommonField.StartFieldBitOffset) %
985                ObjDesc->CommonField.AccessBitWidth;
986    if (BufferTailBits)
987    {
988        Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
989    }
990
991    /* Write the last datum to the field */
992
993    MergedDatum &= Mask;
994    Status = AcpiExWriteWithUpdateRule (ObjDesc,
995                Mask, MergedDatum, FieldOffset);
996
997    return_ACPI_STATUS (Status);
998}
999
1000
1001