exfldio.c revision 77424
1/******************************************************************************
2 *
3 * Module Name: exfldio - Aml Field I/O
4 *              $Revision: 57 $
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 ("ExSetupField");
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 %08lX\n",
313            AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
314            RgnDesc->Region.SpaceId, ObjDesc->CommonField.AccessBitWidth,
315            ObjDesc->CommonField.BaseByteOffset, FieldDatumByteOffset,
316            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 %p width %X\n",
700            Value, AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
701            RgnDesc->Region.SpaceId, Address, ObjDesc->CommonField.AccessBitWidth));
702
703        /* Invoke the appropriate AddressSpace/OpRegion handler */
704
705        Status = AcpiEvAddressSpaceDispatch (RgnDesc, ACPI_WRITE_ADR_SPACE,
706                        Address, ObjDesc->CommonField.AccessBitWidth, &Value);
707
708        if (Status == AE_NOT_IMPLEMENTED)
709        {
710            DEBUG_PRINTP (ACPI_ERROR,
711                ("**** Region type %s(%X) not implemented\n",
712                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
713                RgnDesc->Region.SpaceId));
714        }
715
716        else if (Status == AE_NOT_EXIST)
717        {
718            DEBUG_PRINTP (ACPI_ERROR,
719                ("**** Region type %s(%X) does not have a handler\n",
720                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
721                RgnDesc->Region.SpaceId));
722        }
723
724        break;
725
726
727    default:
728
729        DEBUG_PRINTP (ACPI_ERROR, ("%p, wrong source type - %s\n",
730            ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type)));
731        Status = AE_AML_INTERNAL;
732        break;
733    }
734
735
736    DEBUG_PRINTP (TRACE_BFIELD, ("Value written=%08lX \n", Value));
737    return_ACPI_STATUS (Status);
738}
739
740
741/*******************************************************************************
742 *
743 * FUNCTION:    AcpiExWriteFieldDatumWithUpdateRule
744 *
745 * PARAMETERS:  *ObjDesc            - Field to be set
746 *              Value               - Value to store
747 *
748 * RETURN:      Status
749 *
750 * DESCRIPTION: Apply the field update rule to a field write
751 *
752 ******************************************************************************/
753
754static ACPI_STATUS
755AcpiExWriteFieldDatumWithUpdateRule (
756    ACPI_OPERAND_OBJECT     *ObjDesc,
757    UINT32                  Mask,
758    UINT32                  FieldValue,
759    UINT32                  FieldDatumByteOffset)
760{
761    ACPI_STATUS             Status = AE_OK;
762    UINT32                  MergedValue;
763    UINT32                  CurrentValue;
764
765
766    FUNCTION_TRACE ("ExWriteFieldDatumWithUpdateRule");
767
768
769    /* Start with the new bits  */
770
771    MergedValue = FieldValue;
772
773
774    /* If the mask is all ones, we don't need to worry about the update rule */
775
776    if (Mask != ACPI_UINT32_MAX)
777    {
778        /* Decode the update rule */
779
780        switch (ObjDesc->CommonField.UpdateRule)
781        {
782
783        case UPDATE_PRESERVE:
784
785            /*
786             * Check if update rule needs to be applied (not if mask is all
787             * ones)  The left shift drops the bits we want to ignore.
788             */
789            if ((~Mask << (sizeof (Mask) * 8 -
790                            ObjDesc->CommonField.AccessBitWidth)) != 0)
791            {
792                /*
793                 * Read the current contents of the byte/word/dword containing
794                 * the field, and merge with the new field value.
795                 */
796                Status = AcpiExReadFieldDatum (ObjDesc, FieldDatumByteOffset,
797                                &CurrentValue);
798                MergedValue |= (CurrentValue & ~Mask);
799            }
800            break;
801
802
803        case UPDATE_WRITE_AS_ONES:
804
805            /* Set positions outside the field to all ones */
806
807            MergedValue |= ~Mask;
808            break;
809
810
811        case UPDATE_WRITE_AS_ZEROS:
812
813            /* Set positions outside the field to all zeros */
814
815            MergedValue &= Mask;
816            break;
817
818
819        default:
820            DEBUG_PRINT (ACPI_ERROR,
821                ("WriteWithUpdateRule: Unknown UpdateRule setting: %x\n",
822                ObjDesc->CommonField.UpdateRule));
823            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
824            break;
825        }
826    }
827
828
829    /* Write the merged value */
830
831    Status = AcpiExWriteFieldDatum (ObjDesc, FieldDatumByteOffset,
832                    MergedValue);
833
834    DEBUG_PRINTP (TRACE_BFIELD, ("Mask %X DatumOffset %X Value %X, MergedValue %X\n",
835        Mask, FieldDatumByteOffset, FieldValue, MergedValue));
836
837    return_ACPI_STATUS (Status);
838}
839
840
841/*******************************************************************************
842 *
843 * FUNCTION:    AcpiExInsertIntoField
844 *
845 * PARAMETERS:  *ObjDesc            - Field to be set
846 *              Buffer              - Value to store
847 *
848 * RETURN:      Status
849 *
850 * DESCRIPTION: Store the value into the given field
851 *
852 ******************************************************************************/
853
854ACPI_STATUS
855AcpiExInsertIntoField (
856    ACPI_OPERAND_OBJECT     *ObjDesc,
857    void                    *Buffer,
858    UINT32                  BufferLength)
859{
860    ACPI_STATUS             Status;
861    UINT32                  FieldDatumByteOffset;
862    UINT32                  DatumOffset;
863    UINT32                  Mask;
864    UINT32                  MergedDatum;
865    UINT32                  PreviousRawDatum;
866    UINT32                  ThisRawDatum;
867    UINT32                  ByteFieldLength;
868    UINT32                  DatumCount;
869
870
871    FUNCTION_TRACE ("ExInsertIntoField");
872
873
874    /*
875     * Incoming buffer must be at least as long as the field, we do not
876     * allow "partial" field writes.  We do not care if the buffer is
877     * larger than the field, this typically happens when an integer is
878     * written to a field that is actually smaller than an integer.
879     */
880    ByteFieldLength = ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
881    if (BufferLength < ByteFieldLength)
882    {
883        DEBUG_PRINTP (ACPI_INFO, ("Buffer length %X too small for field %X\n",
884            BufferLength, ByteFieldLength));
885
886        /* TBD: Need a better error code */
887
888        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
889    }
890
891    /* Convert byte count to datum count, round up if necessary */
892
893    DatumCount = ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
894
895    DEBUG_PRINT (ACPI_INFO,
896        ("ByteLen=%x, DatumLen=%x, BitGran=%x, ByteGran=%x\n",
897        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessBitWidth,
898        ObjDesc->CommonField.AccessByteWidth));
899
900
901    /*
902     * Break the request into up to three parts (similar to an I/O request):
903     * 1) non-aligned part at start
904     * 2) aligned part in middle
905     * 3) non-aligned part at the end
906     */
907    FieldDatumByteOffset = 0;
908    DatumOffset= 0;
909
910    /* Get a single datum from the caller's buffer */
911
912    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer,
913            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
914
915    /*
916     * Part1:
917     * Write a partial field datum if field does not begin on a datum boundary
918     * Note: The code in this section also handles the aligned case
919     *
920     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
921     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
922     *
923     * Mask off bits that are "below" the field (if any)
924     */
925    Mask = MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
926
927    /* If the field fits in one datum, may need to mask upper bits */
928
929    if ((ObjDesc->CommonField.AccessFlags & AFIELD_SINGLE_DATUM) &&
930         ObjDesc->CommonField.EndFieldValidBits)
931    {
932        /* There are bits above the field, mask them off also */
933
934        Mask &= MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
935    }
936
937    /* Shift and mask the value into the field position */
938
939    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
940    MergedDatum &= Mask;
941
942    /* Apply the update rule (if necessary) and write the datum to the field */
943
944    Status = AcpiExWriteFieldDatumWithUpdateRule (ObjDesc, Mask, MergedDatum,
945                        FieldDatumByteOffset);
946    if (ACPI_FAILURE (Status))
947    {
948        return_ACPI_STATUS (Status);
949    }
950
951    /* If the entire field fits within one datum, we are done. */
952
953    if ((DatumCount == 1) &&
954       (ObjDesc->CommonField.AccessFlags & AFIELD_SINGLE_DATUM))
955    {
956        return_ACPI_STATUS (AE_OK);
957    }
958
959    /*
960     * Part2:
961     * Write the aligned data.
962     *
963     * We don't need to worry about the update rule for these data, because
964     * all of the bits in each datum are part of the field.
965     *
966     * The last datum must be special cased because it might contain bits
967     * that are not part of the field -- therefore the "update rule" must be
968     * applied in Part3 below.
969     */
970    while (DatumOffset < DatumCount)
971    {
972        DatumOffset++;
973        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
974
975        /*
976         * Get the next raw buffer datum.  It may contain bits of the previous
977         * field datum
978         */
979        AcpiExGetBufferDatum (&ThisRawDatum, Buffer,
980                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
981
982        /* Create the field datum based on the field alignment */
983
984        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
985        {
986            /*
987             * Put together appropriate bits of the two raw buffer data to make
988             * a single complete field datum
989             */
990            MergedDatum =
991                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
992                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
993        }
994
995        else
996        {
997            /* Field began aligned on datum boundary */
998
999            MergedDatum = ThisRawDatum;
1000        }
1001
1002
1003        /*
1004         * Special handling for the last datum if the field does NOT end on
1005         * a datum boundary.  Update Rule must be applied to the bits outside
1006         * the field.
1007         */
1008        if ((DatumOffset == DatumCount)             &&
1009            ObjDesc->CommonField.EndFieldValidBits)
1010        {
1011            /*
1012             * Part3:
1013             * This is the last datum and the field does not end on a datum boundary.
1014             * Build the partial datum and write with the update rule.
1015             */
1016
1017            /* Mask off the unused bits above (after) the end-of-field */
1018
1019            Mask = MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1020            MergedDatum &= Mask;
1021
1022            /* Write the last datum with the update rule */
1023
1024            Status = AcpiExWriteFieldDatumWithUpdateRule (ObjDesc, Mask,
1025                            MergedDatum, FieldDatumByteOffset);
1026            if (ACPI_FAILURE (Status))
1027            {
1028                return_ACPI_STATUS (Status);
1029            }
1030        }
1031
1032        else
1033        {
1034            /* Normal case -- write the completed datum */
1035
1036            Status = AcpiExWriteFieldDatum (ObjDesc,
1037                            FieldDatumByteOffset, MergedDatum);
1038            if (ACPI_FAILURE (Status))
1039            {
1040                return_ACPI_STATUS (Status);
1041            }
1042        }
1043
1044        /*
1045         * Save the most recent datum since it may contain bits of the *next*
1046         * field datum.  Update current byte offset.
1047         */
1048        PreviousRawDatum = ThisRawDatum;
1049    }
1050
1051
1052    return_ACPI_STATUS (Status);
1053}
1054
1055
1056