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