exfldio.c revision 67754
1219069Sdim/******************************************************************************
2219069Sdim *
3219069Sdim * Module Name: amfldio - Aml Field I/O
4219069Sdim *              $Revision: 28 $
5219069Sdim *
6219069Sdim *****************************************************************************/
7219069Sdim
8219069Sdim/******************************************************************************
9219069Sdim *
10219069Sdim * 1. Copyright Notice
11219069Sdim *
12219069Sdim * Some or all of this work - Copyright (c) 1999, Intel Corp.  All rights
13219069Sdim * reserved.
14219069Sdim *
15219069Sdim * 2. License
16249423Sdim *
17249423Sdim * 2.1. This is your license from Intel Corp. under its intellectual property
18249423Sdim * rights.  You may have additional license terms from the party that provided
19221345Sdim * you this software, covering your right to use that party's intellectual
20219069Sdim * property rights.
21219069Sdim *
22226633Sdim * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
23219069Sdim * copy of the source code appearing in this file ("Covered Code") an
24249423Sdim * irrevocable, perpetual, worldwide license under Intel's copyrights in the
25219069Sdim * base code distributed originally by Intel ("Original Intel Code") to copy,
26219069Sdim * make derivatives, distribute, use and display any portion of the Covered
27219069Sdim * Code in any form, with the right to sublicense such rights; and
28219069Sdim *
29221345Sdim * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
30249423Sdim * license (with the right to sublicense), under only those claims of Intel
31234353Sdim * patents that are infringed by the Original Intel Code, to make, use, sell,
32234353Sdim * offer to sell, and import the Covered Code and derivative works thereof
33219069Sdim * solely to the minimum extent necessary to exercise the above copyright
34219069Sdim * license, and in no event shall the patent license extend to any additions
35219069Sdim * to or modifications of the Original Intel Code.  No other license or right
36249423Sdim * is granted directly or by implication, estoppel or otherwise;
37219069Sdim *
38219069Sdim * The above copyright and patent license is granted only if the following
39219069Sdim * conditions are met:
40249423Sdim *
41249423Sdim * 3. Conditions
42219069Sdim *
43219069Sdim * 3.1. Redistribution of Source with Rights to Further Distribute Source.
44219069Sdim * Redistribution of source code of any substantial portion of the Covered
45249423Sdim * Code or modification with rights to further distribute source must include
46249423Sdim * the above Copyright Notice, the above License, this list of Conditions,
47219069Sdim * and the following Disclaimer and Export Compliance provision.  In addition,
48219069Sdim * Licensee must cause all Covered Code to which Licensee contributes to
49249423Sdim * contain a file documenting the changes Licensee made to create that Covered
50219069Sdim * Code and the date of any change.  Licensee must include in that file the
51219069Sdim * documentation of any changes made by any predecessor Licensee.  Licensee
52219069Sdim * must include a prominent statement that the modification is derived,
53219069Sdim * directly or indirectly, from Original Intel Code.
54219069Sdim *
55226633Sdim * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
56219069Sdim * Redistribution of source code of any substantial portion of the Covered
57219069Sdim * Code or modification without rights to further distribute source must
58226633Sdim * include the following Disclaimer and Export Compliance provision in the
59219069Sdim * documentation and/or other materials provided with distribution.  In
60219069Sdim * addition, Licensee may not authorize further sublicense of source of any
61219069Sdim * portion of the Covered Code, and must include terms to the effect that the
62219069Sdim * license from Licensee to its licensee is limited to the intellectual
63226633Sdim * property embodied in the software Licensee provides to its licensee, and
64219069Sdim * not to intellectual property embodied in modifications its licensee may
65219069Sdim * make.
66219069Sdim *
67226633Sdim * 3.3. Redistribution of Executable. Redistribution in executable form of any
68219069Sdim * substantial portion of the Covered Code or modification must reproduce the
69219069Sdim * above Copyright Notice, and the following Disclaimer and Export Compliance
70219069Sdim * provision in the documentation and/or other materials provided with the
71219069Sdim * distribution.
72219069Sdim *
73219069Sdim * 3.4. Intel retains all right, title, and interest in and to the Original
74226633Sdim * Intel Code.
75219069Sdim *
76219069Sdim * 3.5. Neither the name Intel nor any other trademark owned or controlled by
77219069Sdim * Intel shall be used in advertising or otherwise to promote the sale, use or
78219069Sdim * other dealings in products derived from or relating to the Covered Code
79219069Sdim * without prior written authorization from Intel.
80219069Sdim *
81226633Sdim * 4. Disclaimer and Export Compliance
82249423Sdim *
83249423Sdim * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
84249423Sdim * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
85249423Sdim * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
86226633Sdim * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
87226633Sdim * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
88219069Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
89226633Sdim * PARTICULAR PURPOSE.
90219069Sdim *
91219069Sdim * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
92219069Sdim * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
93219069Sdim * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
94219069Sdim * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
95219069Sdim * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
96219069Sdim * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
97219069Sdim * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
98219069Sdim * LIMITED REMEDY.
99219069Sdim *
100219069Sdim * 4.3. Licensee shall not export, either directly or indirectly, any of this
101219069Sdim * software or system incorporating such software without first obtaining any
102219069Sdim * required license or other approval from the U. S. Department of Commerce or
103219069Sdim * any other agency or department of the United States Government.  In the
104219069Sdim * event Licensee exports any such software from the United States or
105219069Sdim * re-exports any such software from a foreign destination, Licensee shall
106219069Sdim * ensure that the distribution and export/re-export of the software is in
107234353Sdim * compliance with all laws, regulations, orders, or other restrictions of the
108219069Sdim * U.S. Export Administration Regulations. Licensee agrees that neither it nor
109249423Sdim * any of its subsidiaries will export/re-export any technical data, process,
110219069Sdim * software, or service, directly or indirectly, to any country for which the
111226633Sdim * United States government or any agency thereof requires an export license,
112219069Sdim * other governmental approval, or letter of assurance, without first obtaining
113219069Sdim * such license, approval or letter.
114219069Sdim *
115219069Sdim *****************************************************************************/
116243830Sdim
117219069Sdim
118219069Sdim#define __AMFLDIO_C__
119219069Sdim
120234353Sdim#include "acpi.h"
121219069Sdim#include "acinterp.h"
122219069Sdim#include "amlcode.h"
123219069Sdim#include "acnamesp.h"
124219069Sdim#include "achware.h"
125243830Sdim#include "acevents.h"
126243830Sdim
127243830Sdim
128243830Sdim#define _COMPONENT          INTERPRETER
129219069Sdim        MODULE_NAME         ("amfldio")
130219069Sdim
131234353Sdim
132234353Sdim/*******************************************************************************
133219069Sdim *
134234353Sdim * FUNCTION:    AcpiAmlReadFieldData
135234353Sdim *
136234353Sdim * PARAMETERS:  *ObjDesc            - Field to be read
137234353Sdim *              *Value              - Where to store value
138234353Sdim *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
139224145Sdim *
140234353Sdim * RETURN:      Status
141243830Sdim *
142243830Sdim * DESCRIPTION: Retrieve the value of the given field
143243830Sdim *
144219069Sdim ******************************************************************************/
145234353Sdim
146234353SdimACPI_STATUS
147234353SdimAcpiAmlReadFieldData (
148234353Sdim    ACPI_OPERAND_OBJECT     *ObjDesc,
149234353Sdim    UINT32                  FieldByteOffset,
150234353Sdim    UINT32                  FieldBitWidth,
151243830Sdim    UINT32                  *Value)
152243830Sdim{
153243830Sdim    ACPI_STATUS             Status;
154243830Sdim    ACPI_OPERAND_OBJECT     *RgnDesc = NULL;
155243830Sdim    ACPI_INTEGER            Address;
156243830Sdim    UINT32                  LocalValue = 0;
157243830Sdim    UINT32                  FieldByteWidth;
158243830Sdim
159234353Sdim
160219069Sdim    FUNCTION_TRACE ("AmlReadFieldData");
161219069Sdim
162249423Sdim
163234353Sdim    /* ObjDesc is validated by callers */
164219069Sdim
165219069Sdim    if (ObjDesc)
166219069Sdim    {
167219069Sdim        RgnDesc = ObjDesc->Field.Container;
168219069Sdim    }
169234353Sdim
170219069Sdim
171219069Sdim    FieldByteWidth = DIV_8 (FieldBitWidth);
172226633Sdim    Status = AcpiAmlSetupField (ObjDesc, RgnDesc, FieldBitWidth);
173219069Sdim    if (ACPI_FAILURE (Status))
174234353Sdim    {
175234353Sdim        return_ACPI_STATUS (Status);
176234353Sdim    }
177234353Sdim
178219069Sdim    /* SetupField validated RgnDesc and FieldBitWidth  */
179219069Sdim
180219069Sdim    if (!Value)
181219069Sdim    {
182219069Sdim        Value = &LocalValue;    /*  support reads without saving value  */
183219069Sdim    }
184219069Sdim
185219069Sdim
186219069Sdim    /*
187219069Sdim     * Set offset to next multiple of field width,
188224145Sdim     *  add region base address and offset within the field
189224145Sdim     */
190224145Sdim    Address = RgnDesc->Region.Address +
191234353Sdim              (ObjDesc->Field.Offset * FieldByteWidth) +
192224145Sdim              FieldByteOffset;
193224145Sdim
194224145Sdim
195219069Sdim    if (RgnDesc->Region.SpaceId >= NUM_REGION_TYPES)
196219069Sdim    {
197219069Sdim        DEBUG_PRINT (TRACE_OPREGION,
198219069Sdim            ("AmlReadFieldData: **** Unknown OpRegion SpaceID %d at %08lx width %d\n",
199219069Sdim            RgnDesc->Region.SpaceId, Address, FieldBitWidth));
200219069Sdim    }
201219069Sdim
202219069Sdim    else
203219069Sdim    {
204219069Sdim        DEBUG_PRINT (TRACE_OPREGION,
205219069Sdim            ("AmlReadFieldData: OpRegion %s at %08lx width %d\n",
206219069Sdim            AcpiGbl_RegionTypes[RgnDesc->Region.SpaceId], Address,
207234353Sdim            FieldBitWidth));
208219069Sdim    }
209219069Sdim
210219069Sdim
211219069Sdim    /* Invoke the appropriate AddressSpace/OpRegion handler */
212219069Sdim
213219069Sdim    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ADDRESS_SPACE_READ,
214234353Sdim                                        Address, FieldBitWidth, Value);
215219069Sdim
216219069Sdim    if (Status == AE_NOT_IMPLEMENTED)
217219069Sdim    {
218219069Sdim        DEBUG_PRINT (ACPI_ERROR,
219219069Sdim            ("AmlReadFieldData: **** OpRegion type %s not implemented\n",
220219069Sdim            AcpiGbl_RegionTypes[RgnDesc->Region.SpaceId]));
221219069Sdim    }
222219069Sdim
223219069Sdim    else if (Status == AE_NOT_EXIST)
224219069Sdim    {
225219069Sdim        DEBUG_PRINT (ACPI_ERROR,
226219069Sdim            ("AmlReadFieldData: **** Unknown OpRegion SpaceID %d\n",
227234353Sdim            RgnDesc->Region.SpaceId));
228219069Sdim    }
229249423Sdim
230219069Sdim    DEBUG_PRINT (TRACE_OPREGION,
231219069Sdim        ("AmlReadField: Returned value=%08lx \n", *Value));
232226633Sdim
233219069Sdim    return_ACPI_STATUS (Status);
234226633Sdim}
235219069Sdim
236219069Sdim
237219069Sdim/*******************************************************************************
238243830Sdim *
239219069Sdim * FUNCTION:    AcpiAmlReadField
240219069Sdim *
241219069Sdim * PARAMETERS:  *ObjDesc            - Field to be read
242219069Sdim *              *Value              - Where to store value
243219069Sdim *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
244219069Sdim *
245 * RETURN:      Status
246 *
247 * DESCRIPTION: Retrieve the value of the given field
248 *
249 ******************************************************************************/
250
251ACPI_STATUS
252AcpiAmlReadField (
253    ACPI_OPERAND_OBJECT     *ObjDesc,
254    void                    *Buffer,
255    UINT32                  BufferLength,
256    UINT32                  ByteLength,
257    UINT32                  DatumLength,
258    UINT32                  BitGranularity,
259    UINT32                  ByteGranularity)
260{
261    ACPI_STATUS             Status;
262    UINT32                  ThisFieldByteOffset;
263    UINT32                  ThisFieldDatumOffset;
264    UINT32                  PreviousRawDatum;
265    UINT32                  ThisRawDatum;
266    UINT32                  ValidFieldBits;
267    UINT32                  Mask;
268    UINT32                  MergedDatum = 0;
269
270
271    FUNCTION_TRACE ("AmlReadField");
272
273    /*
274     * Clear the caller's buffer (the whole buffer length as given)
275     * This is very important, especially in the cases where a byte is read,
276     * but the buffer is really a UINT32 (4 bytes).
277     */
278
279    MEMSET (Buffer, 0, BufferLength);
280
281    /* Read the first raw datum to prime the loop */
282
283    ThisFieldByteOffset = 0;
284    ThisFieldDatumOffset= 0;
285
286    Status = AcpiAmlReadFieldData (ObjDesc, ThisFieldByteOffset, BitGranularity,
287                                    &PreviousRawDatum);
288    if (ACPI_FAILURE (Status))
289    {
290        goto Cleanup;
291    }
292
293    /* We might actually be done if the request fits in one datum */
294
295    if ((DatumLength == 1) &&
296        ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) <=
297            (UINT16) BitGranularity))
298    {
299        MergedDatum = PreviousRawDatum;
300
301        MergedDatum = (MergedDatum >> ObjDesc->Field.BitOffset);
302
303        ValidFieldBits = ObjDesc->FieldUnit.Length % BitGranularity;
304        if (ValidFieldBits)
305        {
306            Mask = (((UINT32) 1 << ValidFieldBits) - (UINT32) 1);
307            MergedDatum &= Mask;
308        }
309
310
311        /*
312         * Place the MergedDatum into the proper format and return buffer
313         * field
314         */
315
316        switch (ByteGranularity)
317        {
318        case 1:
319            ((UINT8 *) Buffer) [ThisFieldDatumOffset] = (UINT8) MergedDatum;
320            break;
321
322        case 2:
323            MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[ThisFieldDatumOffset]), &MergedDatum);
324            break;
325
326        case 4:
327            MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[ThisFieldDatumOffset]), &MergedDatum);
328            break;
329        }
330
331        ThisFieldByteOffset = 1;
332        ThisFieldDatumOffset = 1;
333    }
334
335    else
336    {
337        /* We need to get more raw data to complete one or more field data */
338
339        while (ThisFieldDatumOffset < DatumLength)
340        {
341            /*
342             * Get the next raw datum, it contains bits of the current
343             * field datum
344             */
345
346            Status = AcpiAmlReadFieldData (ObjDesc,
347                            ThisFieldByteOffset + ByteGranularity,
348                            BitGranularity, &ThisRawDatum);
349            if (ACPI_FAILURE (Status))
350            {
351                goto Cleanup;
352            }
353
354            /* Before merging the data, make sure the unused bits are clear */
355
356            switch (ByteGranularity)
357            {
358            case 1:
359                ThisRawDatum &= 0x000000FF;
360                PreviousRawDatum &= 0x000000FF;
361                break;
362
363            case 2:
364                ThisRawDatum &= 0x0000FFFF;
365                PreviousRawDatum &= 0x0000FFFF;
366                break;
367            }
368
369            /*
370             * Put together bits of the two raw data to make a complete
371             * field datum
372             */
373
374
375            if (ObjDesc->Field.BitOffset != 0)
376            {
377                MergedDatum =
378                    (PreviousRawDatum >> ObjDesc->Field.BitOffset) |
379                    (ThisRawDatum << (BitGranularity - ObjDesc->Field.BitOffset));
380            }
381
382            else
383            {
384                MergedDatum = PreviousRawDatum;
385            }
386
387            /*
388             * Prepare the merged datum for storing into the caller's
389             *  buffer.  It is possible to have a 32-bit buffer
390             *  (ByteGranularity == 4), but a ObjDesc->Field.Length
391             *  of 8 or 16, meaning that the upper bytes of merged data
392             *  are undesired.  This section fixes that.
393             */
394            switch (ObjDesc->Field.Length)
395            {
396            case 8:
397                MergedDatum &= 0x000000FF;
398                break;
399
400            case 16:
401                MergedDatum &= 0x0000FFFF;
402                break;
403            }
404
405            /*
406             * Now store the datum in the caller's buffer, according to
407             * the data type
408             */
409            switch (ByteGranularity)
410            {
411            case 1:
412                ((UINT8 *) Buffer) [ThisFieldDatumOffset] = (UINT8) MergedDatum;
413                break;
414
415            case 2:
416                MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer) [ThisFieldDatumOffset]), &MergedDatum);
417                break;
418
419            case 4:
420                MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer) [ThisFieldDatumOffset]), &MergedDatum);
421                break;
422            }
423
424            /*
425             * Save the most recent datum since it contains bits of
426             * the *next* field datum
427             */
428
429            PreviousRawDatum = ThisRawDatum;
430
431            ThisFieldByteOffset += ByteGranularity;
432            ThisFieldDatumOffset++;
433
434        }  /* while */
435    }
436
437Cleanup:
438
439    return_ACPI_STATUS (Status);
440}
441
442
443/*******************************************************************************
444 *
445 * FUNCTION:    AcpiAmlWriteFieldData
446 *
447 * PARAMETERS:  *ObjDesc            - Field to be set
448 *              Value               - Value to store
449 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
450 *
451 * RETURN:      Status
452 *
453 * DESCRIPTION: Store the value into the given field
454 *
455 ******************************************************************************/
456
457ACPI_STATUS
458AcpiAmlWriteFieldData (
459    ACPI_OPERAND_OBJECT     *ObjDesc,
460    UINT32                  FieldByteOffset,
461    UINT32                  FieldBitWidth,
462    UINT32                  Value)
463{
464    ACPI_STATUS             Status = AE_OK;
465    ACPI_OPERAND_OBJECT     *RgnDesc = NULL;
466    ACPI_INTEGER            Address;
467    UINT32                  FieldByteWidth;
468
469
470    FUNCTION_TRACE ("AmlWriteFieldData");
471
472
473    /* ObjDesc is validated by callers */
474
475    if (ObjDesc)
476    {
477        RgnDesc = ObjDesc->Field.Container;
478    }
479
480    FieldByteWidth = DIV_8 (FieldBitWidth);
481    Status = AcpiAmlSetupField (ObjDesc, RgnDesc, FieldBitWidth);
482    if (ACPI_FAILURE (Status))
483    {
484        return_ACPI_STATUS (Status);
485    }
486
487
488    /*
489     * Set offset to next multiple of field width,
490     *  add region base address and offset within the field
491     */
492    Address = RgnDesc->Region.Address +
493              (ObjDesc->Field.Offset * FieldByteWidth) +
494              FieldByteOffset;
495
496
497    if (RgnDesc->Region.SpaceId >= NUM_REGION_TYPES)
498    {
499        DEBUG_PRINT (TRACE_OPREGION,
500            ("AmlWriteField: **** Store %lx in unknown OpRegion SpaceID %d at %p width %d ** \n",
501            Value, RgnDesc->Region.SpaceId, Address, FieldBitWidth));
502    }
503    else
504    {
505        DEBUG_PRINT (TRACE_OPREGION,
506            ("AmlWriteField: Store %lx in OpRegion %s at %p width %d\n",
507            Value, AcpiGbl_RegionTypes[RgnDesc->Region.SpaceId], Address,
508            FieldBitWidth));
509    }
510
511    /* Invoke the appropriate AddressSpace/OpRegion handler */
512
513    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ADDRESS_SPACE_WRITE,
514                                        Address, FieldBitWidth, &Value);
515
516    if (Status == AE_NOT_IMPLEMENTED)
517    {
518        DEBUG_PRINT (ACPI_ERROR,
519            ("AmlWriteField: **** OpRegion type %s not implemented\n",
520            AcpiGbl_RegionTypes[RgnDesc->Region.SpaceId]));
521    }
522
523    else if (Status == AE_NOT_EXIST)
524    {
525        DEBUG_PRINT (ACPI_ERROR,
526            ("AmlWriteField: **** Unknown OpRegion SpaceID %x\n",
527            RgnDesc->Region.SpaceId));
528    }
529
530    return_ACPI_STATUS (Status);
531}
532
533
534/*****************************************************************************
535 *
536 * FUNCTION:    AcpiAmlWriteFieldDataWithUpdateRule
537 *
538 * PARAMETERS:  *ObjDesc            - Field to be set
539 *              Value               - Value to store
540 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
541 *
542 * RETURN:      Status
543 *
544 * DESCRIPTION: Apply the field update rule to a field write
545 *
546 ****************************************************************************/
547
548ACPI_STATUS
549AcpiAmlWriteFieldDataWithUpdateRule (
550    ACPI_OPERAND_OBJECT     *ObjDesc,
551    UINT32                  Mask,
552    UINT32                  FieldValue,
553    UINT32                  ThisFieldByteOffset,
554    UINT32                  BitGranularity)
555{
556    ACPI_STATUS             Status = AE_OK;
557    UINT32                  MergedValue;
558    UINT32                  CurrentValue;
559
560
561    /* Start with the new bits  */
562
563    MergedValue = FieldValue;
564
565    /* Check if update rule needs to be applied (not if mask is all ones) */
566
567
568    /* Decode the update rule */
569
570    switch (ObjDesc->Field.UpdateRule)
571    {
572
573    case UPDATE_PRESERVE:
574
575        /*
576         * Read the current contents of the byte/word/dword containing
577         * the field, and merge with the new field value.
578         */
579        Status = AcpiAmlReadFieldData (ObjDesc, ThisFieldByteOffset,
580                                        BitGranularity, &CurrentValue);
581        MergedValue |= (CurrentValue & ~Mask);
582        break;
583
584
585    case UPDATE_WRITE_AS_ONES:
586
587        /* Set positions outside the field to all ones */
588
589        MergedValue |= ~Mask;
590        break;
591
592
593    case UPDATE_WRITE_AS_ZEROS:
594
595        /* Set positions outside the field to all zeros */
596
597        MergedValue &= Mask;
598        break;
599
600
601    default:
602        DEBUG_PRINT (ACPI_ERROR,
603            ("WriteFieldDataWithUpdateRule: Unknown UpdateRule setting: %x\n",
604            ObjDesc->Field.UpdateRule));
605        Status = AE_AML_OPERAND_VALUE;
606    }
607
608
609    /* Write the merged value */
610
611    if (ACPI_SUCCESS (Status))
612    {
613        Status = AcpiAmlWriteFieldData (ObjDesc, ThisFieldByteOffset,
614                                        BitGranularity, MergedValue);
615    }
616
617    return (Status);
618}
619
620
621/*****************************************************************************
622 *
623 * FUNCTION:    AcpiAmlWriteField
624 *
625 * PARAMETERS:  *ObjDesc            - Field to be set
626 *              Value               - Value to store
627 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
628 *
629 * RETURN:      Status
630 *
631 * DESCRIPTION: Store the value into the given field
632 *
633 ****************************************************************************/
634
635ACPI_STATUS
636AcpiAmlWriteField (
637    ACPI_OPERAND_OBJECT     *ObjDesc,
638    void                    *Buffer,
639    UINT32                  BufferLength,
640    UINT32                  ByteLength,
641    UINT32                  DatumLength,
642    UINT32                  BitGranularity,
643    UINT32                  ByteGranularity)
644{
645    ACPI_STATUS             Status;
646    UINT32                  ThisFieldByteOffset;
647    UINT32                  ThisFieldDatumOffset;
648    UINT32                  Mask;
649    UINT32                  MergedDatum;
650    UINT32                  PreviousRawDatum;
651    UINT32                  ThisRawDatum;
652    UINT32                  FieldValue;
653    UINT32                  ValidFieldBits;
654
655
656    FUNCTION_TRACE ("AmlWriteField");
657
658
659    /*
660     * Break the request into up to three parts:
661     * non-aligned part at start, aligned part in middle, non-aligned part
662     * at end --- Just like an I/O request ---
663     */
664
665    ThisFieldByteOffset = 0;
666    ThisFieldDatumOffset= 0;
667
668    /* Get a datum */
669
670    switch (ByteGranularity)
671    {
672    case 1:
673        PreviousRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset];
674        break;
675
676    case 2:
677        MOVE_UNALIGNED16_TO_32 (&PreviousRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset]));
678        break;
679
680    case 4:
681        MOVE_UNALIGNED32_TO_32 (&PreviousRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset]));
682        break;
683
684    default:
685        DEBUG_PRINT (ACPI_ERROR, ("AmlWriteField: Invalid granularity: %x\n",
686                        ByteGranularity));
687        Status = AE_AML_OPERAND_VALUE;
688        goto Cleanup;
689    }
690
691
692    /*
693     * Write a partial field datum if field does not begin on a datum boundary
694     *
695     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
696     *
697     * 1) Bits above the field
698     */
699
700    Mask = (((UINT32)(-1)) << (UINT32)ObjDesc->Field.BitOffset);
701
702    /* 2) Only the bottom 5 bits are valid for a shift operation. */
703
704    if ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) < 32)
705    {
706        /* Bits above the field */
707
708        Mask &= (~(((UINT32)(-1)) << ((UINT32)ObjDesc->Field.BitOffset +
709                                        (UINT32)ObjDesc->FieldUnit.Length)));
710    }
711
712    /* 3) Shift and mask the value into the field position */
713
714    FieldValue = (PreviousRawDatum << ObjDesc->Field.BitOffset) & Mask;
715
716    Status = AcpiAmlWriteFieldDataWithUpdateRule (ObjDesc, Mask, FieldValue,
717                                                    ThisFieldByteOffset,
718                                                    BitGranularity);
719    if (ACPI_FAILURE (Status))
720    {
721        goto Cleanup;
722    }
723
724
725    /* If the field fits within one datum, we are done. */
726
727    if ((DatumLength == 1) &&
728       ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) <=
729            (UINT16) BitGranularity))
730    {
731        goto Cleanup;
732    }
733
734    /*
735     * We don't need to worry about the update rule for these data, because
736     * all of the bits are part of the field.
737     *
738     * Can't write the last datum, however, because it might contain bits that
739     * are not part of the field -- the update rule must be applied.
740     */
741
742    while (ThisFieldDatumOffset < (DatumLength - 1))
743    {
744        ThisFieldDatumOffset++;
745
746        /* Get the next raw datum, it contains bits of the current field datum... */
747
748        switch (ByteGranularity)
749        {
750        case 1:
751            ThisRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset];
752            break;
753
754        case 2:
755            MOVE_UNALIGNED16_TO_32 (&ThisRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset]));
756            break;
757
758        case 4:
759            MOVE_UNALIGNED32_TO_32 (&ThisRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset]));
760            break;
761
762        default:
763            DEBUG_PRINT (ACPI_ERROR, ("AmlWriteField: Invalid Byte Granularity: %x\n",
764                            ByteGranularity));
765            Status = AE_AML_OPERAND_VALUE;
766            goto Cleanup;
767        }
768
769        /*
770         * Put together bits of the two raw data to make a complete field
771         * datum
772         */
773
774        if (ObjDesc->Field.BitOffset != 0)
775        {
776            MergedDatum =
777                (PreviousRawDatum >> (BitGranularity - ObjDesc->Field.BitOffset)) |
778                (ThisRawDatum << ObjDesc->Field.BitOffset);
779        }
780
781        else
782        {
783            MergedDatum = ThisRawDatum;
784        }
785
786        /* Now write the completed datum  */
787
788
789        Status = AcpiAmlWriteFieldData (ObjDesc,
790                                        ThisFieldByteOffset + ByteGranularity,
791                                        BitGranularity, MergedDatum);
792        if (ACPI_FAILURE (Status))
793        {
794            goto Cleanup;
795        }
796
797
798        /*
799         * Save the most recent datum since it contains bits of
800         * the *next* field datum
801         */
802
803        PreviousRawDatum = ThisRawDatum;
804
805        ThisFieldByteOffset += ByteGranularity;
806
807    }  /* while */
808
809
810    /* Write a partial field datum if field does not end on a datum boundary */
811
812    if ((ObjDesc->FieldUnit.Length + ObjDesc->FieldUnit.BitOffset) %
813        BitGranularity)
814    {
815        switch (ByteGranularity)
816        {
817        case 1:
818            ThisRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset];
819            break;
820
821        case 2:
822            MOVE_UNALIGNED16_TO_32 (&ThisRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset]));
823            break;
824
825        case 4:
826            MOVE_UNALIGNED32_TO_32 (&ThisRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset]));
827            break;
828        }
829
830        /* Construct Mask with 1 bits where the field is, 0 bits elsewhere */
831
832        ValidFieldBits = ((ObjDesc->FieldUnit.Length % BitGranularity) +
833                            ObjDesc->Field.BitOffset);
834
835        Mask = (((UINT32) 1 << ValidFieldBits) - (UINT32) 1);
836
837        /* Shift and mask the value into the field position */
838
839        FieldValue = (PreviousRawDatum >>
840                        (BitGranularity - ObjDesc->Field.BitOffset)) & Mask;
841
842        Status = AcpiAmlWriteFieldDataWithUpdateRule (ObjDesc, Mask, FieldValue,
843                                                        ThisFieldByteOffset + ByteGranularity,
844                                                        BitGranularity);
845        if (ACPI_FAILURE (Status))
846        {
847            goto Cleanup;
848        }
849    }
850
851
852Cleanup:
853
854    return_ACPI_STATUS (Status);
855}
856
857
858