exfldio.c revision 102550
150397Sobrien/******************************************************************************
250397Sobrien *
3169689Skan * Module Name: exfldio - Aml Field I/O
450397Sobrien *              $Revision: 88 $
518334Speter *
6132718Skan *****************************************************************************/
718334Speter
8132718Skan/******************************************************************************
918334Speter *
1018334Speter * 1. Copyright Notice
1118334Speter *
1218334Speter * Some or all of this work - Copyright (c) 1999 - 2002, Intel Corp.
13132718Skan * All rights reserved.
1418334Speter *
1518334Speter * 2. License
1618334Speter *
1718334Speter * 2.1. This is your license from Intel Corp. under its intellectual property
1818334Speter * rights.  You may have additional license terms from the party that provided
19132718Skan * you this software, covering your right to use that party's intellectual
20169689Skan * property rights.
21169689Skan *
2218334Speter * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
2318334Speter * copy of the source code appearing in this file ("Covered Code") an
2418334Speter * irrevocable, perpetual, worldwide license under Intel's copyrights in the
2518334Speter * base code distributed originally by Intel ("Original Intel Code") to copy,
2618334Speter * make derivatives, distribute, use and display any portion of the Covered
2718334Speter * Code in any form, with the right to sublicense such rights; and
2818334Speter *
2918334Speter * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
30132718Skan * license (with the right to sublicense), under only those claims of Intel
3118334Speter * patents that are infringed by the Original Intel Code, to make, use, sell,
3218334Speter * offer to sell, and import the Covered Code and derivative works thereof
33132718Skan * solely to the minimum extent necessary to exercise the above copyright
3418334Speter * license, and in no event shall the patent license extend to any additions
3518334Speter * to or modifications of the Original Intel Code.  No other license or right
3618334Speter * is granted directly or by implication, estoppel or otherwise;
3718334Speter *
3818334Speter * The above copyright and patent license is granted only if the following
3918334Speter * conditions are met:
4018334Speter *
4118334Speter * 3. Conditions
4218334Speter *
4318334Speter * 3.1. Redistribution of Source with Rights to Further Distribute Source.
4418334Speter * Redistribution of source code of any substantial portion of the Covered
45132718Skan * Code or modification with rights to further distribute source must include
4618334Speter * the above Copyright Notice, the above License, this list of Conditions,
4718334Speter * and the following Disclaimer and Export Compliance provision.  In addition,
4818334Speter * Licensee must cause all Covered Code to which Licensee contributes to
4918334Speter * contain a file documenting the changes Licensee made to create that Covered
5018334Speter * Code and the date of any change.  Licensee must include in that file the
5118334Speter * documentation of any changes made by any predecessor Licensee.  Licensee
5218334Speter * must include a prominent statement that the modification is derived,
5318334Speter * directly or indirectly, from Original Intel Code.
5418334Speter *
5518334Speter * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
5618334Speter * Redistribution of source code of any substantial portion of the Covered
57169689Skan * Code or modification without rights to further distribute source must
5818334Speter * include the following Disclaimer and Export Compliance provision in the
5918334Speter * documentation and/or other materials provided with distribution.  In
60132718Skan * addition, Licensee may not authorize further sublicense of source of any
6118334Speter * portion of the Covered Code, and must include terms to the effect that the
6218334Speter * license from Licensee to its licensee is limited to the intellectual
6318334Speter * property embodied in the software Licensee provides to its licensee, and
6418334Speter * not to intellectual property embodied in modifications its licensee may
6590075Sobrien * make.
6618334Speter *
6718334Speter * 3.3. Redistribution of Executable. Redistribution in executable form of any
6818334Speter * substantial portion of the Covered Code or modification must reproduce the
6918334Speter * above Copyright Notice, and the following Disclaimer and Export Compliance
7018334Speter * provision in the documentation and/or other materials provided with the
7118334Speter * distribution.
7218334Speter *
7318334Speter * 3.4. Intel retains all right, title, and interest in and to the Original
7418334Speter * Intel Code.
75117395Skan *
7618334Speter * 3.5. Neither the name Intel nor any other trademark owned or controlled by
7718334Speter * Intel shall be used in advertising or otherwise to promote the sale, use or
7818334Speter * other dealings in products derived from or relating to the Covered Code
7918334Speter * without prior written authorization from Intel.
8018334Speter *
8118334Speter * 4. Disclaimer and Export Compliance
8218334Speter *
8318334Speter * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
8418334Speter * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
8518334Speter * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
8618334Speter * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
8718334Speter * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
8818334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
8918334Speter * PARTICULAR PURPOSE.
9018334Speter *
9118334Speter * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
9218334Speter * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
9318334Speter * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
9418334Speter * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
9518334Speter * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
9650397Sobrien * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
9718334Speter * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
9818334Speter * LIMITED REMEDY.
9918334Speter *
10018334Speter * 4.3. Licensee shall not export, either directly or indirectly, any of this
10150397Sobrien * software or system incorporating such software without first obtaining any
10250397Sobrien * required license or other approval from the U. S. Department of Commerce or
10318334Speter * any other agency or department of the United States Government.  In the
10418334Speter * event Licensee exports any such software from the United States or
10518334Speter * re-exports any such software from a foreign destination, Licensee shall
10618334Speter * ensure that the distribution and export/re-export of the software is in
10718334Speter * compliance with all laws, regulations, orders, or other restrictions of the
10818334Speter * U.S. Export Administration Regulations. Licensee agrees that neither it nor
10918334Speter * any of its subsidiaries will export/re-export any technical data, process,
11018334Speter * software, or service, directly or indirectly, to any country for which the
11118334Speter * United States government or any agency thereof requires an export license,
11218334Speter * other governmental approval, or letter of assurance, without first obtaining
11318334Speter * such license, approval or letter.
11490075Sobrien *
11518334Speter *****************************************************************************/
11618334Speter
11718334Speter
11818334Speter#define __EXFLDIO_C__
11918334Speter
120117395Skan#include "acpi.h"
12118334Speter#include "acinterp.h"
12218334Speter#include "amlcode.h"
12318334Speter#include "acevents.h"
12418334Speter#include "acdispat.h"
12518334Speter
12618334Speter
12718334Speter#define _COMPONENT          ACPI_EXECUTER
12818334Speter        ACPI_MODULE_NAME    ("exfldio")
12990075Sobrien
13018334Speter
13190075Sobrien/*******************************************************************************
13290075Sobrien *
13318334Speter * FUNCTION:    AcpiExSetupRegion
13418334Speter *
13518334Speter * PARAMETERS:  *ObjDesc                - Field to be read or written
13618334Speter *              FieldDatumByteOffset    - Byte offset of this datum within the
13718334Speter *                                        parent field
13818334Speter *
13918334Speter * RETURN:      Status
14018334Speter *
14118334Speter * DESCRIPTION: Common processing for AcpiExExtractFromField and
14218334Speter *              AcpiExInsertIntoField.  Initialize the
14318334Speter *
14418334Speter ******************************************************************************/
14518334Speter
14618334SpeterACPI_STATUS
14718334SpeterAcpiExSetupRegion (
14818334Speter    ACPI_OPERAND_OBJECT     *ObjDesc,
14918334Speter    UINT32                  FieldDatumByteOffset)
15018334Speter{
15118334Speter    ACPI_STATUS             Status = AE_OK;
15218334Speter    ACPI_OPERAND_OBJECT     *RgnDesc;
15318334Speter
15418334Speter
15518334Speter    ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset);
15618334Speter
15718334Speter
15818334Speter    RgnDesc = ObjDesc->CommonField.RegionObj;
15918334Speter
16018334Speter    if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION)
16118334Speter    {
162        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
163            ACPI_GET_OBJECT_TYPE (RgnDesc),
164            AcpiUtGetObjectTypeName (RgnDesc)));
165
166        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
167    }
168
169    /*
170     * If the Region Address and Length have not been previously evaluated,
171     * evaluate them now and save the results.
172     */
173    if (!(RgnDesc->Region.Flags & AOPOBJ_DATA_VALID))
174    {
175        Status = AcpiDsGetRegionArguments (RgnDesc);
176        if (ACPI_FAILURE (Status))
177        {
178            return_ACPI_STATUS (Status);
179        }
180    }
181
182    /*
183     * Validate the request.  The entire request from the byte offset for a
184     * length of one field datum (access width) must fit within the region.
185     * (Region length is specified in bytes)
186     */
187    if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset
188                                    + FieldDatumByteOffset
189                                    + ObjDesc->CommonField.AccessByteWidth))
190    {
191        if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
192        {
193            /*
194             * This is the case where the AccessType (AccWord, etc.) is wider
195             * than the region itself.  For example, a region of length one
196             * byte, and a field with Dword access specified.
197             */
198            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
199                "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
200                ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.AccessByteWidth,
201                RgnDesc->Region.Node->Name.Ascii, 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 [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
210            ObjDesc->CommonField.Node->Name.Ascii, ObjDesc->CommonField.BaseByteOffset,
211            FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
212            RgnDesc->Region.Node->Name.Ascii, RgnDesc->Region.Length));
213
214        return_ACPI_STATUS (AE_AML_REGION_LIMIT);
215    }
216
217    return_ACPI_STATUS (AE_OK);
218}
219
220
221/*******************************************************************************
222 *
223 * FUNCTION:    AcpiExAccessRegion
224 *
225 * PARAMETERS:  *ObjDesc                - Field to be read
226 *              FieldDatumByteOffset    - Byte offset of this datum within the
227 *                                        parent field
228 *              *Value                  - Where to store value (must be 32 bits)
229 *              ReadWrite               - Read or Write flag
230 *
231 * RETURN:      Status
232 *
233 * DESCRIPTION: Read or Write a single field datum to an Operation Region.
234 *
235 ******************************************************************************/
236
237ACPI_STATUS
238AcpiExAccessRegion (
239    ACPI_OPERAND_OBJECT     *ObjDesc,
240    UINT32                  FieldDatumByteOffset,
241    ACPI_INTEGER            *Value,
242    UINT32                  ReadWrite)
243{
244    ACPI_STATUS             Status;
245    ACPI_OPERAND_OBJECT     *RgnDesc;
246    ACPI_PHYSICAL_ADDRESS   Address;
247
248
249    ACPI_FUNCTION_TRACE ("ExAccessRegion");
250
251
252    /*
253     * The physical address of this field datum is:
254     *
255     * 1) The base of the region, plus
256     * 2) The base offset of the field, plus
257     * 3) The current offset into the field
258     */
259    RgnDesc = ObjDesc->CommonField.RegionObj;
260    Address = RgnDesc->Region.Address
261                + ObjDesc->CommonField.BaseByteOffset
262                + FieldDatumByteOffset;
263
264    if (ReadWrite == ACPI_READ)
265    {
266        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
267    }
268    else
269    {
270        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
271    }
272
273    ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
274        " Region[%s-%X] Access %X Base:Off %X:%X at %8.8X%8.8X\n",
275        AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
276        RgnDesc->Region.SpaceId,
277        ObjDesc->CommonField.AccessByteWidth,
278        ObjDesc->CommonField.BaseByteOffset,
279        FieldDatumByteOffset,
280        ACPI_HIDWORD (Address), ACPI_LODWORD (Address)));
281
282    /* Invoke the appropriate AddressSpace/OpRegion handler */
283
284    Status = AcpiEvAddressSpaceDispatch (RgnDesc, ReadWrite,
285                    Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
286
287    if (ACPI_FAILURE (Status))
288    {
289        if (Status == AE_NOT_IMPLEMENTED)
290        {
291            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
292                "Region %s(%X) not implemented\n",
293                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
294                RgnDesc->Region.SpaceId));
295        }
296
297        else if (Status == AE_NOT_EXIST)
298        {
299            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
300                "Region %s(%X) has no handler\n",
301                AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
302                RgnDesc->Region.SpaceId));
303        }
304    }
305
306    return_ACPI_STATUS (Status);
307}
308
309
310/*******************************************************************************
311 *
312 * FUNCTION:    AcpiExRegisterOverflow
313 *
314 * PARAMETERS:  *ObjDesc                - Register(Field) to be written
315 *              Value                   - Value to be stored
316 *
317 * RETURN:      TRUE if value overflows the field, FALSE otherwise
318 *
319 * DESCRIPTION: Check if a value is out of range of the field being written.
320 *              Used to check if the values written to Index and Bank registers
321 *              are out of range.  Normally, the value is simply truncated
322 *              to fit the field, but this case is most likely a serious
323 *              coding error in the ASL.
324 *
325 ******************************************************************************/
326
327BOOLEAN
328AcpiExRegisterOverflow (
329    ACPI_OPERAND_OBJECT     *ObjDesc,
330    ACPI_INTEGER            Value)
331{
332
333    if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
334    {
335        /*
336         * The field is large enough to hold the maximum integer, so we can
337         * never overflow it.
338         */
339        return (FALSE);
340    }
341
342    if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
343    {
344        /*
345         * The Value is larger than the maximum value that can fit into
346         * the register.
347         */
348        return (TRUE);
349    }
350
351    /* The Value will fit into the field with no truncation */
352
353    return (FALSE);
354}
355
356
357/*******************************************************************************
358 *
359 * FUNCTION:    AcpiExFieldDatumIo
360 *
361 * PARAMETERS:  *ObjDesc                - Field to be read
362 *              FieldDatumByteOffset    - Byte offset of this datum within the
363 *                                        parent field
364 *              *Value                  - Where to store value (must be 64 bits)
365 *              ReadWrite               - Read or Write flag
366 *
367 * RETURN:      Status
368 *
369 * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
370 *              demultiplexed here to handle the different types of fields
371 *              (BufferField, RegionField, IndexField, BankField)
372 *
373 ******************************************************************************/
374
375ACPI_STATUS
376AcpiExFieldDatumIo (
377    ACPI_OPERAND_OBJECT     *ObjDesc,
378    UINT32                  FieldDatumByteOffset,
379    ACPI_INTEGER            *Value,
380    UINT32                  ReadWrite)
381{
382    ACPI_STATUS             Status;
383    ACPI_INTEGER            LocalValue;
384
385
386    ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset);
387
388
389    if (ReadWrite == ACPI_READ)
390    {
391        if (!Value)
392        {
393            LocalValue = 0;
394            Value = &LocalValue;  /* To support reads without saving return value */
395        }
396
397        /* Clear the entire return buffer first, [Very Important!] */
398
399        *Value = 0;
400    }
401
402    /*
403     * The four types of fields are:
404     *
405     * BufferFields - Read/write from/to a Buffer
406     * RegionFields - Read/write from/to a Operation Region.
407     * BankFields   - Write to a Bank Register, then read/write from/to an OpRegion
408     * IndexFields  - Write to an Index Register, then read/write from/to a Data Register
409     */
410    switch (ACPI_GET_OBJECT_TYPE (ObjDesc))
411    {
412    case ACPI_TYPE_BUFFER_FIELD:
413        /*
414         * If the BufferField arguments have not been previously evaluated,
415         * evaluate them now and save the results.
416         */
417        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
418        {
419            Status = AcpiDsGetBufferFieldArguments (ObjDesc);
420            if (ACPI_FAILURE (Status))
421            {
422                return_ACPI_STATUS (Status);
423            }
424        }
425
426        if (ReadWrite == ACPI_READ)
427        {
428            /*
429             * Copy the data from the source buffer.
430             * Length is the field width in bytes.
431             */
432            ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer
433                            + ObjDesc->BufferField.BaseByteOffset
434                            + FieldDatumByteOffset,
435                            ObjDesc->CommonField.AccessByteWidth);
436        }
437        else
438        {
439            /*
440             * Copy the data to the target buffer.
441             * Length is the field width in bytes.
442             */
443            ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer
444                    + ObjDesc->BufferField.BaseByteOffset
445                    + FieldDatumByteOffset,
446                    Value, ObjDesc->CommonField.AccessByteWidth);
447        }
448
449        Status = AE_OK;
450        break;
451
452
453    case INTERNAL_TYPE_BANK_FIELD:
454
455        /* Ensure that the BankValue is not beyond the capacity of the register */
456
457        if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
458                                    (ACPI_INTEGER) ObjDesc->BankField.Value))
459        {
460            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
461        }
462
463        /*
464         * For BankFields, we must write the BankValue to the BankRegister
465         * (itself a RegionField) before we can access the data.
466         */
467        Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
468                                &ObjDesc->BankField.Value,
469                                sizeof (ObjDesc->BankField.Value));
470        if (ACPI_FAILURE (Status))
471        {
472            return_ACPI_STATUS (Status);
473        }
474
475        /*
476         * Now that the Bank has been selected, fall through to the
477         * RegionField case and write the datum to the Operation Region
478         */
479
480        /*lint -fallthrough */
481
482
483    case INTERNAL_TYPE_REGION_FIELD:
484        /*
485         * For simple RegionFields, we just directly access the owning
486         * Operation Region.
487         */
488        Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
489        if (ACPI_FAILURE (Status))
490        {
491            return_ACPI_STATUS (Status);
492        }
493
494        Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
495                        ReadWrite);
496        break;
497
498
499    case INTERNAL_TYPE_INDEX_FIELD:
500
501
502        /* Ensure that the IndexValue is not beyond the capacity of the register */
503
504        if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
505                                    (ACPI_INTEGER) ObjDesc->IndexField.Value))
506        {
507            return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
508        }
509
510        /* Write the index value to the IndexRegister (itself a RegionField) */
511
512        Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
513                                &ObjDesc->IndexField.Value,
514                                sizeof (ObjDesc->IndexField.Value));
515        if (ACPI_FAILURE (Status))
516        {
517            return_ACPI_STATUS (Status);
518        }
519
520        if (ReadWrite == ACPI_READ)
521        {
522            /* Read the datum from the DataRegister */
523
524            Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
525                            Value, ObjDesc->CommonField.AccessByteWidth);
526        }
527        else
528        {
529            /* Write the datum to the Data register */
530
531            Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
532                            Value, ObjDesc->CommonField.AccessByteWidth);
533        }
534        break;
535
536
537    default:
538
539        ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, Wrong object type - %s\n",
540            ObjDesc, AcpiUtGetObjectTypeName (ObjDesc)));
541        Status = AE_AML_INTERNAL;
542        break;
543    }
544
545    if (ACPI_SUCCESS (Status))
546    {
547        if (ReadWrite == ACPI_READ)
548        {
549            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read=%8.8X%8.8X\n",
550                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
551        }
552        else
553        {
554            ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written=%8.8X%8.8X\n",
555                                ACPI_HIDWORD (*Value), ACPI_LODWORD (*Value)));
556        }
557    }
558
559    return_ACPI_STATUS (Status);
560}
561
562
563/*******************************************************************************
564 *
565 * FUNCTION:    AcpiExWriteWithUpdateRule
566 *
567 * PARAMETERS:  *ObjDesc            - Field to be set
568 *              Value               - Value to store
569 *
570 * RETURN:      Status
571 *
572 * DESCRIPTION: Apply the field update rule to a field write
573 *
574 ******************************************************************************/
575
576ACPI_STATUS
577AcpiExWriteWithUpdateRule (
578    ACPI_OPERAND_OBJECT     *ObjDesc,
579    ACPI_INTEGER            Mask,
580    ACPI_INTEGER            FieldValue,
581    UINT32                  FieldDatumByteOffset)
582{
583    ACPI_STATUS             Status = AE_OK;
584    ACPI_INTEGER            MergedValue;
585    ACPI_INTEGER            CurrentValue;
586
587
588    ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask);
589
590
591    /* Start with the new bits  */
592
593    MergedValue = FieldValue;
594
595    /* If the mask is all ones, we don't need to worry about the update rule */
596
597    if (Mask != ACPI_INTEGER_MAX)
598    {
599        /* Decode the update rule */
600
601        switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
602        {
603        case AML_FIELD_UPDATE_PRESERVE:
604            /*
605             * Check if update rule needs to be applied (not if mask is all
606             * ones)  The left shift drops the bits we want to ignore.
607             */
608            if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
609                           ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
610            {
611                /*
612                 * Read the current contents of the byte/word/dword containing
613                 * the field, and merge with the new field value.
614                 */
615                Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
616                                &CurrentValue, ACPI_READ);
617                MergedValue |= (CurrentValue & ~Mask);
618            }
619            break;
620
621        case AML_FIELD_UPDATE_WRITE_AS_ONES:
622
623            /* Set positions outside the field to all ones */
624
625            MergedValue |= ~Mask;
626            break;
627
628        case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
629
630            /* Set positions outside the field to all zeros */
631
632            MergedValue &= Mask;
633            break;
634
635        default:
636            ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
637                "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n",
638                (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
639            return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
640        }
641    }
642
643    /* Write the merged value */
644
645    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
646                    &MergedValue, ACPI_WRITE);
647
648    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
649        "Mask %8.8X%8.8X DatumOffset %X Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
650        ACPI_HIDWORD (Mask), ACPI_LODWORD (Mask),
651        FieldDatumByteOffset,
652        ACPI_HIDWORD (FieldValue), ACPI_LODWORD (FieldValue),
653        ACPI_HIDWORD (MergedValue),ACPI_LODWORD (MergedValue)));
654
655    return_ACPI_STATUS (Status);
656}
657
658
659/*******************************************************************************
660 *
661 * FUNCTION:    AcpiExGetBufferDatum
662 *
663 * PARAMETERS:  Datum               - Where the Datum is returned
664 *              Buffer              - Raw field buffer
665 *              ByteGranularity     - 1/2/4/8 Granularity of the field
666 *                                    (aka Datum Size)
667 *              Offset              - Datum offset into the buffer
668 *
669 * RETURN:      none
670 *
671 * DESCRIPTION: Get a datum from the buffer according to the buffer field
672 *              byte granularity
673 *
674 ******************************************************************************/
675
676void
677AcpiExGetBufferDatum(
678    ACPI_INTEGER            *Datum,
679    void                    *Buffer,
680    UINT32                  ByteGranularity,
681    UINT32                  Offset)
682{
683
684    ACPI_FUNCTION_ENTRY ();
685
686
687    switch (ByteGranularity)
688    {
689    case ACPI_FIELD_BYTE_GRANULARITY:
690
691        *Datum = ((UINT8 *) Buffer) [Offset];
692        break;
693
694    case ACPI_FIELD_WORD_GRANULARITY:
695
696        ACPI_MOVE_UNALIGNED16_TO_32 (Datum, &(((UINT16 *) Buffer) [Offset]));
697        break;
698
699    case ACPI_FIELD_DWORD_GRANULARITY:
700
701        ACPI_MOVE_UNALIGNED32_TO_32 (Datum, &(((UINT32 *) Buffer) [Offset]));
702        break;
703
704    case ACPI_FIELD_QWORD_GRANULARITY:
705
706        ACPI_MOVE_UNALIGNED64_TO_64 (Datum, &(((UINT64 *) Buffer) [Offset]));
707        break;
708
709    default:
710        /* Should not get here */
711        break;
712    }
713}
714
715
716/*******************************************************************************
717 *
718 * FUNCTION:    AcpiExSetBufferDatum
719 *
720 * PARAMETERS:  MergedDatum         - Value to store
721 *              Buffer              - Receiving buffer
722 *              ByteGranularity     - 1/2/4/8 Granularity of the field
723 *                                    (aka Datum Size)
724 *              Offset              - Datum offset into the buffer
725 *
726 * RETURN:      none
727 *
728 * DESCRIPTION: Store the merged datum to the buffer according to the
729 *              byte granularity
730 *
731 ******************************************************************************/
732
733void
734AcpiExSetBufferDatum (
735    ACPI_INTEGER            MergedDatum,
736    void                    *Buffer,
737    UINT32                  ByteGranularity,
738    UINT32                  Offset)
739{
740
741    ACPI_FUNCTION_ENTRY ();
742
743
744    switch (ByteGranularity)
745    {
746    case ACPI_FIELD_BYTE_GRANULARITY:
747
748        ((UINT8 *) Buffer) [Offset] = (UINT8) MergedDatum;
749        break;
750
751    case ACPI_FIELD_WORD_GRANULARITY:
752
753        ACPI_MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[Offset]), &MergedDatum);
754        break;
755
756    case ACPI_FIELD_DWORD_GRANULARITY:
757
758        ACPI_MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[Offset]), &MergedDatum);
759        break;
760
761    case ACPI_FIELD_QWORD_GRANULARITY:
762
763        ACPI_MOVE_UNALIGNED64_TO_64 (&(((UINT64 *) Buffer)[Offset]), &MergedDatum);
764        break;
765
766    default:
767        /* Should not get here */
768        break;
769    }
770}
771
772
773/*******************************************************************************
774 *
775 * FUNCTION:    AcpiExExtractFromField
776 *
777 * PARAMETERS:  *ObjDesc            - Field to be read
778 *              *Value              - Where to store value
779 *
780 * RETURN:      Status
781 *
782 * DESCRIPTION: Retrieve the value of the given field
783 *
784 ******************************************************************************/
785
786ACPI_STATUS
787AcpiExExtractFromField (
788    ACPI_OPERAND_OBJECT     *ObjDesc,
789    void                    *Buffer,
790    UINT32                  BufferLength)
791{
792    ACPI_STATUS             Status;
793    UINT32                  FieldDatumByteOffset;
794    UINT32                  DatumOffset;
795    ACPI_INTEGER            PreviousRawDatum;
796    ACPI_INTEGER            ThisRawDatum = 0;
797    ACPI_INTEGER            MergedDatum = 0;
798    UINT32                  ByteFieldLength;
799    UINT32                  DatumCount;
800
801
802    ACPI_FUNCTION_TRACE ("ExExtractFromField");
803
804
805    /*
806     * The field must fit within the caller's buffer
807     */
808    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
809    if (ByteFieldLength > BufferLength)
810    {
811        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
812            "Field size %X (bytes) too large for buffer (%X)\n",
813            ByteFieldLength, BufferLength));
814
815        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
816    }
817
818    /* Convert field byte count to datum count, round up if necessary */
819
820    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength,
821                              ObjDesc->CommonField.AccessByteWidth);
822
823    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
824        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
825        ByteFieldLength, DatumCount,ObjDesc->CommonField.AccessByteWidth));
826
827    /*
828     * Clear the caller's buffer (the whole buffer length as given)
829     * This is very important, especially in the cases where a byte is read,
830     * but the buffer is really a UINT32 (4 bytes).
831     */
832    ACPI_MEMSET (Buffer, 0, BufferLength);
833
834    /* Read the first raw datum to prime the loop */
835
836    FieldDatumByteOffset = 0;
837    DatumOffset= 0;
838
839    Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
840                    &PreviousRawDatum, ACPI_READ);
841    if (ACPI_FAILURE (Status))
842    {
843        return_ACPI_STATUS (Status);
844    }
845
846
847    /* We might actually be done if the request fits in one datum */
848
849    if ((DatumCount == 1) &&
850        (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
851    {
852        /* 1) Shift the valid data bits down to start at bit 0 */
853
854        MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
855
856        /* 2) Mask off any upper unused bits (bits not part of the field) */
857
858        if (ObjDesc->CommonField.EndBufferValidBits)
859        {
860            MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
861        }
862
863        /* Store the datum to the caller buffer */
864
865        AcpiExSetBufferDatum (MergedDatum, Buffer, ObjDesc->CommonField.AccessByteWidth,
866                DatumOffset);
867
868        return_ACPI_STATUS (AE_OK);
869    }
870
871
872    /* We need to get more raw data to complete one or more field data */
873
874    while (DatumOffset < DatumCount)
875    {
876        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
877
878        /*
879         * If the field is aligned on a byte boundary, we don't want
880         * to perform a final read, since this would potentially read
881         * past the end of the region.
882         *
883         * We could just split the aligned and non-aligned cases since the
884         * aligned case is so very simple, but this would require more code.
885         */
886        if ((ObjDesc->CommonField.StartFieldBitOffset != 0)  ||
887            ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
888            (DatumOffset < (DatumCount -1))))
889        {
890            /*
891             * Get the next raw datum, it contains some or all bits
892             * of the current field datum
893             */
894            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
895                            &ThisRawDatum, ACPI_READ);
896            if (ACPI_FAILURE (Status))
897            {
898                return_ACPI_STATUS (Status);
899            }
900        }
901
902        /*
903         * Create the (possibly) merged datum to be stored to the caller buffer
904         */
905        if (ObjDesc->CommonField.StartFieldBitOffset == 0)
906        {
907            /* Field is not skewed and we can just copy the datum */
908
909            MergedDatum = PreviousRawDatum;
910        }
911        else
912        {
913            /*
914             * Put together the appropriate bits of the two raw data to make a
915             * single complete field datum
916             *
917             * 1) Normalize the first datum down to bit 0
918             */
919            MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset);
920
921            /* 2) Insert the second datum "above" the first datum */
922
923            MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits);
924
925            if ((DatumOffset >= (DatumCount -1)))
926            {
927                /*
928                 * This is the last iteration of the loop.  We need to clear
929                 * any unused bits (bits that are not part of this field) that
930                 * came from the last raw datum before we store the final
931                 * merged datum into the caller buffer.
932                 */
933                if (ObjDesc->CommonField.EndBufferValidBits)
934                {
935                    MergedDatum &=
936                        ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits);
937                }
938            }
939        }
940
941        /*
942         * Store the merged field datum in the caller's buffer, according to
943         * the granularity of the field (size of each datum).
944         */
945        AcpiExSetBufferDatum (MergedDatum, Buffer,
946                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
947
948        /*
949         * Save the raw datum that was just acquired since it may contain bits
950         * of the *next* field datum.  Update offsets
951         */
952        PreviousRawDatum = ThisRawDatum;
953        DatumOffset++;
954    }
955
956    return_ACPI_STATUS (AE_OK);
957}
958
959
960/*******************************************************************************
961 *
962 * FUNCTION:    AcpiExInsertIntoField
963 *
964 * PARAMETERS:  *ObjDesc            - Field to be set
965 *              Buffer              - Value to store
966 *
967 * RETURN:      Status
968 *
969 * DESCRIPTION: Store the value into the given field
970 *
971 ******************************************************************************/
972
973ACPI_STATUS
974AcpiExInsertIntoField (
975    ACPI_OPERAND_OBJECT     *ObjDesc,
976    void                    *Buffer,
977    UINT32                  BufferLength)
978{
979    ACPI_STATUS             Status;
980    UINT32                  FieldDatumByteOffset;
981    UINT32                  DatumOffset;
982    ACPI_INTEGER            Mask;
983    ACPI_INTEGER            MergedDatum;
984    ACPI_INTEGER            PreviousRawDatum;
985    ACPI_INTEGER            ThisRawDatum;
986    UINT32                  ByteFieldLength;
987    UINT32                  DatumCount;
988
989
990    ACPI_FUNCTION_TRACE ("ExInsertIntoField");
991
992
993    /*
994     * Incoming buffer must be at least as long as the field, we do not
995     * allow "partial" field writes.  We do not care if the buffer is
996     * larger than the field, this typically happens when an integer is
997     * written to a field that is actually smaller than an integer.
998     */
999    ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength);
1000    if (BufferLength < ByteFieldLength)
1001    {
1002        ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Buffer length %X too small for field %X\n",
1003            BufferLength, ByteFieldLength));
1004
1005        return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
1006    }
1007
1008    /* Convert byte count to datum count, round up if necessary */
1009
1010    DatumCount = ACPI_ROUND_UP_TO (ByteFieldLength, ObjDesc->CommonField.AccessByteWidth);
1011
1012    ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
1013        "ByteLen=%X, DatumLen=%X, ByteGran=%X\n",
1014        ByteFieldLength, DatumCount, ObjDesc->CommonField.AccessByteWidth));
1015
1016    /*
1017     * Break the request into up to three parts (similar to an I/O request):
1018     * 1) non-aligned part at start
1019     * 2) aligned part in middle
1020     * 3) non-aligned part at the end
1021     */
1022    FieldDatumByteOffset = 0;
1023    DatumOffset= 0;
1024
1025    /* Get a single datum from the caller's buffer */
1026
1027    AcpiExGetBufferDatum (&PreviousRawDatum, Buffer,
1028            ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1029
1030    /*
1031     * Part1:
1032     * Write a partial field datum if field does not begin on a datum boundary
1033     * Note: The code in this section also handles the aligned case
1034     *
1035     * Construct Mask with 1 bits where the field is, 0 bits elsewhere
1036     * (Only the bottom 5 bits of BitLength are valid for a shift operation)
1037     *
1038     * Mask off bits that are "below" the field (if any)
1039     */
1040    Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
1041
1042    /* If the field fits in one datum, may need to mask upper bits */
1043
1044    if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) &&
1045         ObjDesc->CommonField.EndFieldValidBits)
1046    {
1047        /* There are bits above the field, mask them off also */
1048
1049        Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1050    }
1051
1052    /* Shift and mask the value into the field position */
1053
1054    MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1055    MergedDatum &= Mask;
1056
1057    /* Apply the update rule (if necessary) and write the datum to the field */
1058
1059    Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1060                        FieldDatumByteOffset);
1061    if (ACPI_FAILURE (Status))
1062    {
1063        return_ACPI_STATUS (Status);
1064    }
1065
1066    /* If the entire field fits within one datum, we are done. */
1067
1068    if ((DatumCount == 1) &&
1069       (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM))
1070    {
1071        return_ACPI_STATUS (AE_OK);
1072    }
1073
1074    /*
1075     * Part2:
1076     * Write the aligned data.
1077     *
1078     * We don't need to worry about the update rule for these data, because
1079     * all of the bits in each datum are part of the field.
1080     *
1081     * The last datum must be special cased because it might contain bits
1082     * that are not part of the field -- therefore the "update rule" must be
1083     * applied in Part3 below.
1084     */
1085    while (DatumOffset < DatumCount)
1086    {
1087        DatumOffset++;
1088        FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth;
1089
1090        /*
1091         * Get the next raw buffer datum.  It may contain bits of the previous
1092         * field datum
1093         */
1094        AcpiExGetBufferDatum (&ThisRawDatum, Buffer,
1095                ObjDesc->CommonField.AccessByteWidth, DatumOffset);
1096
1097        /* Create the field datum based on the field alignment */
1098
1099        if (ObjDesc->CommonField.StartFieldBitOffset != 0)
1100        {
1101            /*
1102             * Put together appropriate bits of the two raw buffer data to make
1103             * a single complete field datum
1104             */
1105            MergedDatum =
1106                (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) |
1107                (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset);
1108        }
1109        else
1110        {
1111            /* Field began aligned on datum boundary */
1112
1113            MergedDatum = ThisRawDatum;
1114        }
1115
1116        /*
1117         * Special handling for the last datum if the field does NOT end on
1118         * a datum boundary.  Update Rule must be applied to the bits outside
1119         * the field.
1120         */
1121        if (DatumOffset == DatumCount)
1122        {
1123            /*
1124             * If there are dangling non-aligned bits, perform one more merged write
1125             * Else - field is aligned at the end, no need for any more writes
1126             */
1127            if (ObjDesc->CommonField.EndFieldValidBits)
1128            {
1129                /*
1130                 * Part3:
1131                 * This is the last datum and the field does not end on a datum boundary.
1132                 * Build the partial datum and write with the update rule.
1133                 *
1134                 * Mask off the unused bits above (after) the end-of-field
1135                 */
1136                Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits);
1137                MergedDatum &= Mask;
1138
1139                /* Write the last datum with the update rule */
1140
1141                Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum,
1142                                    FieldDatumByteOffset);
1143                if (ACPI_FAILURE (Status))
1144                {
1145                    return_ACPI_STATUS (Status);
1146                }
1147            }
1148        }
1149        else
1150        {
1151            /* Normal case -- write the completed datum */
1152
1153            Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
1154                            &MergedDatum, ACPI_WRITE);
1155            if (ACPI_FAILURE (Status))
1156            {
1157                return_ACPI_STATUS (Status);
1158            }
1159        }
1160
1161        /*
1162         * Save the most recent datum since it may contain bits of the *next*
1163         * field datum.  Update current byte offset.
1164         */
1165        PreviousRawDatum = ThisRawDatum;
1166    }
1167
1168    return_ACPI_STATUS (Status);
1169}
1170
1171
1172