]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/contrib/dev/acpica/exfldio.c
This commit was generated by cvs2svn to compensate for changes in r135768,
[FreeBSD/FreeBSD.git] / sys / contrib / dev / acpica / exfldio.c
1 /******************************************************************************
2  *
3  * Module Name: exfldio - Aml Field I/O
4  *              $Revision: 106 $
5  *
6  *****************************************************************************/
7
8 /******************************************************************************
9  *
10  * 1. Copyright Notice
11  *
12  * Some or all of this work - Copyright (c) 1999 - 2004, 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 "acevents.h"
124 #include "acdispat.h"
125
126
127 #define _COMPONENT          ACPI_EXECUTER
128         ACPI_MODULE_NAME    ("exfldio")
129
130
131 /*******************************************************************************
132  *
133  * FUNCTION:    AcpiExSetupRegion
134  *
135  * PARAMETERS:  *ObjDesc                - Field to be read or written
136  *              FieldDatumByteOffset    - Byte offset of this datum within the
137  *                                        parent field
138  *
139  * RETURN:      Status
140  *
141  * DESCRIPTION: Common processing for AcpiExExtractFromField and
142  *              AcpiExInsertIntoField.  Initialize the Region if necessary and
143  *              validate the request.
144  *
145  ******************************************************************************/
146
147 ACPI_STATUS
148 AcpiExSetupRegion (
149     ACPI_OPERAND_OBJECT     *ObjDesc,
150     UINT32                  FieldDatumByteOffset)
151 {
152     ACPI_STATUS             Status = AE_OK;
153     ACPI_OPERAND_OBJECT     *RgnDesc;
154
155
156     ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
157
158
159     RgnDesc = ObjDesc->CommonField.RegionObj;
160
161     /* We must have a valid region */
162
163     if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
164     {
165         ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
166             ACPI_GET_OBJECT_TYPE (RgnDesc),
167             AcpiUtGetObjectTypeName (RgnDesc)));
168
169         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
170     }
171
172     /*
173      * If the Region Address and Length have not been previously evaluated,
174      * evaluate them now and save the results.
175      */
176     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
177     {
178         Status = AcpiDsGetRegionArguments (RgnDesc);
179         if (ACPI_FAILURE (Status))
180         {
181             return_ACPI_STATUS (Status);
182         }
183     }
184
185     if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
186     {
187         /* SMBus has a non-linear address space */
188
189         return_ACPI_STATUS (AE_OK);
190     }
191
192 #ifdef ACPI_UNDER_DEVELOPMENT
193     /*
194      * If the Field access is AnyAcc, we can now compute the optimal
195      * access (because we know know the length of the parent region)
196      */
197     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
198     {
199         if (ACPI_FAILURE (Status))
200         {
201             return_ACPI_STATUS (Status);
202         }
203     }
204 #endif
205
206     /*
207      * Validate the request.  The entire request from the byte offset for a
208      * length of one field datum (access width) must fit within the region.
209      * (Region length is specified in bytes)
210      */
211     if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset
212                                     + FieldDatumByteOffset
213                                     + ObjDesc->CommonField.AccessByteWidth))
214     {
215         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
216         {
217             /*
218              * This is the case where the AccessType (AccWord, etc.) is wider
219              * than the region itself.  For example, a region of length one
220              * byte, and a field with Dword access specified.
221              */
222             ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
223                 "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
224                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
225                 ObjDesc->CommonField.AccessByteWidth,
226                 AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
227         }
228
229         /*
230          * Offset rounded up to next multiple of field width
231          * exceeds region length, indicate an error
232          */
233         ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
234             "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
235             AcpiUtGetNodeName (ObjDesc->CommonField.Node),
236             ObjDesc->CommonField.BaseByteOffset,
237             FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
238             AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length));
239
240 #ifndef ACPICA_PEDANTIC
241         {
242             /*
243              * Allow access to the field if it is within the region size
244              * rounded up to a multiple of the access byte width.  This
245              * overcomes "off-by-one" programming errors in the AML often
246              * found in Toshiba laptops.  These errors were allowed by
247              * the Microsoft ASL compiler.
248              */
249             UINT32 rounded_length = ACPI_ROUND_UP(RgnDesc->Region.Length,
250                 ObjDesc->CommonField.AccessByteWidth);
251
252             if (rounded_length >= (ObjDesc->CommonField.BaseByteOffset +
253                                    FieldDatumByteOffset +
254                                    ObjDesc->CommonField.AccessByteWidth)) {
255                 return_ACPI_STATUS (AE_OK);
256             }
257         }
258 #endif
259         return_ACPI_STATUS (AE_AML_REGION_LIMIT);
260     }
261
262     return_ACPI_STATUS (AE_OK);
263 }
264
265
266 /*******************************************************************************
267  *
268  * FUNCTION:    AcpiExAccessRegion
269  *
270  * PARAMETERS:  *ObjDesc                - Field to be read
271  *              FieldDatumByteOffset    - Byte offset of this datum within the
272  *                                        parent field
273  *              *Value                  - Where to store value (must at least
274  *                                        the size of ACPI_INTEGER)
275  *              Function                - Read or Write flag plus other region-
276  *                                        dependent flags
277  *
278  * RETURN:      Status
279  *
280  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
281  *
282  ******************************************************************************/
283
284 ACPI_STATUS
285 AcpiExAccessRegion (
286     ACPI_OPERAND_OBJECT     *ObjDesc,
287     UINT32                  FieldDatumByteOffset,
288     ACPI_INTEGER            *Value,
289     UINT32                  Function)
290 {
291     ACPI_STATUS             Status;
292     ACPI_OPERAND_OBJECT     *RgnDesc;
293     ACPI_PHYSICAL_ADDRESS   Address;
294
295
296     ACPI_FUNCTION_TRACE ("ExAccessRegion");
297
298
299     /*
300      * Ensure that the region operands are fully evaluated and verify
301      * the validity of the request
302      */
303     Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
304     if (ACPI_FAILURE (Status))
305     {
306         return_ACPI_STATUS (Status);
307     }
308
309     /*
310      * The physical address of this field datum is:
311      *
312      * 1) The base of the region, plus
313      * 2) The base offset of the field, plus
314      * 3) The current offset into the field
315      */
316     RgnDesc = ObjDesc->CommonField.RegionObj;
317     Address = RgnDesc->Region.Address
318                 + ObjDesc->CommonField.BaseByteOffset
319                 + FieldDatumByteOffset;
320
321     if ((Function & ACPI_IO_MASK) == ACPI_READ)
322     {
323         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
324     }
325     else
326     {
327         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
328     }
329
330     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
331         " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
332         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
333         RgnDesc->Region.SpaceId,
334         ObjDesc->CommonField.AccessByteWidth,
335         ObjDesc->CommonField.BaseByteOffset,
336         FieldDatumByteOffset,
337         ACPI_FORMAT_UINT64 (Address)));
338
339     /* Invoke the appropriate AddressSpace/OpRegion handler */
340
341     Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function,
342                     Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
343
344     if (ACPI_FAILURE (Status))
345     {
346         if (Status == AE_NOT_IMPLEMENTED)
347         {
348             ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
349                 "Region %s(%X) not implemented\n",
350                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
351                 RgnDesc->Region.SpaceId));
352         }
353         else if (Status == AE_NOT_EXIST)
354         {
355             ACPI_REPORT_ERROR ((
356                 "Region %s(%X) has no handler\n",
357                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
358                 RgnDesc->Region.SpaceId));
359         }
360     }
361
362     return_ACPI_STATUS (Status);
363 }
364
365
366 /*******************************************************************************
367  *
368  * FUNCTION:    AcpiExRegisterOverflow
369  *
370  * PARAMETERS:  *ObjDesc                - Register(Field) to be written
371  *              Value                   - Value to be stored
372  *
373  * RETURN:      TRUE if value overflows the field, FALSE otherwise
374  *
375  * DESCRIPTION: Check if a value is out of range of the field being written.
376  *              Used to check if the values written to Index and Bank registers
377  *              are out of range.  Normally, the value is simply truncated
378  *              to fit the field, but this case is most likely a serious
379  *              coding error in the ASL.
380  *
381  ******************************************************************************/
382
383 BOOLEAN
384 AcpiExRegisterOverflow (
385     ACPI_OPERAND_OBJECT     *ObjDesc,
386     ACPI_INTEGER            Value)
387 {
388
389     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
390     {
391         /*
392          * The field is large enough to hold the maximum integer, so we can
393          * never overflow it.
394          */
395         return (FALSE);
396     }
397
398     if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
399     {
400         /*
401          * The Value is larger than the maximum value that can fit into
402          * the register.
403          */
404         return (TRUE);
405     }
406
407     /* The Value will fit into the field with no truncation */
408
409     return (FALSE);
410 }
411
412
413 /*******************************************************************************
414  *
415  * FUNCTION:    AcpiExFieldDatumIo
416  *
417  * PARAMETERS:  *ObjDesc                - Field to be read
418  *              FieldDatumByteOffset    - Byte offset of this datum within the
419  *                                        parent field
420  *              *Value                  - Where to store value (must be 64 bits)
421  *              ReadWrite               - Read or Write flag
422  *
423  * RETURN:      Status
424  *
425  * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
426  *              demultiplexed here to handle the different types of fields
427  *              (BufferField, RegionField, IndexField, BankField)
428  *
429  ******************************************************************************/
430
431 ACPI_STATUS
432 AcpiExFieldDatumIo (
433     ACPI_OPERAND_OBJECT     *ObjDesc,
434     UINT32                  FieldDatumByteOffset,
435     ACPI_INTEGER            *Value,
436     UINT32                  ReadWrite)
437 {
438     ACPI_STATUS             Status;
439     ACPI_INTEGER            LocalValue;
440
441
442     ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
443
444
445     if (ReadWrite == ACPI_READ)
446     {
447         if (!Value)
448         {
449             LocalValue = 0;
450             Value = &LocalValue;  /* To support reads without saving return value */
451         }
452
453         /* Clear the entire return buffer first, [Very Important!] */
454
455         *Value = 0;
456     }
457
458     /*
459      * The four types of fields are:
460      *
461      * BufferField - Read/write from/to a Buffer
462      * RegionField - Read/write from/to a Operation Region.
463      * BankField   - Write to a Bank Register, then read/write from/to an OpRegion
464      * IndexField  - Write to an Index Register, then read/write from/to a Data Register
465      */
466     switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
467     {
468     case ACPI_TYPE_BUFFER_FIELD:
469         /*
470          * If the BufferField arguments have not been previously evaluated,
471          * evaluate them now and save the results.
472          */
473         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
474         {
475             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
476             if (ACPI_FAILURE (Status))
477             {
478                 return_ACPI_STATUS (Status);
479             }
480         }
481
482         if (ReadWrite == ACPI_READ)
483         {
484             /*
485              * Copy the data from the source buffer.
486              * Length is the field width in bytes.
487              */
488             ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
489                             + ObjDesc->BufferField.BaseByteOffset
490                             + FieldDatumByteOffset,
491                             ObjDesc->CommonField.AccessByteWidth);
492         }
493         else
494         {
495             /*
496              * Copy the data to the target buffer.
497              * Length is the field width in bytes.
498              */
499             ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
500                     + ObjDesc->BufferField.BaseByteOffset
501                     + FieldDatumByteOffset,
502                     Value, ObjDesc->CommonField.AccessByteWidth);
503         }
504
505         Status = AE_OK;
506         break;
507
508
509     case ACPI_TYPE_LOCAL_BANK_FIELD:
510
511         /* Ensure that the BankValue is not beyond the capacity of the register */
512
513         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
514                                     (ACPI_INTEGER) ObjDesc->BankField.Value))
515         {
516             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
517         }
518
519         /*
520          * For BankFields, we must write the BankValue to the BankRegister
521          * (itself a RegionField) before we can access the data.
522          */
523         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
524                                 &ObjDesc->BankField.Value,
525                                 sizeof (ObjDesc->BankField.Value));
526         if (ACPI_FAILURE (Status))
527         {
528             return_ACPI_STATUS (Status);
529         }
530
531         /*
532          * Now that the Bank has been selected, fall through to the
533          * RegionField case and write the datum to the Operation Region
534          */
535
536         /*lint -fallthrough */
537
538
539     case ACPI_TYPE_LOCAL_REGION_FIELD:
540         /*
541          * For simple RegionFields, we just directly access the owning
542          * Operation Region.
543          */
544         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
545                         ReadWrite);
546         break;
547
548
549     case ACPI_TYPE_LOCAL_INDEX_FIELD:
550
551
552         /* Ensure that the IndexValue is not beyond the capacity of the register */
553
554         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
555                                     (ACPI_INTEGER) ObjDesc->IndexField.Value))
556         {
557             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
558         }
559
560         /* Write the index value to the IndexRegister (itself a RegionField) */
561
562         FieldDatumByteOffset += ObjDesc->IndexField.Value;
563
564         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
565                 "Write to Index Register: Value %8.8X\n",
566                 FieldDatumByteOffset));
567
568         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
569                                 &FieldDatumByteOffset,
570                                 sizeof (FieldDatumByteOffset));
571         if (ACPI_FAILURE (Status))
572         {
573             return_ACPI_STATUS (Status);
574         }
575
576         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
577                 "I/O to Data Register: ValuePtr %p\n",
578                 Value));
579
580         if (ReadWrite == ACPI_READ)
581         {
582             /* Read the datum from the DataRegister */
583
584             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
585                             Value, sizeof (ACPI_INTEGER));
586         }
587         else
588         {
589             /* Write the datum to the DataRegister */
590
591             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
592                             Value, sizeof (ACPI_INTEGER));
593         }
594         break;
595
596
597     default:
598
599         ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n",
600             ACPI_GET_OBJECT_TYPE (ObjDesc)));
601         Status = AE_AML_INTERNAL;
602         break;
603     }
604
605     if (ACPI_SUCCESS (Status))
606     {
607         if (ReadWrite == ACPI_READ)
608         {
609             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n",
610                                 ACPI_FORMAT_UINT64 (*Value),
611                                 ObjDesc->CommonField.AccessByteWidth));
612         }
613         else
614         {
615             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n",
616                                 ACPI_FORMAT_UINT64 (*Value),
617                                 ObjDesc->CommonField.AccessByteWidth));
618         }
619     }
620
621     return_ACPI_STATUS (Status);
622 }
623
624
625 /*******************************************************************************
626  *
627  * FUNCTION:    AcpiExWriteWithUpdateRule
628  *
629  * PARAMETERS:  *ObjDesc            - Field to be set
630  *              Value               - Value to store
631  *
632  * RETURN:      Status
633  *
634  * DESCRIPTION: Apply the field update rule to a field write
635  *
636  ******************************************************************************/
637
638 ACPI_STATUS
639 AcpiExWriteWithUpdateRule (
640     ACPI_OPERAND_OBJECT     *ObjDesc,
641     ACPI_INTEGER            Mask,
642     ACPI_INTEGER            FieldValue,
643     UINT32                  FieldDatumByteOffset)
644 {
645     ACPI_STATUS             Status = AE_OK;
646     ACPI_INTEGER            MergedValue;
647     ACPI_INTEGER            CurrentValue;
648
649
650     ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
651
652
653     /* Start with the new bits  */
654
655     MergedValue = FieldValue;
656
657     /* If the mask is all ones, we don't need to worry about the update rule */
658
659     if (Mask != ACPI_INTEGER_MAX)
660     {
661         /* Decode the update rule */
662
663         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
664         {
665         case AML_FIELD_UPDATE_PRESERVE:
666             /*
667              * Check if update rule needs to be applied (not if mask is all
668              * ones)  The left shift drops the bits we want to ignore.
669              */
670             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
671                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
672             {
673                 /*
674                  * Read the current contents of the byte/word/dword containing
675                  * the field, and merge with the new field value.
676                  */
677                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
678                                 &CurrentValue, ACPI_READ);
679                 if (ACPI_FAILURE (Status))
680                 {
681                     return_ACPI_STATUS (Status);
682                 }
683
684                 MergedValue |= (CurrentValue & ~Mask);
685             }
686             break;
687
688         case AML_FIELD_UPDATE_WRITE_AS_ONES:
689
690             /* Set positions outside the field to all ones */
691
692             MergedValue |= ~Mask;
693             break;
694
695         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
696
697             /* Set positions outside the field to all zeros */
698
699             MergedValue &= Mask;
700             break;
701
702         default:
703
704             ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
705                 "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
706                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
707             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
708         }
709     }
710
711     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
712         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
713         ACPI_FORMAT_UINT64 (Mask),
714         FieldDatumByteOffset,
715         ObjDesc->CommonField.AccessByteWidth,
716         ACPI_FORMAT_UINT64 (FieldValue),
717         ACPI_FORMAT_UINT64 (MergedValue)));
718
719     /* Write the merged value */
720
721     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
722                     &MergedValue, ACPI_WRITE);
723
724     return_ACPI_STATUS (Status);
725 }
726
727
728 /*******************************************************************************
729  *
730  * FUNCTION:    AcpiExGetBufferDatum
731  *
732  * PARAMETERS:  Datum               - Where the Datum is returned
733  *              Buffer              - Raw field buffer
734  *              BufferLength        - Entire length (used for big-endian only)
735  *              ByteGranularity     - 1/2/4/8 Granularity of the field
736  *                                    (aka Datum Size)
737  *              BufferOffset        - Datum offset into the buffer
738  *
739  * RETURN:      none
740  *
741  * DESCRIPTION: Get a datum from the buffer according to the buffer field
742  *              byte granularity
743  *
744  ******************************************************************************/
745
746 void
747 AcpiExGetBufferDatum (
748     ACPI_INTEGER            *Datum,
749     void                    *Buffer,
750     UINT32                  BufferLength,
751     UINT32                  ByteGranularity,
752     UINT32                  BufferOffset)
753 {
754     UINT32                  Index;
755
756
757     ACPI_FUNCTION_TRACE_U32 ("ExGetBufferDatum", ByteGranularity);
758
759
760     /* Get proper index into buffer (handles big/little endian) */
761
762     Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
763
764     /* Move the requested number of bytes */
765
766     switch (ByteGranularity)
767     {
768     case ACPI_FIELD_BYTE_GRANULARITY:
769
770         *Datum = ((UINT8 *) Buffer) [Index];
771         break;
772
773     case ACPI_FIELD_WORD_GRANULARITY:
774
775         ACPI_MOVE_16_TO_64 (Datum, &(((UINT16 *) Buffer) [Index]));
776         break;
777
778     case ACPI_FIELD_DWORD_GRANULARITY:
779
780         ACPI_MOVE_32_TO_64 (Datum, &(((UINT32 *) Buffer) [Index]));
781         break;
782
783     case ACPI_FIELD_QWORD_GRANULARITY:
784
785         ACPI_MOVE_64_TO_64 (Datum, &(((UINT64 *) Buffer) [Index]));
786         break;
787
788     default:
789         /* Should not get here */
790         break;
791     }
792
793     return_VOID;
794 }
795
796
797 /*******************************************************************************
798  *
799  * FUNCTION:    AcpiExSetBufferDatum
800  *
801  * PARAMETERS:  MergedDatum         - Value to store
802  *              Buffer              - Receiving buffer
803  *              BufferLength        - Entire length (used for big-endian only)
804  *              ByteGranularity     - 1/2/4/8 Granularity of the field
805  *                                    (aka Datum Size)
806  *              BufferOffset        - Datum offset into the buffer
807  *
808  * RETURN:      none
809  *
810  * DESCRIPTION: Store the merged datum to the buffer according to the
811  *              byte granularity
812  *
813  ******************************************************************************/
814
815 void
816 AcpiExSetBufferDatum (
817     ACPI_INTEGER            MergedDatum,
818     void                    *Buffer,
819     UINT32                  BufferLength,
820     UINT32                  ByteGranularity,
821     UINT32                  BufferOffset)
822 {
823     UINT32                  Index;
824
825
826     ACPI_FUNCTION_TRACE_U32 ("ExSetBufferDatum", ByteGranularity);
827
828
829     /* Get proper index into buffer (handles big/little endian) */
830
831     Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity);
832
833     /* Move the requested number of bytes */
834
835     switch (ByteGranularity)
836     {
837     case ACPI_FIELD_BYTE_GRANULARITY:
838
839         ((UINT8 *) Buffer) [Index] = (UINT8) MergedDatum;
840         break;
841
842     case ACPI_FIELD_WORD_GRANULARITY:
843
844         ACPI_MOVE_64_TO_16 (&(((UINT16 *) Buffer)[Index]), &MergedDatum);
845         break;
846
847     case ACPI_FIELD_DWORD_GRANULARITY:
848
849         ACPI_MOVE_64_TO_32 (&(((UINT32 *) Buffer)[Index]), &MergedDatum);
850         break;
851
852     case ACPI_FIELD_QWORD_GRANULARITY:
853
854         ACPI_MOVE_64_TO_64 (&(((UINT64 *) Buffer)[Index]), &MergedDatum);
855         break;
856
857     default:
858         /* Should not get here */
859         break;
860     }
861
862     return_VOID;
863 }
864
865
866 /*******************************************************************************
867  *
868  * FUNCTION:    AcpiExCommonBufferSetup
869  *
870  * PARAMETERS:  ObjDesc             - Field object
871  *              BufferLength        - Length of caller's buffer
872  *              DatumCount          - Where the DatumCount is returned
873  *
874  * RETURN:      Status, DatumCount
875  *
876  * DESCRIPTION: Common code to validate the incoming buffer size and compute
877  *              the number of field "datums" that must be read or written.
878  *              A "datum" is the smallest unit that can be read or written
879  *              to the field, it is either 1,2,4, or 8 bytes.
880  *
881  ******************************************************************************/
882
883 ACPI_STATUS
884 AcpiExCommonBufferSetup (
885     ACPI_OPERAND_OBJECT     *ObjDesc,
886     UINT32                  BufferLength,
887     UINT32                  *DatumCount)
888 {
889     UINT32                  ByteFieldLength;
890     UINT32                  ActualByteFieldLength;
891
892
893     ACPI_FUNCTION_TRACE ("ExCommonBufferSetup");
894
895
896     /*
897      * Incoming buffer must be at least as long as the field, we do not
898      * allow "partial" field reads/writes.  We do not care if the buffer is
899      * larger than the field, this typically happens when an integer is
900      * read/written to a field that is actually smaller than an integer.
901      */
902     ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
903                             ObjDesc->CommonField.BitLength);
904     if (ByteFieldLength > BufferLength)
905     {
906         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
907             "Field size %X (bytes) is too large for buffer (%X)\n",
908             ByteFieldLength, BufferLength));
909
910         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
911     }
912
913     /* 
914      * Create "actual" field byte count (minimum number of bytes that
915      * must be read), then convert to datum count (minimum number
916      * of datum-sized units that must be read)
917      */
918     ActualByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (
919                                 ObjDesc->CommonField.StartFieldBitOffset +
920                                 ObjDesc->CommonField.BitLength);
921
922
923     *DatumCount = ACPI_ROUND_UP_TO (ActualByteFieldLength,
924                         ObjDesc->CommonField.AccessByteWidth);
925
926     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
927         "BufferBytes %X, ActualBytes %X, Datums %X, ByteGran %X\n",
928         ByteFieldLength, ActualByteFieldLength,
929         *DatumCount, ObjDesc->CommonField.AccessByteWidth));
930
931     return_ACPI_STATUS (AE_OK);
932 }
933
934
935 /*******************************************************************************
936  *
937  * FUNCTION:    AcpiExExtractFromField
938  *
939  * PARAMETERS:  ObjDesc             - Field to be read
940  *              Buffer              - Where to store the field data
941  *              BufferLength        - Length of Buffer
942  *
943  * RETURN:      Status
944  *
945  * DESCRIPTION: Retrieve the current value of the given field
946  *
947  ******************************************************************************/
948
949 ACPI_STATUS
950 AcpiExExtractFromField (
951     ACPI_OPERAND_OBJECT     *ObjDesc,
952     void                    *Buffer,
953     UINT32                  BufferLength)
954 {
955     ACPI_STATUS             Status;
956     UINT32                  FieldDatumByteOffset;
957     UINT32                  BufferDatumOffset;
958     ACPI_INTEGER            PreviousRawDatum = 0;
959     ACPI_INTEGER            ThisRawDatum = 0;
960     ACPI_INTEGER            MergedDatum = 0;
961     UINT32                  DatumCount;
962     UINT32                  i;
963
964
965     ACPI_FUNCTION_TRACE ("ExExtractFromField");
966
967
968     /* Validate buffer, compute number of datums */
969
970     Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount);
971     if (ACPI_FAILURE (Status))
972     {
973         return_ACPI_STATUS (Status);
974     }
975
976     /*
977      * Clear the caller's buffer (the whole buffer length as given)
978      * This is very important, especially in the cases where the buffer
979      * is longer than the size of the field.
980      */
981     ACPI_MEMSET (Buffer, 0, BufferLength);
982
983     FieldDatumByteOffset = 0;
984     BufferDatumOffset= 0;
985
986     /* Read the entire field */
987
988     for (i = 0; i < DatumCount; i++)
989     {
990         Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
991                         &ThisRawDatum, ACPI_READ);
992         if (ACPI_FAILURE (Status))
993         {
994             return_ACPI_STATUS (Status);
995         }
996
997         /* We might actually be done if the request fits in one datum */
998
999         if ((DatumCount == 1) &&
1000             (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1001         {
1002             /* 1) Shift the valid data bits down to start at bit 0 */
1003
1004             MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1005
1006             /* 2) Mask off any upper unused bits (bits not part of the field) */
1007
1008             if (ObjDesc->CommonField.EndBufferValidBits)
1009             {
1010                 MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
1011             }
1012
1013             /* Store the datum to the caller buffer */
1014
1015             AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1016                     ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1017
1018             return_ACPI_STATUS (AE_OK);
1019         }
1020
1021         /* Special handling for the last datum to ignore extra bits */
1022
1023         if ((i >= (DatumCount -1))           &&
1024             (ObjDesc->CommonField.EndFieldValidBits))
1025         {
1026             /*
1027              * This is the last iteration of the loop.  We need to clear
1028              * any unused bits (bits that are not part of this field) before
1029              * we store the final merged datum into the caller buffer.
1030              */
1031             ThisRawDatum &=
1032                 ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1033         }
1034
1035         /*
1036          * Create the (possibly) merged datum to be stored to the caller buffer
1037          */
1038         if (ObjDesc->CommonField.StartFieldBitOffset == 0)
1039         {
1040             /* Field is not skewed and we can just copy the datum */
1041
1042             AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength,
1043                     ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1044             BufferDatumOffset++;
1045         }
1046         else
1047         {
1048             /* Not aligned -- on the first iteration, just save the datum */
1049
1050             if (i != 0)
1051             {
1052                 /*
1053                  * Put together the appropriate bits of the two raw data to make a
1054                  * single complete field datum
1055                  *
1056                  * 1) Normalize the first datum down to bit 0
1057                  */
1058                 MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1059
1060                 /* 2) Insert the second datum "above" the first datum */
1061
1062                 MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
1063
1064                 AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1065                         ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1066                 BufferDatumOffset++;
1067             }
1068
1069             /*
1070              * Save the raw datum that was just acquired since it may contain bits
1071              * of the *next* field datum
1072              */
1073             PreviousRawDatum = ThisRawDatum;
1074         }
1075
1076         FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1077     }
1078
1079     /* For non-aligned case, there is one last datum to insert */
1080
1081     if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1082     {
1083         MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
1084
1085         AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength,
1086                 ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset);
1087     }
1088
1089     return_ACPI_STATUS (AE_OK);
1090 }
1091
1092
1093 /*******************************************************************************
1094  *
1095  * FUNCTION:    AcpiExInsertIntoField
1096  *
1097  * PARAMETERS:  ObjDesc             - Field to be written
1098  *              Buffer              - Data to be written
1099  *              BufferLength        - Length of Buffer
1100  *
1101  * RETURN:      Status
1102  *
1103  * DESCRIPTION: Store the Buffer contents into the given field
1104  *
1105  ******************************************************************************/
1106
1107 ACPI_STATUS
1108 AcpiExInsertIntoField (
1109     ACPI_OPERAND_OBJECT     *ObjDesc,
1110     void                    *Buffer,
1111     UINT32                  BufferLength)
1112 {
1113     ACPI_STATUS             Status;
1114     UINT32                  FieldDatumByteOffset;
1115     UINT32                  DatumOffset;
1116     ACPI_INTEGER            Mask;
1117     ACPI_INTEGER            MergedDatum;
1118     ACPI_INTEGER            PreviousRawDatum;
1119     ACPI_INTEGER            ThisRawDatum;
1120     UINT32                  DatumCount;
1121
1122
1123     ACPI_FUNCTION_TRACE ("ExInsertIntoField");
1124
1125
1126     /* Validate buffer, compute number of datums */
1127
1128     Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount);
1129     if (ACPI_FAILURE (Status))
1130     {
1131         return_ACPI_STATUS (Status);
1132     }
1133
1134     /*
1135      * Break the request into up to three parts (similar to an I/O request):
1136      * 1) non-aligned part at start
1137      * 2) aligned part in middle
1138      * 3) non-aligned part at the end
1139      */
1140     FieldDatumByteOffset = 0;
1141     DatumOffset= 0;
1142
1143     /* Get a single datum from the caller's buffer */
1144
1145     AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength,
1146             ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1147
1148     /*
1149      * Part1:
1150      * Write a partial field datum if field does not begin on a datum boundary
1151      * Note: The code in this section also handles the aligned case
1152      *
1153      * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1154      * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1155      *
1156      * Mask off bits that are "below" the field (if any)
1157      */
1158     Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1159
1160     /* If the field fits in one datum, may need to mask upper bits */
1161
1162     if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1163          ObjDesc->CommonField.EndFieldValidBits)
1164     {
1165         /* There are bits above the field, mask them off also */
1166
1167         Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1168     }
1169
1170     /* Shift and mask the value into the field position */
1171
1172     MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1173     MergedDatum &= Mask;
1174
1175     /* Apply the update rule (if necessary) and write the datum to the field */
1176
1177     Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1178                         FieldDatumByteOffset);
1179     if (ACPI_FAILURE (Status))
1180     {
1181         return_ACPI_STATUS (Status);
1182     }
1183
1184     /* We just wrote the first datum */
1185
1186     DatumOffset++;
1187
1188     /* If the entire field fits within one datum, we are done. */
1189
1190     if ((DatumCount == 1) &&
1191        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1192     {
1193         return_ACPI_STATUS (AE_OK);
1194     }
1195
1196     /*
1197      * Part2:
1198      * Write the aligned data.
1199      *
1200      * We don't need to worry about the update rule for these data, because
1201      * all of the bits in each datum are part of the field.
1202      *
1203      * The last datum must be special cased because it might contain bits
1204      * that are not part of the field -- therefore the "update rule" must be
1205      * applied in Part3 below.
1206      */
1207     while (DatumOffset < DatumCount)
1208     {
1209         FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1210
1211         /*
1212          * Get the next raw buffer datum.  It may contain bits of the previous
1213          * field datum
1214          */
1215         AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength,
1216                 ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1217
1218         /* Create the field datum based on the field alignment */
1219
1220         if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1221         {
1222             /*
1223              * Put together appropriate bits of the two raw buffer data to make
1224              * a single complete field datum
1225              */
1226             MergedDatum =
1227                 (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1228                 (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1229         }
1230         else
1231         {
1232             /* Field began aligned on datum boundary */
1233
1234             MergedDatum = ThisRawDatum;
1235         }
1236
1237         /*
1238          * Special handling for the last datum if the field does NOT end on
1239          * a datum boundary.  Update Rule must be applied to the bits outside
1240          * the field.
1241          */
1242         DatumOffset++;
1243         if ((DatumOffset == DatumCount) &&
1244             (ObjDesc->CommonField.EndFieldValidBits))
1245         {
1246             /*
1247              * If there are dangling non-aligned bits, perform one more merged write
1248              * Else - field is aligned at the end, no need for any more writes
1249              */
1250
1251             /*
1252              * Part3:
1253              * This is the last datum and the field does not end on a datum boundary.
1254              * Build the partial datum and write with the update rule.
1255              *
1256              * Mask off the unused bits above (after) the end-of-field
1257              */
1258             Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1259             MergedDatum &= Mask;
1260
1261             /* Write the last datum with the update rule */
1262
1263             Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1264                                 FieldDatumByteOffset);
1265             if (ACPI_FAILURE (Status))
1266             {
1267                 return_ACPI_STATUS (Status);
1268             }
1269         }
1270         else
1271         {
1272             /* Normal (aligned) case -- write the completed datum */
1273
1274             Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1275                             &MergedDatum, ACPI_WRITE);
1276             if (ACPI_FAILURE (Status))
1277             {
1278                 return_ACPI_STATUS (Status);
1279             }
1280         }
1281
1282         /*
1283          * Save the most recent datum since it may contain bits of the *next*
1284          * field datum.  Update current byte offset.
1285          */
1286         PreviousRawDatum = ThisRawDatum;
1287     }
1288
1289     return_ACPI_STATUS (Status);
1290 }
1291
1292