exfldio.c revision 73561
150476Speter/******************************************************************************
221611Swosch *
321611Swosch * Module Name: amfldio - Aml Field I/O
421611Swosch *              $Revision: 39 $
521611Swosch *
618052Sbde *****************************************************************************/
721611Swosch
836494Sbde/******************************************************************************
918052Sbde *
1036494Sbde * 1. Copyright Notice
1176576Smarkm *
1239412Sphk * Some or all of this work - Copyright (c) 1999, 2000, 2001, Intel Corp.
1336494Sbde * All rights reserved.
1476515Sbde *
1569227Sbrian * 2. License
1636494Sbde *
1739259Sgibbs * 2.1. This is your license from Intel Corp. under its intellectual property
1836575Speter * rights.  You may have additional license terms from the party that provided
1976515Sbde * you this software, covering your right to use that party's intellectual
2036494Sbde * property rights.
2136494Sbde *
2257461Smarkm * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
2336494Sbde * copy of the source code appearing in this file ("Covered Code") an
2436575Speter * irrevocable, perpetual, worldwide license under Intel's copyrights in the
2576515Sbde * base code distributed originally by Intel ("Original Intel Code") to copy,
2639259Sgibbs * make derivatives, distribute, use and display any portion of the Covered
2736494Sbde * Code in any form, with the right to sublicense such rights; and
2836494Sbde *
2936494Sbde * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
3074535Sdes * license (with the right to sublicense), under only those claims of Intel
3118052Sbde * patents that are infringed by the Original Intel Code, to make, use, sell,
3276515Sbde * offer to sell, and import the Covered Code and derivative works thereof
3336494Sbde * solely to the minimum extent necessary to exercise the above copyright
3476515Sbde * license, and in no event shall the patent license extend to any additions
3536494Sbde * to or modifications of the Original Intel Code.  No other license or right
3636494Sbde * is granted directly or by implication, estoppel or otherwise;
3736494Sbde *
3847570Sache * The above copyright and patent license is granted only if the following
3957538Sshin * conditions are met:
4036494Sbde *
4167523Sarchie * 3. Conditions
4236575Speter *
4336575Speter * 3.1. Redistribution of Source with Rights to Further Distribute Source.
4476576Smarkm * Redistribution of source code of any substantial portion of the Covered
4536494Sbde * Code or modification with rights to further distribute source must include
4636494Sbde * the above Copyright Notice, the above License, this list of Conditions,
4736494Sbde * and the following Disclaimer and Export Compliance provision.  In addition,
4865916Sache * Licensee must cause all Covered Code to which Licensee contributes to
4936494Sbde * contain a file documenting the changes Licensee made to create that Covered
5036494Sbde * Code and the date of any change.  Licensee must include in that file the
5176515Sbde * documentation of any changes made by any predecessor Licensee.  Licensee
5236494Sbde * must include a prominent statement that the modification is derived,
5365916Sache * directly or indirectly, from Original Intel Code.
5452251Sbp *
5536494Sbde * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
5652419Sjulian * Redistribution of source code of any substantial portion of the Covered
5736494Sbde * Code or modification without rights to further distribute source must
5836494Sbde * include the following Disclaimer and Export Compliance provision in the
5942916Sjdp * documentation and/or other materials provided with distribution.  In
6042916Sjdp * addition, Licensee may not authorize further sublicense of source of any
6142916Sjdp * portion of the Covered Code, and must include terms to the effect that the
6259770Sbde * license from Licensee to its licensee is limited to the intellectual
6342916Sjdp * property embodied in the software Licensee provides to its licensee, and
6442916Sjdp * not to intellectual property embodied in modifications its licensee may
6576576Smarkm * make.
6642916Sjdp *
6776576Smarkm * 3.3. Redistribution of Executable. Redistribution in executable form of any
6876576Smarkm * substantial portion of the Covered Code or modification must reproduce the
6942916Sjdp * above Copyright Notice, and the following Disclaimer and Export Compliance
7076576Smarkm * provision in the documentation and/or other materials provided with the
7177866Smarkm * distribution.
7277866Smarkm *
7376576Smarkm * 3.4. Intel retains all right, title, and interest in and to the Original
7477866Smarkm * Intel Code.
7576576Smarkm *
7676576Smarkm * 3.5. Neither the name Intel nor any other trademark owned or controlled by
7755157Sbde * Intel shall be used in advertising or otherwise to promote the sale, use or
7877866Smarkm * other dealings in products derived from or relating to the Covered Code
7977866Smarkm * without prior written authorization from Intel.
8042916Sjdp *
8142916Sjdp * 4. Disclaimer and Export Compliance
8276515Sbde *
8336494Sbde * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
8436494Sbde * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
8539020Smarkm * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
8636494Sbde * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
8741231Sjdp * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
8836494Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
8936494Sbde * PARTICULAR PURPOSE.
9077866Smarkm *
9136494Sbde * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
9274840Sken * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
9336494Sbde * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
9436494Sbde * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
9566913Sgshapiro * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
9636494Sbde * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
9741231Sjdp * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
9836494Sbde * LIMITED REMEDY.
9918052Sbde *
10076515Sbde * 4.3. Licensee shall not export, either directly or indirectly, any of this
10136494Sbde * software or system incorporating such software without first obtaining any
10276515Sbde * required license or other approval from the U. S. Department of Commerce or
10376515Sbde * any other agency or department of the United States Government.  In the
10444757Smarkm * event Licensee exports any such software from the United States or
10536494Sbde * re-exports any such software from a foreign destination, Licensee shall
10636494Sbde * ensure that the distribution and export/re-export of the software is in
10736494Sbde * 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 __AMFLDIO_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
127
128#define _COMPONENT          INTERPRETER
129        MODULE_NAME         ("amfldio")
130
131
132/*******************************************************************************
133 *
134 * FUNCTION:    AcpiAmlReadFieldData
135 *
136 * PARAMETERS:  *ObjDesc            - Field to be read
137 *              *Value              - Where to store value
138 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
139 *
140 * RETURN:      Status
141 *
142 * DESCRIPTION: Retrieve the value of the given field
143 *
144 ******************************************************************************/
145
146ACPI_STATUS
147AcpiAmlReadFieldData (
148    ACPI_OPERAND_OBJECT     *ObjDesc,
149    UINT32                  FieldByteOffset,
150    UINT32                  FieldBitWidth,
151    UINT32                  *Value)
152{
153    ACPI_STATUS             Status;
154    ACPI_OPERAND_OBJECT     *RgnDesc = NULL;
155    ACPI_PHYSICAL_ADDRESS   Address;
156    UINT32                  LocalValue = 0;
157    UINT32                  FieldByteWidth;
158
159
160    FUNCTION_TRACE ("AmlReadFieldData");
161
162
163    /* ObjDesc is validated by callers */
164
165    if (ObjDesc)
166    {
167        RgnDesc = ObjDesc->Field.Container;
168    }
169
170
171    FieldByteWidth = DIV_8 (FieldBitWidth);
172    Status = AcpiAmlSetupField (ObjDesc, RgnDesc, FieldBitWidth);
173    if (ACPI_FAILURE (Status))
174    {
175        return_ACPI_STATUS (Status);
176    }
177
178    /* SetupField validated RgnDesc and FieldBitWidth  */
179
180    if (!Value)
181    {
182        Value = &LocalValue;    /*  support reads without saving value  */
183    }
184
185
186    /*
187     * Set offset to next multiple of field width,
188     *  add region base address and offset within the field
189     */
190    Address = RgnDesc->Region.Address +
191              (ObjDesc->Field.Offset * FieldByteWidth) +
192              FieldByteOffset;
193
194    DEBUG_PRINT (TRACE_OPREGION,
195        ("AmlReadFieldData: Region %s(%X) at %08lx width %X\n",
196        AcpiCmGetRegionName (RgnDesc->Region.SpaceId),
197        RgnDesc->Region.SpaceId, Address,
198        FieldBitWidth));
199
200
201    /* Invoke the appropriate AddressSpace/OpRegion handler */
202
203    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ADDRESS_SPACE_READ,
204                                        Address, FieldBitWidth, Value);
205
206    if (Status == AE_NOT_IMPLEMENTED)
207    {
208        DEBUG_PRINT (ACPI_ERROR,
209            ("AmlReadFieldData: **** Region %s(%X) not implemented\n",
210            AcpiCmGetRegionName (RgnDesc->Region.SpaceId),
211            RgnDesc->Region.SpaceId));
212    }
213
214    else if (Status == AE_NOT_EXIST)
215    {
216        DEBUG_PRINT (ACPI_ERROR,
217            ("AmlReadFieldData: **** Region %s(%X) has no handler\n",
218            AcpiCmGetRegionName (RgnDesc->Region.SpaceId),
219            RgnDesc->Region.SpaceId));
220    }
221
222    DEBUG_PRINT (TRACE_OPREGION,
223        ("AmlReadField: Returned value=%08lx \n", *Value));
224
225    return_ACPI_STATUS (Status);
226}
227
228
229/*******************************************************************************
230 *
231 * FUNCTION:    AcpiAmlReadField
232 *
233 * PARAMETERS:  *ObjDesc            - Field to be read
234 *              *Value              - Where to store value
235 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
236 *
237 * RETURN:      Status
238 *
239 * DESCRIPTION: Retrieve the value of the given field
240 *
241 ******************************************************************************/
242
243ACPI_STATUS
244AcpiAmlReadField (
245    ACPI_OPERAND_OBJECT     *ObjDesc,
246    void                    *Buffer,
247    UINT32                  BufferLength,
248    UINT32                  ByteLength,
249    UINT32                  DatumLength,
250    UINT32                  BitGranularity,
251    UINT32                  ByteGranularity)
252{
253    ACPI_STATUS             Status;
254    UINT32                  ThisFieldByteOffset;
255    UINT32                  ThisFieldDatumOffset;
256    UINT32                  PreviousRawDatum;
257    UINT32                  ThisRawDatum = 0;
258    UINT32                  ValidFieldBits;
259    UINT32                  Mask;
260    UINT32                  MergedDatum = 0;
261
262
263    FUNCTION_TRACE ("AmlReadField");
264
265    /*
266     * Clear the caller's buffer (the whole buffer length as given)
267     * This is very important, especially in the cases where a byte is read,
268     * but the buffer is really a UINT32 (4 bytes).
269     */
270
271    MEMSET (Buffer, 0, BufferLength);
272
273    /* Read the first raw datum to prime the loop */
274
275    ThisFieldByteOffset = 0;
276    ThisFieldDatumOffset= 0;
277
278    Status = AcpiAmlReadFieldData (ObjDesc, ThisFieldByteOffset, BitGranularity,
279                                    &PreviousRawDatum);
280    if (ACPI_FAILURE (Status))
281    {
282        goto Cleanup;
283    }
284
285    /* We might actually be done if the request fits in one datum */
286
287    if ((DatumLength == 1) &&
288        ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) <=
289            (UINT16) BitGranularity))
290    {
291        MergedDatum = PreviousRawDatum;
292
293        MergedDatum = (MergedDatum >> ObjDesc->Field.BitOffset);
294
295        ValidFieldBits = ObjDesc->FieldUnit.Length % BitGranularity;
296        if (ValidFieldBits)
297        {
298            Mask = (((UINT32) 1 << ValidFieldBits) - (UINT32) 1);
299            MergedDatum &= Mask;
300        }
301
302
303        /*
304         * Place the MergedDatum into the proper format and return buffer
305         * field
306         */
307
308        switch (ByteGranularity)
309        {
310        case 1:
311            ((UINT8 *) Buffer) [ThisFieldDatumOffset] = (UINT8) MergedDatum;
312            break;
313
314        case 2:
315            MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[ThisFieldDatumOffset]), &MergedDatum);
316            break;
317
318        case 4:
319            MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[ThisFieldDatumOffset]), &MergedDatum);
320            break;
321        }
322
323        ThisFieldByteOffset = 1;
324        ThisFieldDatumOffset = 1;
325    }
326
327    else
328    {
329        /* We need to get more raw data to complete one or more field data */
330
331        while (ThisFieldDatumOffset < DatumLength)
332        {
333            /*
334             * If the field is aligned on a byte boundary, we don't want
335             * to perform a final read, since this would potentially read
336             * past the end of the region.
337             *
338             * TBD: [Investigate] It may make more sense to just split the aligned
339             * and non-aligned cases since the aligned case is so very simple,
340             */
341            if ((ObjDesc->Field.BitOffset != 0) ||
342                ((ObjDesc->Field.BitOffset == 0) &&
343                (ThisFieldDatumOffset < (DatumLength -1))))
344            {
345                /*
346                 * Get the next raw datum, it contains some or all bits
347                 * of the current field datum
348                 */
349
350                Status = AcpiAmlReadFieldData (ObjDesc,
351                                ThisFieldByteOffset + ByteGranularity,
352                                BitGranularity, &ThisRawDatum);
353                if (ACPI_FAILURE (Status))
354                {
355                    goto Cleanup;
356                }
357
358                /* Before merging the data, make sure the unused bits are clear */
359
360                switch (ByteGranularity)
361                {
362                case 1:
363                    ThisRawDatum &= 0x000000FF;
364                    PreviousRawDatum &= 0x000000FF;
365                    break;
366
367                case 2:
368                    ThisRawDatum &= 0x0000FFFF;
369                    PreviousRawDatum &= 0x0000FFFF;
370                    break;
371                }
372            }
373
374
375            /*
376             * Put together bits of the two raw data to make a complete
377             * field datum
378             */
379
380
381            if (ObjDesc->Field.BitOffset != 0)
382            {
383                MergedDatum =
384                    (PreviousRawDatum >> ObjDesc->Field.BitOffset) |
385                    (ThisRawDatum << (BitGranularity - ObjDesc->Field.BitOffset));
386            }
387
388            else
389            {
390                MergedDatum = PreviousRawDatum;
391            }
392
393            /*
394             * Prepare the merged datum for storing into the caller's
395             *  buffer.  It is possible to have a 32-bit buffer
396             *  (ByteGranularity == 4), but a ObjDesc->Field.Length
397             *  of 8 or 16, meaning that the upper bytes of merged data
398             *  are undesired.  This section fixes that.
399             */
400            switch (ObjDesc->Field.Length)
401            {
402            case 8:
403                MergedDatum &= 0x000000FF;
404                break;
405
406            case 16:
407                MergedDatum &= 0x0000FFFF;
408                break;
409            }
410
411            /*
412             * Now store the datum in the caller's buffer, according to
413             * the data type
414             */
415            switch (ByteGranularity)
416            {
417            case 1:
418                ((UINT8 *) Buffer) [ThisFieldDatumOffset] = (UINT8) MergedDatum;
419                break;
420
421            case 2:
422                MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer) [ThisFieldDatumOffset]), &MergedDatum);
423                break;
424
425            case 4:
426                MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer) [ThisFieldDatumOffset]), &MergedDatum);
427                break;
428            }
429
430            /*
431             * Save the most recent datum since it contains bits of
432             * the *next* field datum
433             */
434
435            PreviousRawDatum = ThisRawDatum;
436
437            ThisFieldByteOffset += ByteGranularity;
438            ThisFieldDatumOffset++;
439
440        }  /* while */
441    }
442
443Cleanup:
444
445    return_ACPI_STATUS (Status);
446}
447
448
449/*******************************************************************************
450 *
451 * FUNCTION:    AcpiAmlWriteFieldData
452 *
453 * PARAMETERS:  *ObjDesc            - Field to be set
454 *              Value               - Value to store
455 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
456 *
457 * RETURN:      Status
458 *
459 * DESCRIPTION: Store the value into the given field
460 *
461 ******************************************************************************/
462
463static ACPI_STATUS
464AcpiAmlWriteFieldData (
465    ACPI_OPERAND_OBJECT     *ObjDesc,
466    UINT32                  FieldByteOffset,
467    UINT32                  FieldBitWidth,
468    UINT32                  Value)
469{
470    ACPI_STATUS             Status = AE_OK;
471    ACPI_OPERAND_OBJECT     *RgnDesc = NULL;
472    ACPI_PHYSICAL_ADDRESS   Address;
473    UINT32                  FieldByteWidth;
474
475
476    FUNCTION_TRACE ("AmlWriteFieldData");
477
478
479    /* ObjDesc is validated by callers */
480
481    if (ObjDesc)
482    {
483        RgnDesc = ObjDesc->Field.Container;
484    }
485
486    FieldByteWidth = DIV_8 (FieldBitWidth);
487    Status = AcpiAmlSetupField (ObjDesc, RgnDesc, FieldBitWidth);
488    if (ACPI_FAILURE (Status))
489    {
490        return_ACPI_STATUS (Status);
491    }
492
493
494    /*
495     * Set offset to next multiple of field width,
496     *  add region base address and offset within the field
497     */
498    Address = RgnDesc->Region.Address +
499              (ObjDesc->Field.Offset * FieldByteWidth) +
500              FieldByteOffset;
501
502    DEBUG_PRINT (TRACE_OPREGION,
503        ("AmlWriteField: Store %lx in Region %s(%X) at %p width %X\n",
504        Value, AcpiCmGetRegionName (RgnDesc->Region.SpaceId),
505        RgnDesc->Region.SpaceId, Address,
506        FieldBitWidth));
507
508    /* Invoke the appropriate AddressSpace/OpRegion handler */
509
510    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ADDRESS_SPACE_WRITE,
511                                        Address, FieldBitWidth, &Value);
512
513    if (Status == AE_NOT_IMPLEMENTED)
514    {
515        DEBUG_PRINT (ACPI_ERROR,
516            ("AmlWriteField: **** Region type %s(%X) not implemented\n",
517            AcpiCmGetRegionName (RgnDesc->Region.SpaceId),
518            RgnDesc->Region.SpaceId));
519    }
520
521    else if (Status == AE_NOT_EXIST)
522    {
523        DEBUG_PRINT (ACPI_ERROR,
524            ("AmlWriteField: **** Region type %s(%X) does not have a handler\n",
525            AcpiCmGetRegionName (RgnDesc->Region.SpaceId),
526            RgnDesc->Region.SpaceId));
527    }
528
529    return_ACPI_STATUS (Status);
530}
531
532
533/*****************************************************************************
534 *
535 * FUNCTION:    AcpiAmlWriteFieldDataWithUpdateRule
536 *
537 * PARAMETERS:  *ObjDesc            - Field to be set
538 *              Value               - Value to store
539 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
540 *
541 * RETURN:      Status
542 *
543 * DESCRIPTION: Apply the field update rule to a field write
544 *
545 ****************************************************************************/
546
547static ACPI_STATUS
548AcpiAmlWriteFieldDataWithUpdateRule (
549    ACPI_OPERAND_OBJECT     *ObjDesc,
550    UINT32                  Mask,
551    UINT32                  FieldValue,
552    UINT32                  ThisFieldByteOffset,
553    UINT32                  BitGranularity)
554{
555    ACPI_STATUS             Status = AE_OK;
556    UINT32                  MergedValue;
557    UINT32                  CurrentValue;
558
559
560    /* Start with the new bits  */
561
562    MergedValue = FieldValue;
563
564
565
566    /* Decode the update rule */
567
568    switch (ObjDesc->Field.UpdateRule)
569    {
570
571    case UPDATE_PRESERVE:
572
573        /* Check if update rule needs to be applied (not if mask is all ones) */
574
575        /* The left shift drops the bits we want to ignore. */
576        if ((~Mask << (sizeof(Mask)*8 - BitGranularity)) != 0)
577        {
578            /*
579             * Read the current contents of the byte/word/dword containing
580             * the field, and merge with the new field value.
581             */
582            Status = AcpiAmlReadFieldData (ObjDesc, ThisFieldByteOffset,
583                                            BitGranularity, &CurrentValue);
584            MergedValue |= (CurrentValue & ~Mask);
585        }
586        break;
587
588
589    case UPDATE_WRITE_AS_ONES:
590
591        /* Set positions outside the field to all ones */
592
593        MergedValue |= ~Mask;
594        break;
595
596
597    case UPDATE_WRITE_AS_ZEROS:
598
599        /* Set positions outside the field to all zeros */
600
601        MergedValue &= Mask;
602        break;
603
604
605    default:
606        DEBUG_PRINT (ACPI_ERROR,
607            ("WriteFieldDataWithUpdateRule: Unknown UpdateRule setting: %x\n",
608            ObjDesc->Field.UpdateRule));
609        Status = AE_AML_OPERAND_VALUE;
610    }
611
612
613    /* Write the merged value */
614
615    if (ACPI_SUCCESS (Status))
616    {
617        Status = AcpiAmlWriteFieldData (ObjDesc, ThisFieldByteOffset,
618                                        BitGranularity, MergedValue);
619    }
620
621    return (Status);
622}
623
624
625/*****************************************************************************
626 *
627 * FUNCTION:    AcpiAmlWriteField
628 *
629 * PARAMETERS:  *ObjDesc            - Field to be set
630 *              Value               - Value to store
631 *              FieldBitWidth       - Field Width in bits (8, 16, or 32)
632 *
633 * RETURN:      Status
634 *
635 * DESCRIPTION: Store the value into the given field
636 *
637 ****************************************************************************/
638
639ACPI_STATUS
640AcpiAmlWriteField (
641    ACPI_OPERAND_OBJECT     *ObjDesc,
642    void                    *Buffer,
643    UINT32                  BufferLength,
644    UINT32                  ByteLength,
645    UINT32                  DatumLength,
646    UINT32                  BitGranularity,
647    UINT32                  ByteGranularity)
648{
649    ACPI_STATUS             Status;
650    UINT32                  ThisFieldByteOffset;
651    UINT32                  ThisFieldDatumOffset;
652    UINT32                  Mask;
653    UINT32                  MergedDatum;
654    UINT32                  PreviousRawDatum;
655    UINT32                  ThisRawDatum;
656    UINT32                  FieldValue;
657    UINT32                  ValidFieldBits;
658
659
660    FUNCTION_TRACE ("AmlWriteField");
661
662
663    /*
664     * Break the request into up to three parts:
665     * non-aligned part at start, aligned part in middle, non-aligned part
666     * at end --- Just like an I/O request ---
667     */
668
669    ThisFieldByteOffset = 0;
670    ThisFieldDatumOffset= 0;
671
672    /* Get a datum */
673
674    switch (ByteGranularity)
675    {
676    case 1:
677        PreviousRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset];
678        break;
679
680    case 2:
681        MOVE_UNALIGNED16_TO_32 (&PreviousRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset]));
682        break;
683
684    case 4:
685        MOVE_UNALIGNED32_TO_32 (&PreviousRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset]));
686        break;
687
688    default:
689        DEBUG_PRINT (ACPI_ERROR, ("AmlWriteField: Invalid granularity: %x\n",
690                        ByteGranularity));
691        Status = AE_AML_OPERAND_VALUE;
692        goto Cleanup;
693    }
694
695
696    /*
697     * Write a partial field datum if field does not begin on a datum boundary
698     *
699     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
700     *
701     * 1) Bits above the field
702     */
703
704    Mask = (((UINT32)(-1)) << (UINT32)ObjDesc->Field.BitOffset);
705
706    /* 2) Only the bottom 5 bits are valid for a shift operation. */
707
708    if ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) < 32)
709    {
710        /* Bits above the field */
711
712        Mask &= (~(((UINT32)(-1)) << ((UINT32)ObjDesc->Field.BitOffset +
713                                        (UINT32)ObjDesc->FieldUnit.Length)));
714    }
715
716    /* 3) Shift and mask the value into the field position */
717
718    FieldValue = (PreviousRawDatum << ObjDesc->Field.BitOffset) & Mask;
719
720    Status = AcpiAmlWriteFieldDataWithUpdateRule (ObjDesc, Mask, FieldValue,
721                                                    ThisFieldByteOffset,
722                                                    BitGranularity);
723    if (ACPI_FAILURE (Status))
724    {
725        goto Cleanup;
726    }
727
728
729    /* If the field fits within one datum, we are done. */
730
731    if ((DatumLength == 1) &&
732       ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) <=
733            (UINT16) BitGranularity))
734    {
735        goto Cleanup;
736    }
737
738    /*
739     * We don't need to worry about the update rule for these data, because
740     * all of the bits are part of the field.
741     *
742     * Can't write the last datum, however, because it might contain bits that
743     * are not part of the field -- the update rule must be applied.
744     */
745
746    while (ThisFieldDatumOffset < (DatumLength - 1))
747    {
748        ThisFieldDatumOffset++;
749
750        /* Get the next raw datum, it contains bits of the current field datum... */
751
752        switch (ByteGranularity)
753        {
754        case 1:
755            ThisRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset];
756            break;
757
758        case 2:
759            MOVE_UNALIGNED16_TO_32 (&ThisRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset]));
760            break;
761
762        case 4:
763            MOVE_UNALIGNED32_TO_32 (&ThisRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset]));
764            break;
765
766        default:
767            DEBUG_PRINT (ACPI_ERROR, ("AmlWriteField: Invalid Byte Granularity: %x\n",
768                            ByteGranularity));
769            Status = AE_AML_OPERAND_VALUE;
770            goto Cleanup;
771        }
772
773        /*
774         * Put together bits of the two raw data to make a complete field
775         * datum
776         */
777
778        if (ObjDesc->Field.BitOffset != 0)
779        {
780            MergedDatum =
781                (PreviousRawDatum >> (BitGranularity - ObjDesc->Field.BitOffset)) |
782                (ThisRawDatum << ObjDesc->Field.BitOffset);
783        }
784
785        else
786        {
787            MergedDatum = ThisRawDatum;
788        }
789
790        /* Now write the completed datum  */
791
792
793        Status = AcpiAmlWriteFieldData (ObjDesc,
794                                        ThisFieldByteOffset + ByteGranularity,
795                                        BitGranularity, MergedDatum);
796        if (ACPI_FAILURE (Status))
797        {
798            goto Cleanup;
799        }
800
801
802        /*
803         * Save the most recent datum since it contains bits of
804         * the *next* field datum
805         */
806
807        PreviousRawDatum = ThisRawDatum;
808
809        ThisFieldByteOffset += ByteGranularity;
810
811    }  /* while */
812
813
814    /* Write a partial field datum if field does not end on a datum boundary */
815
816    if ((ObjDesc->FieldUnit.Length + ObjDesc->FieldUnit.BitOffset) %
817        BitGranularity)
818    {
819        switch (ByteGranularity)
820        {
821        case 1:
822            ThisRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset];
823            break;
824
825        case 2:
826            MOVE_UNALIGNED16_TO_32 (&ThisRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset]));
827            break;
828
829        case 4:
830            MOVE_UNALIGNED32_TO_32 (&ThisRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset]));
831            break;
832        }
833
834        /* Construct Mask with 1 bits where the field is, 0 bits elsewhere */
835
836        ValidFieldBits = ((ObjDesc->FieldUnit.Length % BitGranularity) +
837                            ObjDesc->Field.BitOffset);
838
839        Mask = (((UINT32) 1 << ValidFieldBits) - (UINT32) 1);
840
841        /* Shift and mask the value into the field position */
842
843        FieldValue = (PreviousRawDatum >>
844                        (BitGranularity - ObjDesc->Field.BitOffset)) & Mask;
845
846        Status = AcpiAmlWriteFieldDataWithUpdateRule (ObjDesc, Mask, FieldValue,
847                                                        ThisFieldByteOffset + ByteGranularity,
848                                                        BitGranularity);
849        if (ACPI_FAILURE (Status))
850        {
851            goto Cleanup;
852        }
853    }
854
855
856Cleanup:
857
858    return_ACPI_STATUS (Status);
859}
860
861
862