Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/acpica/exfldio.c need to be fixed.

0001 /******************************************************************************
0002  *
0003  * Module Name: exfldio - Aml Field I/O
0004  *
0005  *****************************************************************************/
0006 
0007 /******************************************************************************
0008  *
0009  * 1. Copyright Notice
0010  *
0011  * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp.
0012  * All rights reserved.
0013  *
0014  * 2. License
0015  *
0016  * 2.1. This is your license from Intel Corp. under its intellectual property
0017  * rights.  You may have additional license terms from the party that provided
0018  * you this software, covering your right to use that party's intellectual
0019  * property rights.
0020  *
0021  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
0022  * copy of the source code appearing in this file ("Covered Code") an
0023  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
0024  * base code distributed originally by Intel ("Original Intel Code") to copy,
0025  * make derivatives, distribute, use and display any portion of the Covered
0026  * Code in any form, with the right to sublicense such rights; and
0027  *
0028  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
0029  * license (with the right to sublicense), under only those claims of Intel
0030  * patents that are infringed by the Original Intel Code, to make, use, sell,
0031  * offer to sell, and import the Covered Code and derivative works thereof
0032  * solely to the minimum extent necessary to exercise the above copyright
0033  * license, and in no event shall the patent license extend to any additions
0034  * to or modifications of the Original Intel Code.  No other license or right
0035  * is granted directly or by implication, estoppel or otherwise;
0036  *
0037  * The above copyright and patent license is granted only if the following
0038  * conditions are met:
0039  *
0040  * 3. Conditions
0041  *
0042  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
0043  * Redistribution of source code of any substantial portion of the Covered
0044  * Code or modification with rights to further distribute source must include
0045  * the above Copyright Notice, the above License, this list of Conditions,
0046  * and the following Disclaimer and Export Compliance provision.  In addition,
0047  * Licensee must cause all Covered Code to which Licensee contributes to
0048  * contain a file documenting the changes Licensee made to create that Covered
0049  * Code and the date of any change.  Licensee must include in that file the
0050  * documentation of any changes made by any predecessor Licensee.  Licensee
0051  * must include a prominent statement that the modification is derived,
0052  * directly or indirectly, from Original Intel Code.
0053  *
0054  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
0055  * Redistribution of source code of any substantial portion of the Covered
0056  * Code or modification without rights to further distribute source must
0057  * include the following Disclaimer and Export Compliance provision in the
0058  * documentation and/or other materials provided with distribution.  In
0059  * addition, Licensee may not authorize further sublicense of source of any
0060  * portion of the Covered Code, and must include terms to the effect that the
0061  * license from Licensee to its licensee is limited to the intellectual
0062  * property embodied in the software Licensee provides to its licensee, and
0063  * not to intellectual property embodied in modifications its licensee may
0064  * make.
0065  *
0066  * 3.3. Redistribution of Executable. Redistribution in executable form of any
0067  * substantial portion of the Covered Code or modification must reproduce the
0068  * above Copyright Notice, and the following Disclaimer and Export Compliance
0069  * provision in the documentation and/or other materials provided with the
0070  * distribution.
0071  *
0072  * 3.4. Intel retains all right, title, and interest in and to the Original
0073  * Intel Code.
0074  *
0075  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
0076  * Intel shall be used in advertising or otherwise to promote the sale, use or
0077  * other dealings in products derived from or relating to the Covered Code
0078  * without prior written authorization from Intel.
0079  *
0080  * 4. Disclaimer and Export Compliance
0081  *
0082  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
0083  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
0084  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
0085  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
0086  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
0087  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
0088  * PARTICULAR PURPOSE.
0089  *
0090  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
0091  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
0092  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
0093  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
0094  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
0095  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
0096  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
0097  * LIMITED REMEDY.
0098  *
0099  * 4.3. Licensee shall not export, either directly or indirectly, any of this
0100  * software or system incorporating such software without first obtaining any
0101  * required license or other approval from the U. S. Department of Commerce or
0102  * any other agency or department of the United States Government.  In the
0103  * event Licensee exports any such software from the United States or
0104  * re-exports any such software from a foreign destination, Licensee shall
0105  * ensure that the distribution and export/re-export of the software is in
0106  * compliance with all laws, regulations, orders, or other restrictions of the
0107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
0108  * any of its subsidiaries will export/re-export any technical data, process,
0109  * software, or service, directly or indirectly, to any country for which the
0110  * United States government or any agency thereof requires an export license,
0111  * other governmental approval, or letter of assurance, without first obtaining
0112  * such license, approval or letter.
0113  *
0114  *****************************************************************************/
0115 
0116 
0117 #define __EXFLDIO_C__
0118 
0119 #include "acpi.h"
0120 #include "accommon.h"
0121 #include "acinterp.h"
0122 #include "amlcode.h"
0123 #include "acevents.h"
0124 #include "acdispat.h"
0125 
0126 
0127 #define _COMPONENT          ACPI_EXECUTER
0128         ACPI_MODULE_NAME    ("exfldio")
0129 
0130 /* Local prototypes */
0131 
0132 static ACPI_STATUS
0133 AcpiExFieldDatumIo (
0134     ACPI_OPERAND_OBJECT     *ObjDesc,
0135     UINT32                  FieldDatumByteOffset,
0136     ACPI_INTEGER            *Value,
0137     UINT32                  ReadWrite);
0138 
0139 static BOOLEAN
0140 AcpiExRegisterOverflow (
0141     ACPI_OPERAND_OBJECT     *ObjDesc,
0142     ACPI_INTEGER            Value);
0143 
0144 static ACPI_STATUS
0145 AcpiExSetupRegion (
0146     ACPI_OPERAND_OBJECT     *ObjDesc,
0147     UINT32                  FieldDatumByteOffset);
0148 
0149 
0150 /*******************************************************************************
0151  *
0152  * FUNCTION:    AcpiExSetupRegion
0153  *
0154  * PARAMETERS:  ObjDesc                 - Field to be read or written
0155  *              FieldDatumByteOffset    - Byte offset of this datum within the
0156  *                                        parent field
0157  *
0158  * RETURN:      Status
0159  *
0160  * DESCRIPTION: Common processing for AcpiExExtractFromField and
0161  *              AcpiExInsertIntoField.  Initialize the Region if necessary and
0162  *              validate the request.
0163  *
0164  ******************************************************************************/
0165 
0166 static ACPI_STATUS
0167 AcpiExSetupRegion (
0168     ACPI_OPERAND_OBJECT     *ObjDesc,
0169     UINT32                  FieldDatumByteOffset)
0170 {
0171     ACPI_STATUS             Status = AE_OK;
0172     ACPI_OPERAND_OBJECT     *RgnDesc;
0173 
0174 
0175     ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
0176 
0177 
0178     RgnDesc = ObjDesc->CommonField.RegionObj;
0179 
0180     /* We must have a valid region */
0181 
0182     if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
0183     {
0184         ACPI_ERROR ((AE_INFO, "Needed Region, found type %X (%s)",
0185             RgnDesc->Common.Type,
0186             AcpiUtGetObjectTypeName (RgnDesc)));
0187 
0188         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
0189     }
0190 
0191     /*
0192      * If the Region Address and Length have not been previously evaluated,
0193      * evaluate them now and save the results.
0194      */
0195     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
0196     {
0197         Status = AcpiDsGetRegionArguments (RgnDesc);
0198         if (ACPI_FAILURE (Status))
0199         {
0200             return_ACPI_STATUS (Status);
0201         }
0202     }
0203 
0204     /*
0205      * Exit now for SMBus or IPMI address space, it has a non-linear address space
0206      * and the request cannot be directly validated
0207      */
0208     if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
0209         RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI)
0210     {
0211         /* SMBus or IPMI has a non-linear address space */
0212 
0213         return_ACPI_STATUS (AE_OK);
0214     }
0215 
0216 #ifdef ACPI_UNDER_DEVELOPMENT
0217     /*
0218      * If the Field access is AnyAcc, we can now compute the optimal
0219      * access (because we know know the length of the parent region)
0220      */
0221     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
0222     {
0223         if (ACPI_FAILURE (Status))
0224         {
0225             return_ACPI_STATUS (Status);
0226         }
0227     }
0228 #endif
0229 
0230     /*
0231      * Validate the request.  The entire request from the byte offset for a
0232      * length of one field datum (access width) must fit within the region.
0233      * (Region length is specified in bytes)
0234      */
0235     if (RgnDesc->Region.Length <
0236             (ObjDesc->CommonField.BaseByteOffset +
0237             FieldDatumByteOffset +
0238             ObjDesc->CommonField.AccessByteWidth))
0239     {
0240         if (AcpiGbl_EnableInterpreterSlack)
0241         {
0242             /*
0243              * Slack mode only:  We will go ahead and allow access to this
0244              * field if it is within the region length rounded up to the next
0245              * access width boundary. ACPI_SIZE cast for 64-bit compile.
0246              */
0247             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
0248                     ObjDesc->CommonField.AccessByteWidth) >=
0249                 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
0250                     ObjDesc->CommonField.AccessByteWidth +
0251                     FieldDatumByteOffset))
0252             {
0253                 return_ACPI_STATUS (AE_OK);
0254             }
0255         }
0256 
0257         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
0258         {
0259             /*
0260              * This is the case where the AccessType (AccWord, etc.) is wider
0261              * than the region itself.  For example, a region of length one
0262              * byte, and a field with Dword access specified.
0263              */
0264             ACPI_ERROR ((AE_INFO,
0265                 "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)",
0266                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
0267                 ObjDesc->CommonField.AccessByteWidth,
0268                 AcpiUtGetNodeName (RgnDesc->Region.Node),
0269                 RgnDesc->Region.Length));
0270         }
0271 
0272         /*
0273          * Offset rounded up to next multiple of field width
0274          * exceeds region length, indicate an error
0275          */
0276         ACPI_ERROR ((AE_INFO,
0277             "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)",
0278             AcpiUtGetNodeName (ObjDesc->CommonField.Node),
0279             ObjDesc->CommonField.BaseByteOffset,
0280             FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
0281             AcpiUtGetNodeName (RgnDesc->Region.Node),
0282             RgnDesc->Region.Length));
0283 
0284         return_ACPI_STATUS (AE_AML_REGION_LIMIT);
0285     }
0286 
0287     return_ACPI_STATUS (AE_OK);
0288 }
0289 
0290 
0291 /*******************************************************************************
0292  *
0293  * FUNCTION:    AcpiExAccessRegion
0294  *
0295  * PARAMETERS:  ObjDesc                 - Field to be read
0296  *              FieldDatumByteOffset    - Byte offset of this datum within the
0297  *                                        parent field
0298  *              Value                   - Where to store value (must at least
0299  *                                        the size of ACPI_INTEGER)
0300  *              Function                - Read or Write flag plus other region-
0301  *                                        dependent flags
0302  *
0303  * RETURN:      Status
0304  *
0305  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
0306  *
0307  ******************************************************************************/
0308 
0309 ACPI_STATUS
0310 AcpiExAccessRegion (
0311     ACPI_OPERAND_OBJECT     *ObjDesc,
0312     UINT32                  FieldDatumByteOffset,
0313     ACPI_INTEGER            *Value,
0314     UINT32                  Function)
0315 {
0316     ACPI_STATUS             Status;
0317     ACPI_OPERAND_OBJECT     *RgnDesc;
0318     UINT32                  RegionOffset;
0319 
0320 
0321     ACPI_FUNCTION_TRACE (ExAccessRegion);
0322 
0323 
0324     /*
0325      * Ensure that the region operands are fully evaluated and verify
0326      * the validity of the request
0327      */
0328     Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
0329     if (ACPI_FAILURE (Status))
0330     {
0331         return_ACPI_STATUS (Status);
0332     }
0333 
0334     /*
0335      * The physical address of this field datum is:
0336      *
0337      * 1) The base of the region, plus
0338      * 2) The base offset of the field, plus
0339      * 3) The current offset into the field
0340      */
0341     RgnDesc = ObjDesc->CommonField.RegionObj;
0342     RegionOffset =
0343         ObjDesc->CommonField.BaseByteOffset +
0344         FieldDatumByteOffset;
0345 
0346     if ((Function & ACPI_IO_MASK) == ACPI_READ)
0347     {
0348         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
0349     }
0350     else
0351     {
0352         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
0353     }
0354 
0355     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
0356         " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
0357         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
0358         RgnDesc->Region.SpaceId,
0359         ObjDesc->CommonField.AccessByteWidth,
0360         ObjDesc->CommonField.BaseByteOffset,
0361         FieldDatumByteOffset,
0362         ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset))));
0363 
0364     /* Invoke the appropriate AddressSpace/OpRegion handler */
0365 
0366     Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, RegionOffset,
0367                 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
0368 
0369     if (ACPI_FAILURE (Status))
0370     {
0371         if (Status == AE_NOT_IMPLEMENTED)
0372         {
0373             ACPI_ERROR ((AE_INFO,
0374                 "Region %s(%X) not implemented",
0375                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
0376                 RgnDesc->Region.SpaceId));
0377         }
0378         else if (Status == AE_NOT_EXIST)
0379         {
0380             ACPI_ERROR ((AE_INFO,
0381                 "Region %s(%X) has no handler",
0382                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
0383                 RgnDesc->Region.SpaceId));
0384         }
0385     }
0386 
0387     return_ACPI_STATUS (Status);
0388 }
0389 
0390 
0391 /*******************************************************************************
0392  *
0393  * FUNCTION:    AcpiExRegisterOverflow
0394  *
0395  * PARAMETERS:  ObjDesc                 - Register(Field) to be written
0396  *              Value                   - Value to be stored
0397  *
0398  * RETURN:      TRUE if value overflows the field, FALSE otherwise
0399  *
0400  * DESCRIPTION: Check if a value is out of range of the field being written.
0401  *              Used to check if the values written to Index and Bank registers
0402  *              are out of range.  Normally, the value is simply truncated
0403  *              to fit the field, but this case is most likely a serious
0404  *              coding error in the ASL.
0405  *
0406  ******************************************************************************/
0407 
0408 static BOOLEAN
0409 AcpiExRegisterOverflow (
0410     ACPI_OPERAND_OBJECT     *ObjDesc,
0411     ACPI_INTEGER            Value)
0412 {
0413 
0414     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
0415     {
0416         /*
0417          * The field is large enough to hold the maximum integer, so we can
0418          * never overflow it.
0419          */
0420         return (FALSE);
0421     }
0422 
0423     if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength))
0424     {
0425         /*
0426          * The Value is larger than the maximum value that can fit into
0427          * the register.
0428          */
0429         return (TRUE);
0430     }
0431 
0432     /* The Value will fit into the field with no truncation */
0433 
0434     return (FALSE);
0435 }
0436 
0437 
0438 /*******************************************************************************
0439  *
0440  * FUNCTION:    AcpiExFieldDatumIo
0441  *
0442  * PARAMETERS:  ObjDesc                 - Field to be read
0443  *              FieldDatumByteOffset    - Byte offset of this datum within the
0444  *                                        parent field
0445  *              Value                   - Where to store value (must be 64 bits)
0446  *              ReadWrite               - Read or Write flag
0447  *
0448  * RETURN:      Status
0449  *
0450  * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
0451  *              demultiplexed here to handle the different types of fields
0452  *              (BufferField, RegionField, IndexField, BankField)
0453  *
0454  ******************************************************************************/
0455 
0456 static ACPI_STATUS
0457 AcpiExFieldDatumIo (
0458     ACPI_OPERAND_OBJECT     *ObjDesc,
0459     UINT32                  FieldDatumByteOffset,
0460     ACPI_INTEGER            *Value,
0461     UINT32                  ReadWrite)
0462 {
0463     ACPI_STATUS             Status;
0464     ACPI_INTEGER            LocalValue;
0465 
0466 
0467     ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
0468 
0469 
0470     if (ReadWrite == ACPI_READ)
0471     {
0472         if (!Value)
0473         {
0474             LocalValue = 0;
0475 
0476             /* To support reads without saving return value */
0477             Value = &LocalValue;
0478         }
0479 
0480         /* Clear the entire return buffer first, [Very Important!] */
0481 
0482         *Value = 0;
0483     }
0484 
0485     /*
0486      * The four types of fields are:
0487      *
0488      * BufferField - Read/write from/to a Buffer
0489      * RegionField - Read/write from/to a Operation Region.
0490      * BankField   - Write to a Bank Register, then read/write from/to an
0491      *               OperationRegion
0492      * IndexField  - Write to an Index Register, then read/write from/to a
0493      *               Data Register
0494      */
0495     switch (ObjDesc->Common.Type)
0496     {
0497     case ACPI_TYPE_BUFFER_FIELD:
0498         /*
0499          * If the BufferField arguments have not been previously evaluated,
0500          * evaluate them now and save the results.
0501          */
0502         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
0503         {
0504             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
0505             if (ACPI_FAILURE (Status))
0506             {
0507                 return_ACPI_STATUS (Status);
0508             }
0509         }
0510 
0511         if (ReadWrite == ACPI_READ)
0512         {
0513             /*
0514              * Copy the data from the source buffer.
0515              * Length is the field width in bytes.
0516              */
0517             ACPI_MEMCPY (Value,
0518                 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
0519                     ObjDesc->BufferField.BaseByteOffset +
0520                     FieldDatumByteOffset,
0521                 ObjDesc->CommonField.AccessByteWidth);
0522         }
0523         else
0524         {
0525             /*
0526              * Copy the data to the target buffer.
0527              * Length is the field width in bytes.
0528              */
0529             ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
0530                 ObjDesc->BufferField.BaseByteOffset +
0531                 FieldDatumByteOffset,
0532                 Value, ObjDesc->CommonField.AccessByteWidth);
0533         }
0534 
0535         Status = AE_OK;
0536         break;
0537 
0538 
0539     case ACPI_TYPE_LOCAL_BANK_FIELD:
0540 
0541         /*
0542          * Ensure that the BankValue is not beyond the capacity of
0543          * the register
0544          */
0545         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
0546                 (ACPI_INTEGER) ObjDesc->BankField.Value))
0547         {
0548             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
0549         }
0550 
0551         /*
0552          * For BankFields, we must write the BankValue to the BankRegister
0553          * (itself a RegionField) before we can access the data.
0554          */
0555         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
0556                     &ObjDesc->BankField.Value,
0557                     sizeof (ObjDesc->BankField.Value));
0558         if (ACPI_FAILURE (Status))
0559         {
0560             return_ACPI_STATUS (Status);
0561         }
0562 
0563         /*
0564          * Now that the Bank has been selected, fall through to the
0565          * RegionField case and write the datum to the Operation Region
0566          */
0567 
0568         /*lint -fallthrough */
0569 
0570 
0571     case ACPI_TYPE_LOCAL_REGION_FIELD:
0572         /*
0573          * For simple RegionFields, we just directly access the owning
0574          * Operation Region.
0575          */
0576         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
0577                     ReadWrite);
0578         break;
0579 
0580 
0581     case ACPI_TYPE_LOCAL_INDEX_FIELD:
0582 
0583 
0584         /*
0585          * Ensure that the IndexValue is not beyond the capacity of
0586          * the register
0587          */
0588         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
0589                 (ACPI_INTEGER) ObjDesc->IndexField.Value))
0590         {
0591             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
0592         }
0593 
0594         /* Write the index value to the IndexRegister (itself a RegionField) */
0595 
0596         FieldDatumByteOffset += ObjDesc->IndexField.Value;
0597 
0598         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
0599             "Write to Index Register: Value %8.8X\n",
0600             FieldDatumByteOffset));
0601 
0602         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
0603                     &FieldDatumByteOffset,
0604                     sizeof (FieldDatumByteOffset));
0605         if (ACPI_FAILURE (Status))
0606         {
0607             return_ACPI_STATUS (Status);
0608         }
0609 
0610         if (ReadWrite == ACPI_READ)
0611         {
0612             /* Read the datum from the DataRegister */
0613 
0614             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
0615                 "Read from Data Register\n"));
0616 
0617             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
0618                         Value, sizeof (ACPI_INTEGER));
0619         }
0620         else
0621         {
0622             /* Write the datum to the DataRegister */
0623 
0624             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
0625                 "Write to Data Register: Value %8.8X%8.8X\n",
0626                 ACPI_FORMAT_UINT64 (*Value)));
0627 
0628             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
0629                         Value, sizeof (ACPI_INTEGER));
0630         }
0631         break;
0632 
0633 
0634     default:
0635 
0636         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %X",
0637             ObjDesc->Common.Type));
0638         Status = AE_AML_INTERNAL;
0639         break;
0640     }
0641 
0642     if (ACPI_SUCCESS (Status))
0643     {
0644         if (ReadWrite == ACPI_READ)
0645         {
0646             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
0647                 "Value Read %8.8X%8.8X, Width %d\n",
0648                 ACPI_FORMAT_UINT64 (*Value),
0649                 ObjDesc->CommonField.AccessByteWidth));
0650         }
0651         else
0652         {
0653             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
0654                 "Value Written %8.8X%8.8X, Width %d\n",
0655                 ACPI_FORMAT_UINT64 (*Value),
0656                 ObjDesc->CommonField.AccessByteWidth));
0657         }
0658     }
0659 
0660     return_ACPI_STATUS (Status);
0661 }
0662 
0663 
0664 /*******************************************************************************
0665  *
0666  * FUNCTION:    AcpiExWriteWithUpdateRule
0667  *
0668  * PARAMETERS:  ObjDesc                 - Field to be written
0669  *              Mask                    - bitmask within field datum
0670  *              FieldValue              - Value to write
0671  *              FieldDatumByteOffset    - Offset of datum within field
0672  *
0673  * RETURN:      Status
0674  *
0675  * DESCRIPTION: Apply the field update rule to a field write
0676  *
0677  ******************************************************************************/
0678 
0679 ACPI_STATUS
0680 AcpiExWriteWithUpdateRule (
0681     ACPI_OPERAND_OBJECT     *ObjDesc,
0682     ACPI_INTEGER            Mask,
0683     ACPI_INTEGER            FieldValue,
0684     UINT32                  FieldDatumByteOffset)
0685 {
0686     ACPI_STATUS             Status = AE_OK;
0687     ACPI_INTEGER            MergedValue;
0688     ACPI_INTEGER            CurrentValue;
0689 
0690 
0691     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
0692 
0693 
0694     /* Start with the new bits  */
0695 
0696     MergedValue = FieldValue;
0697 
0698     /* If the mask is all ones, we don't need to worry about the update rule */
0699 
0700     if (Mask != ACPI_INTEGER_MAX)
0701     {
0702         /* Decode the update rule */
0703 
0704         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
0705         {
0706         case AML_FIELD_UPDATE_PRESERVE:
0707             /*
0708              * Check if update rule needs to be applied (not if mask is all
0709              * ones)  The left shift drops the bits we want to ignore.
0710              */
0711             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
0712                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
0713             {
0714                 /*
0715                  * Read the current contents of the byte/word/dword containing
0716                  * the field, and merge with the new field value.
0717                  */
0718                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
0719                             &CurrentValue, ACPI_READ);
0720                 if (ACPI_FAILURE (Status))
0721                 {
0722                     return_ACPI_STATUS (Status);
0723                 }
0724 
0725                 MergedValue |= (CurrentValue & ~Mask);
0726             }
0727             break;
0728 
0729         case AML_FIELD_UPDATE_WRITE_AS_ONES:
0730 
0731             /* Set positions outside the field to all ones */
0732 
0733             MergedValue |= ~Mask;
0734             break;
0735 
0736         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
0737 
0738             /* Set positions outside the field to all zeros */
0739 
0740             MergedValue &= Mask;
0741             break;
0742 
0743         default:
0744 
0745             ACPI_ERROR ((AE_INFO,
0746                 "Unknown UpdateRule value: %X",
0747                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
0748             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
0749         }
0750     }
0751 
0752     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
0753         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
0754         ACPI_FORMAT_UINT64 (Mask),
0755         FieldDatumByteOffset,
0756         ObjDesc->CommonField.AccessByteWidth,
0757         ACPI_FORMAT_UINT64 (FieldValue),
0758         ACPI_FORMAT_UINT64 (MergedValue)));
0759 
0760     /* Write the merged value */
0761 
0762     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
0763                 &MergedValue, ACPI_WRITE);
0764 
0765     return_ACPI_STATUS (Status);
0766 }
0767 
0768 
0769 /*******************************************************************************
0770  *
0771  * FUNCTION:    AcpiExExtractFromField
0772  *
0773  * PARAMETERS:  ObjDesc             - Field to be read
0774  *              Buffer              - Where to store the field data
0775  *              BufferLength        - Length of Buffer
0776  *
0777  * RETURN:      Status
0778  *
0779  * DESCRIPTION: Retrieve the current value of the given field
0780  *
0781  ******************************************************************************/
0782 
0783 ACPI_STATUS
0784 AcpiExExtractFromField (
0785     ACPI_OPERAND_OBJECT     *ObjDesc,
0786     void                    *Buffer,
0787     UINT32                  BufferLength)
0788 {
0789     ACPI_STATUS             Status;
0790     ACPI_INTEGER            RawDatum;
0791     ACPI_INTEGER            MergedDatum;
0792     UINT32                  FieldOffset = 0;
0793     UINT32                  BufferOffset = 0;
0794     UINT32                  BufferTailBits;
0795     UINT32                  DatumCount;
0796     UINT32                  FieldDatumCount;
0797     UINT32                  i;
0798 
0799 
0800     ACPI_FUNCTION_TRACE (ExExtractFromField);
0801 
0802 
0803     /* Validate target buffer and clear it */
0804 
0805     if (BufferLength <
0806             ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
0807     {
0808         ACPI_ERROR ((AE_INFO,
0809             "Field size %X (bits) is too large for buffer (%X)",
0810             ObjDesc->CommonField.BitLength, BufferLength));
0811 
0812         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
0813     }
0814     ACPI_MEMSET (Buffer, 0, BufferLength);
0815 
0816     /* Compute the number of datums (access width data items) */
0817 
0818     DatumCount = ACPI_ROUND_UP_TO (
0819                         ObjDesc->CommonField.BitLength,
0820                         ObjDesc->CommonField.AccessBitWidth);
0821     FieldDatumCount = ACPI_ROUND_UP_TO (
0822                         ObjDesc->CommonField.BitLength +
0823                         ObjDesc->CommonField.StartFieldBitOffset,
0824                         ObjDesc->CommonField.AccessBitWidth);
0825 
0826     /* Priming read from the field */
0827 
0828     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
0829     if (ACPI_FAILURE (Status))
0830     {
0831         return_ACPI_STATUS (Status);
0832     }
0833     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
0834 
0835     /* Read the rest of the field */
0836 
0837     for (i = 1; i < FieldDatumCount; i++)
0838     {
0839         /* Get next input datum from the field */
0840 
0841         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
0842         Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
0843                     &RawDatum, ACPI_READ);
0844         if (ACPI_FAILURE (Status))
0845         {
0846             return_ACPI_STATUS (Status);
0847         }
0848 
0849         /*
0850          * Merge with previous datum if necessary.
0851          *
0852          * Note: Before the shift, check if the shift value will be larger than
0853          * the integer size. If so, there is no need to perform the operation.
0854          * This avoids the differences in behavior between different compilers
0855          * concerning shift values larger than the target data width.
0856          */
0857         if ((ObjDesc->CommonField.AccessBitWidth -
0858             ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE)
0859         {
0860             MergedDatum |= RawDatum <<
0861                 (ObjDesc->CommonField.AccessBitWidth -
0862                     ObjDesc->CommonField.StartFieldBitOffset);
0863         }
0864 
0865         if (i == DatumCount)
0866         {
0867             break;
0868         }
0869 
0870         /* Write merged datum to target buffer */
0871 
0872         ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
0873             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
0874                 BufferLength - BufferOffset));
0875 
0876         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
0877         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
0878     }
0879 
0880     /* Mask off any extra bits in the last datum */
0881 
0882     BufferTailBits = ObjDesc->CommonField.BitLength %
0883                         ObjDesc->CommonField.AccessBitWidth;
0884     if (BufferTailBits)
0885     {
0886         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
0887     }
0888 
0889     /* Write the last datum to the buffer */
0890 
0891     ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
0892         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
0893             BufferLength - BufferOffset));
0894 
0895     return_ACPI_STATUS (AE_OK);
0896 }
0897 
0898 
0899 /*******************************************************************************
0900  *
0901  * FUNCTION:    AcpiExInsertIntoField
0902  *
0903  * PARAMETERS:  ObjDesc             - Field to be written
0904  *              Buffer              - Data to be written
0905  *              BufferLength        - Length of Buffer
0906  *
0907  * RETURN:      Status
0908  *
0909  * DESCRIPTION: Store the Buffer contents into the given field
0910  *
0911  ******************************************************************************/
0912 
0913 ACPI_STATUS
0914 AcpiExInsertIntoField (
0915     ACPI_OPERAND_OBJECT     *ObjDesc,
0916     void                    *Buffer,
0917     UINT32                  BufferLength)
0918 {
0919     ACPI_STATUS             Status;
0920     ACPI_INTEGER            Mask;
0921     ACPI_INTEGER            WidthMask;
0922     ACPI_INTEGER            MergedDatum;
0923     ACPI_INTEGER            RawDatum = 0;
0924     UINT32                  FieldOffset = 0;
0925     UINT32                  BufferOffset = 0;
0926     UINT32                  BufferTailBits;
0927     UINT32                  DatumCount;
0928     UINT32                  FieldDatumCount;
0929     UINT32                  i;
0930     UINT32                  RequiredLength;
0931     void                    *NewBuffer;
0932 
0933 
0934     ACPI_FUNCTION_TRACE (ExInsertIntoField);
0935 
0936 
0937     /* Validate input buffer */
0938 
0939     NewBuffer = NULL;
0940     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
0941                         ObjDesc->CommonField.BitLength);
0942     /*
0943      * We must have a buffer that is at least as long as the field
0944      * we are writing to.  This is because individual fields are
0945      * indivisible and partial writes are not supported -- as per
0946      * the ACPI specification.
0947      */
0948     if (BufferLength < RequiredLength)
0949     {
0950         /* We need to create a new buffer */
0951 
0952         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
0953         if (!NewBuffer)
0954         {
0955             return_ACPI_STATUS (AE_NO_MEMORY);
0956         }
0957 
0958         /*
0959          * Copy the original data to the new buffer, starting
0960          * at Byte zero.  All unused (upper) bytes of the
0961          * buffer will be 0.
0962          */
0963         ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
0964         Buffer = NewBuffer;
0965         BufferLength = RequiredLength;
0966     }
0967 
0968     /*
0969      * Create the bitmasks used for bit insertion.
0970      * Note: This if/else is used to bypass compiler differences with the
0971      * shift operator
0972      */
0973     if (ObjDesc->CommonField.AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
0974     {
0975         WidthMask = ACPI_INTEGER_MAX;
0976     }
0977     else
0978     {
0979         WidthMask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.AccessBitWidth);
0980     }
0981 
0982     Mask = WidthMask &
0983             ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
0984 
0985     /* Compute the number of datums (access width data items) */
0986 
0987     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
0988                     ObjDesc->CommonField.AccessBitWidth);
0989 
0990     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
0991                         ObjDesc->CommonField.StartFieldBitOffset,
0992                         ObjDesc->CommonField.AccessBitWidth);
0993 
0994     /* Get initial Datum from the input buffer */
0995 
0996     ACPI_MEMCPY (&RawDatum, Buffer,
0997         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
0998             BufferLength - BufferOffset));
0999 
1000     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1001 
1002     /* Write the entire field */
1003 
1004     for (i = 1; i < FieldDatumCount; i++)
1005     {
1006         /* Write merged datum to the target field */
1007 
1008         MergedDatum &= Mask;
1009         Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
1010                     MergedDatum, FieldOffset);
1011         if (ACPI_FAILURE (Status))
1012         {
1013             goto Exit;
1014         }
1015 
1016         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
1017 
1018         /*
1019          * Start new output datum by merging with previous input datum
1020          * if necessary.
1021          *
1022          * Note: Before the shift, check if the shift value will be larger than
1023          * the integer size. If so, there is no need to perform the operation.
1024          * This avoids the differences in behavior between different compilers
1025          * concerning shift values larger than the target data width.
1026          */
1027         if ((ObjDesc->CommonField.AccessBitWidth -
1028             ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE)
1029         {
1030             MergedDatum = RawDatum >>
1031                 (ObjDesc->CommonField.AccessBitWidth -
1032                     ObjDesc->CommonField.StartFieldBitOffset);
1033         }
1034         else
1035         {
1036             MergedDatum = 0;
1037         }
1038 
1039         Mask = WidthMask;
1040 
1041         if (i == DatumCount)
1042         {
1043             break;
1044         }
1045 
1046         /* Get the next input datum from the buffer */
1047 
1048         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1049         ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
1050             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1051                      BufferLength - BufferOffset));
1052         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1053     }
1054 
1055     /* Mask off any extra bits in the last datum */
1056 
1057     BufferTailBits = (ObjDesc->CommonField.BitLength +
1058             ObjDesc->CommonField.StartFieldBitOffset) %
1059                 ObjDesc->CommonField.AccessBitWidth;
1060     if (BufferTailBits)
1061     {
1062         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1063     }
1064 
1065     /* Write the last datum to the field */
1066 
1067     MergedDatum &= Mask;
1068     Status = AcpiExWriteWithUpdateRule (ObjDesc,
1069                 Mask, MergedDatum, FieldOffset);
1070 
1071 Exit:
1072     /* Free temporary buffer if we used one */
1073 
1074     if (NewBuffer)
1075     {
1076         ACPI_FREE (NewBuffer);
1077     }
1078     return_ACPI_STATUS (Status);
1079 }
1080 
1081