exfldio.c revision 80062
1/******************************************************************************
2 *
3 * Module Name: exfldio - Aml Field I/O
4 *              $Revision: 59 $
5 *
6 *****************************************************************************/
7
8/******************************************************************************
9 *
10 * 1. Copyright Notice
11 *
12 * Some or all of this work - Copyright (c) 1999, 2000, 2001, 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 "acnamesp.h"
124#include "achware.h"
125#include "acevents.h"
126#include "acdispat.h"
127
128
129#define _COMPONENT          ACPI_EXECUTER
130        MODULE_NAME         ("exfldio")
131
132
133/*******************************************************************************
134 *
135 * FUNCTION:    AcpiExSetupField
136 *
137 * PARAMETERS:  *ObjDesc            - Field to be read or written
138 *              FieldDatumByteOffset     - Current offset into the field
139 *
140 * RETURN:      Status
141 *
142 * DESCRIPTION: Common processing for AcpiExExtractFromField and
143 *              AcpiExInsertIntoField
144 *
145 ******************************************************************************/
146
147ACPI_STATUS
148AcpiExSetupField (
149    ACPI_OPERAND_OBJECT     *ObjDesc,
150    UINT32                  FieldDatumByteOffset)
151{
152    ACPI_STATUS             Status = AE_OK;
153    ACPI_OPERAND_OBJECT     *RgnDesc;
154
155
156    FUNCTION_TRACE_U32 ("ExSetupField", FieldDatumByteOffset);
157
158
159    /* Parameter validation */
160
161    RgnDesc = ObjDesc->CommonField.RegionObj;
162    if (!ObjDesc || !RgnDesc)
163    {
164        DEBUG_PRINTP (ACPI_ERROR, ("Internal error - null handle\n"));
165        return_ACPI_STATUS (AE_AML_NO_OPERAND);
166    }
167
168    if (ACPI_TYPE_REGION != RgnDesc->Common.Type)
169    {
170        DEBUG_PRINTP (ACPI_ERROR, ("Needed Region, found type %x %s\n",
171            RgnDesc->Common.Type, AcpiUtGetTypeName (RgnDesc->Common.Type)));
172        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
173    }
174
175
176    /*
177     * If the Region Address and Length have not been previously evaluated,
178     * evaluate them now and save the results.
179     */
180    if (!(RgnDesc->Region.Flags & AOPOBJ_DATA_VALID))
181    {
182
183        Status = AcpiDsGetRegionArguments (RgnDesc);
184        if (ACPI_FAILURE (Status))
185        {
186            return_ACPI_STATUS (Status);
187        }
188    }
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            DEBUG_PRINTP (ACPI_ERROR,
208                ("Field access width (%d bytes) too large for region size (%X)\n",
209                ObjDesc->CommonField.AccessByteWidth, RgnDesc->Region.Length));
210        }
211
212        /*
213         * Offset rounded up to next multiple of field width
214         * exceeds region length, indicate an error
215         */
216        DEBUG_PRINTP (ACPI_ERROR,
217            ("Field base+offset+width %X+%X+%X exceeds region size (%X bytes) field=%p region=%p\n",
218            ObjDesc->CommonField.BaseByteOffset, FieldDatumByteOffset,
219            ObjDesc->CommonField.AccessByteWidth,
220            RgnDesc->Region.Length, ObjDesc, RgnDesc));
221
222        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
223    }
224
225    return_ACPI_STATUS (AE_OK);
226}
227
228
229/*******************************************************************************
230 *
231 * FUNCTION:    AcpiExReadFieldDatum
232 *
233 * PARAMETERS:  *ObjDesc            - Field to be read
234 *              *Value              - Where to store value (must be 32 bits)
235 *
236 * RETURN:      Status
237 *
238 * DESCRIPTION: Retrieve the value of the given field
239 *
240 ******************************************************************************/
241
242ACPI_STATUS
243AcpiExReadFieldDatum (
244    ACPI_OPERAND_OBJECT     *ObjDesc,
245    UINT32                  FieldDatumByteOffset,
246    UINT32                  *Value)
247{
248    ACPI_STATUS             Status;
249    ACPI_OPERAND_OBJECT     *RgnDesc;
250    ACPI_PHYSICAL_ADDRESS   Address;
251    UINT32                  LocalValue;
252
253
254    FUNCTION_TRACE_U32 ("ExReadFieldDatum", FieldDatumByteOffset);
255
256
257    if (!Value)
258    {
259        LocalValue = 0;
260        Value = &LocalValue;    /*  support reads without saving value  */
261    }
262
263    /* Clear the entire return buffer first, [Very Important!] */
264
265    *Value = 0;
266
267
268    /*
269     * BufferFields - Read from a Buffer
270     * Other Fields - Read from a Operation Region.
271     */
272    switch (ObjDesc->Common.Type)
273    {
274    case ACPI_TYPE_BUFFER_FIELD:
275
276        /*
277         * For BufferFields, we only need to copy the data from the
278         * source buffer.  Length is the field width in bytes.
279         */
280        MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
281                        + ObjDesc->BufferField.BaseByteOffset + FieldDatumByteOffset,
282                        ObjDesc->CommonField.AccessByteWidth);
283        Status = AE_OK;
284        break;
285
286
287    case INTERNAL_TYPE_REGION_FIELD:
288    case INTERNAL_TYPE_BANK_FIELD:
289
290        /*
291         * For other fields, we need to go through an Operation Region
292         * (Only types that will get here are RegionFields and BankFields)
293         */
294        Status = AcpiExSetupField (ObjDesc, FieldDatumByteOffset);
295        if (ACPI_FAILURE (Status))
296        {
297            return_ACPI_STATUS (Status);
298        }
299
300
301        /*
302         * The physical address of this field datum is:
303         *
304         * 1) The base of the region, plus
305         * 2) The base offset of the field, plus
306         * 3) The current offset into the field
307         */
308        RgnDesc = ObjDesc->CommonField.RegionObj;
309        Address = RgnDesc->Region.Address + ObjDesc->CommonField.BaseByteOffset +
310                    FieldDatumByteOffset;
311
312        DEBUG_PRINTP (TRACE_BFIELD, ("Region %s(%X) width %X base:off %X:%X at %8.8lX%8.8lX\n",
313            AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
314            RgnDesc->Region.SpaceId, ObjDesc->CommonField.AccessBitWidth,
315            ObjDesc->CommonField.BaseByteOffset, FieldDatumByteOffset,
316            HIDWORD(Address), LODWORD(Address)));
317
318
319        /* Invoke the appropriate AddressSpace/OpRegion handler */
320
321        Status = AcpiEvAddressSpaceDispatch (RgnDesc, ACPI_READ_ADR_SPACE,
322                        Address, ObjDesc->CommonField.AccessBitWidth, Value);
323        if (Status == AE_NOT_IMPLEMENTED)
324        {
325            DEBUG_PRINTP (ACPI_ERROR, ("Region %s(%X) not implemented\n",
326                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
327                RgnDesc->Region.SpaceId));
328        }
329
330        else if (Status == AE_NOT_EXIST)
331        {
332            DEBUG_PRINTP (ACPI_ERROR, ("Region %s(%X) has no handler\n",
333                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
334                RgnDesc->Region.SpaceId));
335        }
336        break;
337
338
339    default:
340
341        DEBUG_PRINTP (ACPI_ERROR, ("%p, wrong source type - %s\n",
342            ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type)));
343        Status = AE_AML_INTERNAL;
344        break;
345    }
346
347
348    DEBUG_PRINTP (TRACE_BFIELD, ("Returned value=%08lX \n", *Value));
349
350    return_ACPI_STATUS (Status);
351}
352
353
354/*******************************************************************************
355 *
356 * FUNCTION:    AcpiExGetBufferDatum
357 *
358 * PARAMETERS:  MergedDatum         - Value to store
359 *              Buffer              - Receiving buffer
360 *              ByteGranularity     - 1/2/4 Granularity of the field
361 *                                    (aka Datum Size)
362 *              Offset              - Datum offset into the buffer
363 *
364 * RETURN:      none
365 *
366 * DESCRIPTION: Store the merged datum to the buffer according to the
367 *              byte granularity
368 *
369 ******************************************************************************/
370
371static void
372AcpiExGetBufferDatum(
373    UINT32                  *Datum,
374    void                    *Buffer,
375    UINT32                  ByteGranularity,
376    UINT32                  Offset)
377{
378
379    switch (ByteGranularity)
380    {
381    case ACPI_FIELD_BYTE_GRANULARITY:
382        *Datum = ((UINT8 *) Buffer) [Offset];
383        break;
384
385    case ACPI_FIELD_WORD_GRANULARITY:
386        MOVE_UNALIGNED16_TO_32 (Datum, &(((UINT16 *) Buffer) [Offset]));
387        break;
388
389    case ACPI_FIELD_DWORD_GRANULARITY:
390        MOVE_UNALIGNED32_TO_32 (Datum, &(((UINT32 *) Buffer) [Offset]));
391        break;
392    }
393}
394
395
396/*******************************************************************************
397 *
398 * FUNCTION:    AcpiExSetBufferDatum
399 *
400 * PARAMETERS:  MergedDatum         - Value to store
401 *              Buffer              - Receiving buffer
402 *              ByteGranularity     - 1/2/4 Granularity of the field
403 *                                    (aka Datum Size)
404 *              Offset              - Datum offset into the buffer
405 *
406 * RETURN:      none
407 *
408 * DESCRIPTION: Store the merged datum to the buffer according to the
409 *              byte granularity
410 *
411 ******************************************************************************/
412
413static void
414AcpiExSetBufferDatum (
415    UINT32                  MergedDatum,
416    void                    *Buffer,
417    UINT32                  ByteGranularity,
418    UINT32                  Offset)
419{
420
421    switch (ByteGranularity)
422    {
423    case ACPI_FIELD_BYTE_GRANULARITY:
424        ((UINT8 *) Buffer) [Offset] = (UINT8) MergedDatum;
425        break;
426
427    case ACPI_FIELD_WORD_GRANULARITY:
428        MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[Offset]), &MergedDatum);
429        break;
430
431    case ACPI_FIELD_DWORD_GRANULARITY:
432        MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[Offset]), &MergedDatum);
433        break;
434    }
435}
436
437
438/*******************************************************************************
439 *
440 * FUNCTION:    AcpiExExtractFromField
441 *
442 * PARAMETERS:  *ObjDesc            - Field to be read
443 *              *Value              - Where to store value
444 *
445 * RETURN:      Status
446 *
447 * DESCRIPTION: Retrieve the value of the given field
448 *
449 ******************************************************************************/
450
451ACPI_STATUS
452AcpiExExtractFromField (
453    ACPI_OPERAND_OBJECT     *ObjDesc,
454    void                    *Buffer,
455    UINT32                  BufferLength)
456{
457    ACPI_STATUS             Status;
458    UINT32                  FieldDatumByteOffset;
459    UINT32                  DatumOffset;
460    UINT32                  PreviousRawDatum;
461    UINT32                  ThisRawDatum = 0;
462    UINT32                  MergedDatum = 0;
463    UINT32                  ByteFieldLength;
464    UINT32                  DatumCount;
465
466
467    FUNCTION_TRACE ("ExExtractFromField");
468
469
470    /*
471     * The field must fit within the caller's buffer
472     */
473    ByteFieldLength = ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
474    if (ByteFieldLength > BufferLength)
475    {
476        DEBUG_PRINTP (ACPI_INFO, ("Field size %X (bytes) too large for buffer (%X)\n",
477            ByteFieldLength, BufferLength));
478
479        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
480    }
481
482    /* Convert field byte count to datum count, round up if necessary */
483
484    DatumCount = ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
485
486    DEBUG_PRINT (ACPI_INFO,
487        ("ByteLen=%x, DatumLen=%x, BitGran=%x, ByteGran=%x\n",
488        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessBitWidth,
489        ObjDesc->CommonField.AccessByteWidth));
490
491
492    /*
493     * Clear the caller's buffer (the whole buffer length as given)
494     * This is very important, especially in the cases where a byte is read,
495     * but the buffer is really a UINT32 (4 bytes).
496     */
497    MEMSET (Buffer, 0, BufferLength);
498
499    /* Read the first raw datum to prime the loop */
500
501    FieldDatumByteOffset = 0;
502    DatumOffset= 0;
503
504    Status = AcpiExReadFieldDatum (ObjDesc, FieldDatumByteOffset, &PreviousRawDatum);
505    if (ACPI_FAILURE (Status))
506    {
507        return_ACPI_STATUS (Status);
508    }
509
510
511    /* We might actually be done if the request fits in one datum */
512
513    if ((DatumCount == 1) &&
514        (ObjDesc->CommonField.AccessFlags & AFIELD_SINGLE_DATUM))
515    {
516        /* 1) Shift the valid data bits down to start at bit 0 */
517
518        MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
519
520        /* 2) Mask off any upper unused bits (bits not part of the field) */
521
522        if (ObjDesc->CommonField.EndBufferValidBits)
523        {
524            MergedDatum &= MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
525        }
526
527        /* Store the datum to the caller buffer */
528
529        AcpiExSetBufferDatum (MergedDatum, Buffer, ObjDesc->CommonField.AccessByteWidth,
530                DatumOffset);
531
532        return_ACPI_STATUS (AE_OK);
533    }
534
535
536    /* We need to get more raw data to complete one or more field data */
537
538    while (DatumOffset < DatumCount)
539    {
540        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
541
542        /*
543         * If the field is aligned on a byte boundary, we don't want
544         * to perform a final read, since this would potentially read
545         * past the end of the region.
546         *
547         * TBD: [Investigate] It may make more sense to just split the aligned
548         * and non-aligned cases since the aligned case is so very simple,
549         */
550        if ((ObjDesc->CommonField.StartFieldBitOffset != 0)       ||
551            ((ObjDesc->CommonField.StartFieldBitOffset == 0)      &&
552            (DatumOffset < (DatumCount -1))))
553        {
554            /*
555             * Get the next raw datum, it contains some or all bits
556             * of the current field datum
557             */
558            Status = AcpiExReadFieldDatum (ObjDesc, FieldDatumByteOffset, &ThisRawDatum);
559            if (ACPI_FAILURE (Status))
560            {
561                return_ACPI_STATUS (Status);
562            }
563        }
564
565        /*
566         * Create the (possibly) merged datum to be stored to the caller buffer
567         */
568        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
569        {
570            /* Field is not skewed and we can just copy the datum */
571
572            MergedDatum = PreviousRawDatum;
573        }
574
575        else
576        {
577            /*
578             * Put together the appropriate bits of the two raw data to make a
579             * single complete field datum
580             *
581             * 1) Normalize the first datum down to bit 0
582             */
583            MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
584
585            /* 2) Insert the second datum "above" the first datum */
586
587            MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
588
589            if ((DatumOffset >= (DatumCount -1)))
590            {
591                /*
592                 * This is the last iteration of the loop.  We need to clear
593                 * any unused bits (bits that are not part of this field) that
594                 * came from the last raw datum before we store the final
595                 * merged datum into the caller buffer.
596                 */
597                if (ObjDesc->CommonField.EndBufferValidBits)
598                {
599                    MergedDatum &=
600                        MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
601                }
602            }
603        }
604
605
606        /*
607         * Store the merged field datum in the caller's buffer, according to
608         * the granularity of the field (size of each datum).
609         */
610        AcpiExSetBufferDatum (MergedDatum, Buffer, ObjDesc->CommonField.AccessByteWidth,
611                DatumOffset);
612
613        /*
614         * Save the raw datum that was just acquired since it may contain bits
615         * of the *next* field datum.  Update offsets
616         */
617        PreviousRawDatum = ThisRawDatum;
618        DatumOffset++;
619    }
620
621
622    return_ACPI_STATUS (AE_OK);
623}
624
625
626/*******************************************************************************
627 *
628 * FUNCTION:    AcpiExWriteFieldDatum
629 *
630 * PARAMETERS:  *ObjDesc            - Field to be set
631 *              Value               - Value to store
632 *
633 * RETURN:      Status
634 *
635 * DESCRIPTION: Store the value into the given field
636 *
637 ******************************************************************************/
638
639static ACPI_STATUS
640AcpiExWriteFieldDatum (
641    ACPI_OPERAND_OBJECT     *ObjDesc,
642    UINT32                  FieldDatumByteOffset,
643    UINT32                  Value)
644{
645    ACPI_STATUS             Status = AE_OK;
646    ACPI_OPERAND_OBJECT     *RgnDesc = NULL;
647    ACPI_PHYSICAL_ADDRESS   Address;
648
649
650    FUNCTION_TRACE_U32 ("ExWriteFieldDatum", FieldDatumByteOffset);
651
652
653
654    /*
655     * BufferFields - Read from a Buffer
656     * Other Fields - Read from a Operation Region.
657     */
658    switch (ObjDesc->Common.Type)
659    {
660    case ACPI_TYPE_BUFFER_FIELD:
661
662        /*
663         * For BufferFields, we only need to copy the data to the
664         * target buffer.  Length is the field width in bytes.
665         */
666        MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
667                + ObjDesc->BufferField.BaseByteOffset + FieldDatumByteOffset,
668                &Value, ObjDesc->CommonField.AccessByteWidth);
669        Status = AE_OK;
670        break;
671
672
673    case INTERNAL_TYPE_REGION_FIELD:
674    case INTERNAL_TYPE_BANK_FIELD:
675
676        /*
677         * For other fields, we need to go through an Operation Region
678         * (Only types that will get here are RegionFields and BankFields)
679         */
680        Status = AcpiExSetupField (ObjDesc, FieldDatumByteOffset);
681        if (ACPI_FAILURE (Status))
682        {
683            return_ACPI_STATUS (Status);
684        }
685
686        /*
687         * The physical address of this field datum is:
688         *
689         * 1) The base of the region, plus
690         * 2) The base offset of the field, plus
691         * 3) The current offset into the field
692         */
693        RgnDesc = ObjDesc->CommonField.RegionObj;
694        Address = RgnDesc->Region.Address +
695                    ObjDesc->CommonField.BaseByteOffset +
696                    FieldDatumByteOffset;
697
698        DEBUG_PRINTP (TRACE_BFIELD,
699            ("Store %X in Region %s(%X) at %8.8lX%8.8lX width %X\n",
700            Value, AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
701            RgnDesc->Region.SpaceId, HIDWORD(Address), LODWORD(Address),
702            ObjDesc->CommonField.AccessBitWidth));
703
704        /* Invoke the appropriate AddressSpace/OpRegion handler */
705
706        Status = AcpiEvAddressSpaceDispatch (RgnDesc, ACPI_WRITE_ADR_SPACE,
707                        Address, ObjDesc->CommonField.AccessBitWidth, &Value);
708
709        if (Status == AE_NOT_IMPLEMENTED)
710        {
711            DEBUG_PRINTP (ACPI_ERROR,
712                ("**** Region type %s(%X) not implemented\n",
713                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
714                RgnDesc->Region.SpaceId));
715        }
716
717        else if (Status == AE_NOT_EXIST)
718        {
719            DEBUG_PRINTP (ACPI_ERROR,
720                ("**** Region type %s(%X) does not have a handler\n",
721                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
722                RgnDesc->Region.SpaceId));
723        }
724
725        break;
726
727
728    default:
729
730        DEBUG_PRINTP (ACPI_ERROR, ("%p, wrong source type - %s\n",
731            ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type)));
732        Status = AE_AML_INTERNAL;
733        break;
734    }
735
736
737    DEBUG_PRINTP (TRACE_BFIELD, ("Value written=%08lX \n", Value));
738    return_ACPI_STATUS (Status);
739}
740
741
742/*******************************************************************************
743 *
744 * FUNCTION:    AcpiExWriteFieldDatumWithUpdateRule
745 *
746 * PARAMETERS:  *ObjDesc            - Field to be set
747 *              Value               - Value to store
748 *
749 * RETURN:      Status
750 *
751 * DESCRIPTION: Apply the field update rule to a field write
752 *
753 ******************************************************************************/
754
755static ACPI_STATUS
756AcpiExWriteFieldDatumWithUpdateRule (
757    ACPI_OPERAND_OBJECT     *ObjDesc,
758    UINT32                  Mask,
759    UINT32                  FieldValue,
760    UINT32                  FieldDatumByteOffset)
761{
762    ACPI_STATUS             Status = AE_OK;
763    UINT32                  MergedValue;
764    UINT32                  CurrentValue;
765
766
767    FUNCTION_TRACE ("ExWriteFieldDatumWithUpdateRule");
768
769
770    /* Start with the new bits  */
771
772    MergedValue = FieldValue;
773
774
775    /* If the mask is all ones, we don't need to worry about the update rule */
776
777    if (Mask != ACPI_UINT32_MAX)
778    {
779        /* Decode the update rule */
780
781        switch (ObjDesc->CommonField.UpdateRule)
782        {
783
784        case UPDATE_PRESERVE:
785
786            /*
787             * Check if update rule needs to be applied (not if mask is all
788             * ones)  The left shift drops the bits we want to ignore.
789             */
790            if ((~Mask << (sizeof (Mask) * 8 -
791                            ObjDesc->CommonField.AccessBitWidth)) != 0)
792            {
793                /*
794                 * Read the current contents of the byte/word/dword containing
795                 * the field, and merge with the new field value.
796                 */
797                Status = AcpiExReadFieldDatum (ObjDesc, FieldDatumByteOffset,
798                                &CurrentValue);
799                MergedValue |= (CurrentValue & ~Mask);
800            }
801            break;
802
803
804        case UPDATE_WRITE_AS_ONES:
805
806            /* Set positions outside the field to all ones */
807
808            MergedValue |= ~Mask;
809            break;
810
811
812        case UPDATE_WRITE_AS_ZEROS:
813
814            /* Set positions outside the field to all zeros */
815
816            MergedValue &= Mask;
817            break;
818
819
820        default:
821            DEBUG_PRINT (ACPI_ERROR,
822                ("WriteWithUpdateRule: Unknown UpdateRule setting: %x\n",
823                ObjDesc->CommonField.UpdateRule));
824            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
825            break;
826        }
827    }
828
829
830    /* Write the merged value */
831
832    Status = AcpiExWriteFieldDatum (ObjDesc, FieldDatumByteOffset,
833                    MergedValue);
834
835    DEBUG_PRINTP (TRACE_BFIELD, ("Mask %X DatumOffset %X Value %X, MergedValue %X\n",
836        Mask, FieldDatumByteOffset, FieldValue, MergedValue));
837
838    return_ACPI_STATUS (Status);
839}
840
841
842/*******************************************************************************
843 *
844 * FUNCTION:    AcpiExInsertIntoField
845 *
846 * PARAMETERS:  *ObjDesc            - Field to be set
847 *              Buffer              - Value to store
848 *
849 * RETURN:      Status
850 *
851 * DESCRIPTION: Store the value into the given field
852 *
853 ******************************************************************************/
854
855ACPI_STATUS
856AcpiExInsertIntoField (
857    ACPI_OPERAND_OBJECT     *ObjDesc,
858    void                    *Buffer,
859    UINT32                  BufferLength)
860{
861    ACPI_STATUS             Status;
862    UINT32                  FieldDatumByteOffset;
863    UINT32                  DatumOffset;
864    UINT32                  Mask;
865    UINT32                  MergedDatum;
866    UINT32                  PreviousRawDatum;
867    UINT32                  ThisRawDatum;
868    UINT32                  ByteFieldLength;
869    UINT32                  DatumCount;
870
871
872    FUNCTION_TRACE ("ExInsertIntoField");
873
874
875    /*
876     * Incoming buffer must be at least as long as the field, we do not
877     * allow "partial" field writes.  We do not care if the buffer is
878     * larger than the field, this typically happens when an integer is
879     * written to a field that is actually smaller than an integer.
880     */
881    ByteFieldLength = ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
882    if (BufferLength < ByteFieldLength)
883    {
884        DEBUG_PRINTP (ACPI_INFO, ("Buffer length %X too small for field %X\n",
885            BufferLength, ByteFieldLength));
886
887        /* TBD: Need a better error code */
888
889        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
890    }
891
892    /* Convert byte count to datum count, round up if necessary */
893
894    DatumCount = ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
895
896    DEBUG_PRINT (ACPI_INFO,
897        ("ByteLen=%x, DatumLen=%x, BitGran=%x, ByteGran=%x\n",
898        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessBitWidth,
899        ObjDesc->CommonField.AccessByteWidth));
900
901
902    /*
903     * Break the request into up to three parts (similar to an I/O request):
904     * 1) non-aligned part at start
905     * 2) aligned part in middle
906     * 3) non-aligned part at the end
907     */
908    FieldDatumByteOffset = 0;
909    DatumOffset= 0;
910
911    /* Get a single datum from the caller's buffer */
912
913    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer,
914            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
915
916    /*
917     * Part1:
918     * Write a partial field datum if field does not begin on a datum boundary
919     * Note: The code in this section also handles the aligned case
920     *
921     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
922     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
923     *
924     * Mask off bits that are "below" the field (if any)
925     */
926    Mask = MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
927
928    /* If the field fits in one datum, may need to mask upper bits */
929
930    if ((ObjDesc->CommonField.AccessFlags & AFIELD_SINGLE_DATUM) &&
931         ObjDesc->CommonField.EndFieldValidBits)
932    {
933        /* There are bits above the field, mask them off also */
934
935        Mask &= MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
936    }
937
938    /* Shift and mask the value into the field position */
939
940    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
941    MergedDatum &= Mask;
942
943    /* Apply the update rule (if necessary) and write the datum to the field */
944
945    Status = AcpiExWriteFieldDatumWithUpdateRule (ObjDesc, Mask, MergedDatum,
946                        FieldDatumByteOffset);
947    if (ACPI_FAILURE (Status))
948    {
949        return_ACPI_STATUS (Status);
950    }
951
952    /* If the entire field fits within one datum, we are done. */
953
954    if ((DatumCount == 1) &&
955       (ObjDesc->CommonField.AccessFlags & AFIELD_SINGLE_DATUM))
956    {
957        return_ACPI_STATUS (AE_OK);
958    }
959
960    /*
961     * Part2:
962     * Write the aligned data.
963     *
964     * We don't need to worry about the update rule for these data, because
965     * all of the bits in each datum are part of the field.
966     *
967     * The last datum must be special cased because it might contain bits
968     * that are not part of the field -- therefore the "update rule" must be
969     * applied in Part3 below.
970     */
971    while (DatumOffset < DatumCount)
972    {
973        DatumOffset++;
974        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
975
976        /*
977         * Get the next raw buffer datum.  It may contain bits of the previous
978         * field datum
979         */
980        AcpiExGetBufferDatum (&ThisRawDatum, Buffer,
981                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
982
983        /* Create the field datum based on the field alignment */
984
985        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
986        {
987            /*
988             * Put together appropriate bits of the two raw buffer data to make
989             * a single complete field datum
990             */
991            MergedDatum =
992                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
993                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
994        }
995
996        else
997        {
998            /* Field began aligned on datum boundary */
999
1000            MergedDatum = ThisRawDatum;
1001        }
1002
1003
1004        /*
1005         * Special handling for the last datum if the field does NOT end on
1006         * a datum boundary.  Update Rule must be applied to the bits outside
1007         * the field.
1008         */
1009        if ((DatumOffset == DatumCount)             &&
1010            ObjDesc->CommonField.EndFieldValidBits)
1011        {
1012            /*
1013             * Part3:
1014             * This is the last datum and the field does not end on a datum boundary.
1015             * Build the partial datum and write with the update rule.
1016             */
1017
1018            /* Mask off the unused bits above (after) the end-of-field */
1019
1020            Mask = MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1021            MergedDatum &= Mask;
1022
1023            /* Write the last datum with the update rule */
1024
1025            Status = AcpiExWriteFieldDatumWithUpdateRule (ObjDesc, Mask,
1026                            MergedDatum, FieldDatumByteOffset);
1027            if (ACPI_FAILURE (Status))
1028            {
1029                return_ACPI_STATUS (Status);
1030            }
1031        }
1032
1033        else
1034        {
1035            /* Normal case -- write the completed datum */
1036
1037            Status = AcpiExWriteFieldDatum (ObjDesc,
1038                            FieldDatumByteOffset, MergedDatum);
1039            if (ACPI_FAILURE (Status))
1040            {
1041                return_ACPI_STATUS (Status);
1042            }
1043        }
1044
1045        /*
1046         * Save the most recent datum since it may contain bits of the *next*
1047         * field datum.  Update current byte offset.
1048         */
1049        PreviousRawDatum = ThisRawDatum;
1050    }
1051
1052
1053    return_ACPI_STATUS (Status);
1054}
1055
1056
1057