Home | History | Annotate | Line # | Download | only in executer
exfldio.c revision 1.1.1.4.2.2
      1          1.1    jruoho /******************************************************************************
      2          1.1    jruoho  *
      3          1.1    jruoho  * Module Name: exfldio - Aml Field I/O
      4          1.1    jruoho  *
      5          1.1    jruoho  *****************************************************************************/
      6          1.1    jruoho 
      7      1.1.1.2    jruoho /*
      8  1.1.1.4.2.1     skrll  * Copyright (C) 2000 - 2015, Intel Corp.
      9          1.1    jruoho  * All rights reserved.
     10          1.1    jruoho  *
     11      1.1.1.2    jruoho  * Redistribution and use in source and binary forms, with or without
     12      1.1.1.2    jruoho  * modification, are permitted provided that the following conditions
     13      1.1.1.2    jruoho  * are met:
     14      1.1.1.2    jruoho  * 1. Redistributions of source code must retain the above copyright
     15      1.1.1.2    jruoho  *    notice, this list of conditions, and the following disclaimer,
     16      1.1.1.2    jruoho  *    without modification.
     17      1.1.1.2    jruoho  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18      1.1.1.2    jruoho  *    substantially similar to the "NO WARRANTY" disclaimer below
     19      1.1.1.2    jruoho  *    ("Disclaimer") and any redistribution must be conditioned upon
     20      1.1.1.2    jruoho  *    including a substantially similar Disclaimer requirement for further
     21      1.1.1.2    jruoho  *    binary redistribution.
     22      1.1.1.2    jruoho  * 3. Neither the names of the above-listed copyright holders nor the names
     23      1.1.1.2    jruoho  *    of any contributors may be used to endorse or promote products derived
     24      1.1.1.2    jruoho  *    from this software without specific prior written permission.
     25      1.1.1.2    jruoho  *
     26      1.1.1.2    jruoho  * Alternatively, this software may be distributed under the terms of the
     27      1.1.1.2    jruoho  * GNU General Public License ("GPL") version 2 as published by the Free
     28      1.1.1.2    jruoho  * Software Foundation.
     29      1.1.1.2    jruoho  *
     30      1.1.1.2    jruoho  * NO WARRANTY
     31      1.1.1.2    jruoho  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32      1.1.1.2    jruoho  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33      1.1.1.2    jruoho  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34      1.1.1.2    jruoho  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35      1.1.1.2    jruoho  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36      1.1.1.2    jruoho  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37      1.1.1.2    jruoho  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38      1.1.1.2    jruoho  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39      1.1.1.2    jruoho  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40      1.1.1.2    jruoho  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41      1.1.1.2    jruoho  * POSSIBILITY OF SUCH DAMAGES.
     42      1.1.1.2    jruoho  */
     43          1.1    jruoho 
     44          1.1    jruoho #include "acpi.h"
     45          1.1    jruoho #include "accommon.h"
     46          1.1    jruoho #include "acinterp.h"
     47          1.1    jruoho #include "amlcode.h"
     48          1.1    jruoho #include "acevents.h"
     49          1.1    jruoho #include "acdispat.h"
     50          1.1    jruoho 
     51          1.1    jruoho 
     52          1.1    jruoho #define _COMPONENT          ACPI_EXECUTER
     53          1.1    jruoho         ACPI_MODULE_NAME    ("exfldio")
     54          1.1    jruoho 
     55          1.1    jruoho /* Local prototypes */
     56          1.1    jruoho 
     57          1.1    jruoho static ACPI_STATUS
     58          1.1    jruoho AcpiExFieldDatumIo (
     59          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
     60          1.1    jruoho     UINT32                  FieldDatumByteOffset,
     61          1.1    jruoho     UINT64                  *Value,
     62          1.1    jruoho     UINT32                  ReadWrite);
     63          1.1    jruoho 
     64          1.1    jruoho static BOOLEAN
     65          1.1    jruoho AcpiExRegisterOverflow (
     66          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
     67          1.1    jruoho     UINT64                  Value);
     68          1.1    jruoho 
     69          1.1    jruoho static ACPI_STATUS
     70          1.1    jruoho AcpiExSetupRegion (
     71          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
     72          1.1    jruoho     UINT32                  FieldDatumByteOffset);
     73          1.1    jruoho 
     74          1.1    jruoho 
     75          1.1    jruoho /*******************************************************************************
     76          1.1    jruoho  *
     77          1.1    jruoho  * FUNCTION:    AcpiExSetupRegion
     78          1.1    jruoho  *
     79          1.1    jruoho  * PARAMETERS:  ObjDesc                 - Field to be read or written
     80          1.1    jruoho  *              FieldDatumByteOffset    - Byte offset of this datum within the
     81          1.1    jruoho  *                                        parent field
     82          1.1    jruoho  *
     83          1.1    jruoho  * RETURN:      Status
     84          1.1    jruoho  *
     85          1.1    jruoho  * DESCRIPTION: Common processing for AcpiExExtractFromField and
     86      1.1.1.3  christos  *              AcpiExInsertIntoField. Initialize the Region if necessary and
     87          1.1    jruoho  *              validate the request.
     88          1.1    jruoho  *
     89          1.1    jruoho  ******************************************************************************/
     90          1.1    jruoho 
     91          1.1    jruoho static ACPI_STATUS
     92          1.1    jruoho AcpiExSetupRegion (
     93          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
     94          1.1    jruoho     UINT32                  FieldDatumByteOffset)
     95          1.1    jruoho {
     96          1.1    jruoho     ACPI_STATUS             Status = AE_OK;
     97          1.1    jruoho     ACPI_OPERAND_OBJECT     *RgnDesc;
     98      1.1.1.3  christos     UINT8                   SpaceId;
     99          1.1    jruoho 
    100          1.1    jruoho 
    101          1.1    jruoho     ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
    102          1.1    jruoho 
    103          1.1    jruoho 
    104          1.1    jruoho     RgnDesc = ObjDesc->CommonField.RegionObj;
    105          1.1    jruoho 
    106          1.1    jruoho     /* We must have a valid region */
    107          1.1    jruoho 
    108          1.1    jruoho     if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
    109          1.1    jruoho     {
    110          1.1    jruoho         ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
    111          1.1    jruoho             RgnDesc->Common.Type,
    112          1.1    jruoho             AcpiUtGetObjectTypeName (RgnDesc)));
    113          1.1    jruoho 
    114          1.1    jruoho         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    115          1.1    jruoho     }
    116          1.1    jruoho 
    117      1.1.1.3  christos     SpaceId = RgnDesc->Region.SpaceId;
    118      1.1.1.3  christos 
    119      1.1.1.3  christos     /* Validate the Space ID */
    120      1.1.1.3  christos 
    121      1.1.1.3  christos     if (!AcpiIsValidSpaceId (SpaceId))
    122      1.1.1.3  christos     {
    123      1.1.1.3  christos         ACPI_ERROR ((AE_INFO, "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId));
    124      1.1.1.3  christos         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    125      1.1.1.3  christos     }
    126      1.1.1.3  christos 
    127          1.1    jruoho     /*
    128          1.1    jruoho      * If the Region Address and Length have not been previously evaluated,
    129          1.1    jruoho      * evaluate them now and save the results.
    130          1.1    jruoho      */
    131          1.1    jruoho     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
    132          1.1    jruoho     {
    133          1.1    jruoho         Status = AcpiDsGetRegionArguments (RgnDesc);
    134          1.1    jruoho         if (ACPI_FAILURE (Status))
    135          1.1    jruoho         {
    136          1.1    jruoho             return_ACPI_STATUS (Status);
    137          1.1    jruoho         }
    138          1.1    jruoho     }
    139          1.1    jruoho 
    140          1.1    jruoho     /*
    141      1.1.1.3  christos      * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
    142          1.1    jruoho      * address space and the request cannot be directly validated
    143          1.1    jruoho      */
    144      1.1.1.3  christos     if (SpaceId == ACPI_ADR_SPACE_SMBUS ||
    145      1.1.1.3  christos         SpaceId == ACPI_ADR_SPACE_GSBUS ||
    146      1.1.1.3  christos         SpaceId == ACPI_ADR_SPACE_IPMI)
    147          1.1    jruoho     {
    148          1.1    jruoho         /* SMBus or IPMI has a non-linear address space */
    149          1.1    jruoho 
    150          1.1    jruoho         return_ACPI_STATUS (AE_OK);
    151          1.1    jruoho     }
    152          1.1    jruoho 
    153          1.1    jruoho #ifdef ACPI_UNDER_DEVELOPMENT
    154          1.1    jruoho     /*
    155          1.1    jruoho      * If the Field access is AnyAcc, we can now compute the optimal
    156          1.1    jruoho      * access (because we know know the length of the parent region)
    157          1.1    jruoho      */
    158          1.1    jruoho     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
    159          1.1    jruoho     {
    160          1.1    jruoho         if (ACPI_FAILURE (Status))
    161          1.1    jruoho         {
    162          1.1    jruoho             return_ACPI_STATUS (Status);
    163          1.1    jruoho         }
    164          1.1    jruoho     }
    165          1.1    jruoho #endif
    166          1.1    jruoho 
    167          1.1    jruoho     /*
    168      1.1.1.3  christos      * Validate the request. The entire request from the byte offset for a
    169          1.1    jruoho      * length of one field datum (access width) must fit within the region.
    170          1.1    jruoho      * (Region length is specified in bytes)
    171          1.1    jruoho      */
    172          1.1    jruoho     if (RgnDesc->Region.Length <
    173          1.1    jruoho             (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
    174          1.1    jruoho             ObjDesc->CommonField.AccessByteWidth))
    175          1.1    jruoho     {
    176          1.1    jruoho         if (AcpiGbl_EnableInterpreterSlack)
    177          1.1    jruoho         {
    178          1.1    jruoho             /*
    179          1.1    jruoho              * Slack mode only:  We will go ahead and allow access to this
    180          1.1    jruoho              * field if it is within the region length rounded up to the next
    181          1.1    jruoho              * access width boundary. ACPI_SIZE cast for 64-bit compile.
    182          1.1    jruoho              */
    183          1.1    jruoho             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
    184          1.1    jruoho                     ObjDesc->CommonField.AccessByteWidth) >=
    185          1.1    jruoho                 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
    186          1.1    jruoho                     ObjDesc->CommonField.AccessByteWidth +
    187          1.1    jruoho                     FieldDatumByteOffset))
    188          1.1    jruoho             {
    189          1.1    jruoho                 return_ACPI_STATUS (AE_OK);
    190          1.1    jruoho             }
    191          1.1    jruoho         }
    192          1.1    jruoho 
    193          1.1    jruoho         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
    194          1.1    jruoho         {
    195          1.1    jruoho             /*
    196          1.1    jruoho              * This is the case where the AccessType (AccWord, etc.) is wider
    197      1.1.1.3  christos              * than the region itself. For example, a region of length one
    198          1.1    jruoho              * byte, and a field with Dword access specified.
    199          1.1    jruoho              */
    200          1.1    jruoho             ACPI_ERROR ((AE_INFO,
    201          1.1    jruoho                 "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
    202          1.1    jruoho                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
    203          1.1    jruoho                 ObjDesc->CommonField.AccessByteWidth,
    204          1.1    jruoho                 AcpiUtGetNodeName (RgnDesc->Region.Node),
    205          1.1    jruoho                 RgnDesc->Region.Length));
    206          1.1    jruoho         }
    207          1.1    jruoho 
    208          1.1    jruoho         /*
    209          1.1    jruoho          * Offset rounded up to next multiple of field width
    210          1.1    jruoho          * exceeds region length, indicate an error
    211          1.1    jruoho          */
    212          1.1    jruoho         ACPI_ERROR ((AE_INFO,
    213          1.1    jruoho             "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)",
    214          1.1    jruoho             AcpiUtGetNodeName (ObjDesc->CommonField.Node),
    215          1.1    jruoho             ObjDesc->CommonField.BaseByteOffset,
    216          1.1    jruoho             FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
    217          1.1    jruoho             AcpiUtGetNodeName (RgnDesc->Region.Node),
    218          1.1    jruoho             RgnDesc->Region.Length));
    219          1.1    jruoho 
    220          1.1    jruoho         return_ACPI_STATUS (AE_AML_REGION_LIMIT);
    221          1.1    jruoho     }
    222          1.1    jruoho 
    223          1.1    jruoho     return_ACPI_STATUS (AE_OK);
    224          1.1    jruoho }
    225          1.1    jruoho 
    226          1.1    jruoho 
    227          1.1    jruoho /*******************************************************************************
    228          1.1    jruoho  *
    229          1.1    jruoho  * FUNCTION:    AcpiExAccessRegion
    230          1.1    jruoho  *
    231          1.1    jruoho  * PARAMETERS:  ObjDesc                 - Field to be read
    232          1.1    jruoho  *              FieldDatumByteOffset    - Byte offset of this datum within the
    233          1.1    jruoho  *                                        parent field
    234          1.1    jruoho  *              Value                   - Where to store value (must at least
    235          1.1    jruoho  *                                        64 bits)
    236          1.1    jruoho  *              Function                - Read or Write flag plus other region-
    237          1.1    jruoho  *                                        dependent flags
    238          1.1    jruoho  *
    239          1.1    jruoho  * RETURN:      Status
    240          1.1    jruoho  *
    241          1.1    jruoho  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
    242          1.1    jruoho  *
    243          1.1    jruoho  ******************************************************************************/
    244          1.1    jruoho 
    245          1.1    jruoho ACPI_STATUS
    246          1.1    jruoho AcpiExAccessRegion (
    247          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    248          1.1    jruoho     UINT32                  FieldDatumByteOffset,
    249          1.1    jruoho     UINT64                  *Value,
    250          1.1    jruoho     UINT32                  Function)
    251          1.1    jruoho {
    252          1.1    jruoho     ACPI_STATUS             Status;
    253          1.1    jruoho     ACPI_OPERAND_OBJECT     *RgnDesc;
    254          1.1    jruoho     UINT32                  RegionOffset;
    255          1.1    jruoho 
    256          1.1    jruoho 
    257          1.1    jruoho     ACPI_FUNCTION_TRACE (ExAccessRegion);
    258          1.1    jruoho 
    259          1.1    jruoho 
    260          1.1    jruoho     /*
    261          1.1    jruoho      * Ensure that the region operands are fully evaluated and verify
    262          1.1    jruoho      * the validity of the request
    263          1.1    jruoho      */
    264          1.1    jruoho     Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
    265          1.1    jruoho     if (ACPI_FAILURE (Status))
    266          1.1    jruoho     {
    267          1.1    jruoho         return_ACPI_STATUS (Status);
    268          1.1    jruoho     }
    269          1.1    jruoho 
    270          1.1    jruoho     /*
    271          1.1    jruoho      * The physical address of this field datum is:
    272          1.1    jruoho      *
    273          1.1    jruoho      * 1) The base of the region, plus
    274          1.1    jruoho      * 2) The base offset of the field, plus
    275          1.1    jruoho      * 3) The current offset into the field
    276          1.1    jruoho      */
    277          1.1    jruoho     RgnDesc = ObjDesc->CommonField.RegionObj;
    278          1.1    jruoho     RegionOffset =
    279          1.1    jruoho         ObjDesc->CommonField.BaseByteOffset +
    280          1.1    jruoho         FieldDatumByteOffset;
    281          1.1    jruoho 
    282          1.1    jruoho     if ((Function & ACPI_IO_MASK) == ACPI_READ)
    283          1.1    jruoho     {
    284          1.1    jruoho         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
    285          1.1    jruoho     }
    286          1.1    jruoho     else
    287          1.1    jruoho     {
    288          1.1    jruoho         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
    289          1.1    jruoho     }
    290          1.1    jruoho 
    291          1.1    jruoho     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
    292  1.1.1.4.2.1     skrll         " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
    293          1.1    jruoho         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
    294          1.1    jruoho         RgnDesc->Region.SpaceId,
    295          1.1    jruoho         ObjDesc->CommonField.AccessByteWidth,
    296          1.1    jruoho         ObjDesc->CommonField.BaseByteOffset,
    297          1.1    jruoho         FieldDatumByteOffset,
    298  1.1.1.4.2.1     skrll         ACPI_FORMAT_UINT64 (RgnDesc->Region.Address + RegionOffset)));
    299          1.1    jruoho 
    300          1.1    jruoho     /* Invoke the appropriate AddressSpace/OpRegion handler */
    301          1.1    jruoho 
    302      1.1.1.3  christos     Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc,
    303      1.1.1.3  christos                 Function, RegionOffset,
    304          1.1    jruoho                 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
    305          1.1    jruoho 
    306          1.1    jruoho     if (ACPI_FAILURE (Status))
    307          1.1    jruoho     {
    308          1.1    jruoho         if (Status == AE_NOT_IMPLEMENTED)
    309          1.1    jruoho         {
    310          1.1    jruoho             ACPI_ERROR ((AE_INFO,
    311      1.1.1.2    jruoho                 "Region %s (ID=%u) not implemented",
    312          1.1    jruoho                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
    313          1.1    jruoho                 RgnDesc->Region.SpaceId));
    314          1.1    jruoho         }
    315          1.1    jruoho         else if (Status == AE_NOT_EXIST)
    316          1.1    jruoho         {
    317          1.1    jruoho             ACPI_ERROR ((AE_INFO,
    318      1.1.1.2    jruoho                 "Region %s (ID=%u) has no handler",
    319          1.1    jruoho                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
    320          1.1    jruoho                 RgnDesc->Region.SpaceId));
    321          1.1    jruoho         }
    322          1.1    jruoho     }
    323          1.1    jruoho 
    324          1.1    jruoho     return_ACPI_STATUS (Status);
    325          1.1    jruoho }
    326          1.1    jruoho 
    327          1.1    jruoho 
    328          1.1    jruoho /*******************************************************************************
    329          1.1    jruoho  *
    330          1.1    jruoho  * FUNCTION:    AcpiExRegisterOverflow
    331          1.1    jruoho  *
    332          1.1    jruoho  * PARAMETERS:  ObjDesc                 - Register(Field) to be written
    333          1.1    jruoho  *              Value                   - Value to be stored
    334          1.1    jruoho  *
    335          1.1    jruoho  * RETURN:      TRUE if value overflows the field, FALSE otherwise
    336          1.1    jruoho  *
    337          1.1    jruoho  * DESCRIPTION: Check if a value is out of range of the field being written.
    338          1.1    jruoho  *              Used to check if the values written to Index and Bank registers
    339      1.1.1.3  christos  *              are out of range. Normally, the value is simply truncated
    340          1.1    jruoho  *              to fit the field, but this case is most likely a serious
    341          1.1    jruoho  *              coding error in the ASL.
    342          1.1    jruoho  *
    343          1.1    jruoho  ******************************************************************************/
    344          1.1    jruoho 
    345          1.1    jruoho static BOOLEAN
    346          1.1    jruoho AcpiExRegisterOverflow (
    347          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    348          1.1    jruoho     UINT64                  Value)
    349          1.1    jruoho {
    350          1.1    jruoho 
    351          1.1    jruoho     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
    352          1.1    jruoho     {
    353          1.1    jruoho         /*
    354          1.1    jruoho          * The field is large enough to hold the maximum integer, so we can
    355          1.1    jruoho          * never overflow it.
    356          1.1    jruoho          */
    357          1.1    jruoho         return (FALSE);
    358          1.1    jruoho     }
    359          1.1    jruoho 
    360          1.1    jruoho     if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
    361          1.1    jruoho     {
    362          1.1    jruoho         /*
    363          1.1    jruoho          * The Value is larger than the maximum value that can fit into
    364          1.1    jruoho          * the register.
    365          1.1    jruoho          */
    366      1.1.1.3  christos         ACPI_ERROR ((AE_INFO,
    367      1.1.1.3  christos             "Index value 0x%8.8X%8.8X overflows field width 0x%X",
    368      1.1.1.3  christos             ACPI_FORMAT_UINT64 (Value),
    369      1.1.1.3  christos             ObjDesc->CommonField.BitLength));
    370      1.1.1.3  christos 
    371          1.1    jruoho         return (TRUE);
    372          1.1    jruoho     }
    373          1.1    jruoho 
    374          1.1    jruoho     /* The Value will fit into the field with no truncation */
    375          1.1    jruoho 
    376          1.1    jruoho     return (FALSE);
    377          1.1    jruoho }
    378          1.1    jruoho 
    379          1.1    jruoho 
    380          1.1    jruoho /*******************************************************************************
    381          1.1    jruoho  *
    382          1.1    jruoho  * FUNCTION:    AcpiExFieldDatumIo
    383          1.1    jruoho  *
    384          1.1    jruoho  * PARAMETERS:  ObjDesc                 - Field to be read
    385          1.1    jruoho  *              FieldDatumByteOffset    - Byte offset of this datum within the
    386          1.1    jruoho  *                                        parent field
    387          1.1    jruoho  *              Value                   - Where to store value (must be 64 bits)
    388          1.1    jruoho  *              ReadWrite               - Read or Write flag
    389          1.1    jruoho  *
    390          1.1    jruoho  * RETURN:      Status
    391          1.1    jruoho  *
    392      1.1.1.3  christos  * DESCRIPTION: Read or Write a single datum of a field. The FieldType is
    393          1.1    jruoho  *              demultiplexed here to handle the different types of fields
    394          1.1    jruoho  *              (BufferField, RegionField, IndexField, BankField)
    395          1.1    jruoho  *
    396          1.1    jruoho  ******************************************************************************/
    397          1.1    jruoho 
    398          1.1    jruoho static ACPI_STATUS
    399          1.1    jruoho AcpiExFieldDatumIo (
    400          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    401          1.1    jruoho     UINT32                  FieldDatumByteOffset,
    402          1.1    jruoho     UINT64                  *Value,
    403          1.1    jruoho     UINT32                  ReadWrite)
    404          1.1    jruoho {
    405          1.1    jruoho     ACPI_STATUS             Status;
    406          1.1    jruoho     UINT64                  LocalValue;
    407          1.1    jruoho 
    408          1.1    jruoho 
    409          1.1    jruoho     ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
    410          1.1    jruoho 
    411          1.1    jruoho 
    412          1.1    jruoho     if (ReadWrite == ACPI_READ)
    413          1.1    jruoho     {
    414          1.1    jruoho         if (!Value)
    415          1.1    jruoho         {
    416          1.1    jruoho             LocalValue = 0;
    417          1.1    jruoho 
    418          1.1    jruoho             /* To support reads without saving return value */
    419          1.1    jruoho             Value = &LocalValue;
    420          1.1    jruoho         }
    421          1.1    jruoho 
    422          1.1    jruoho         /* Clear the entire return buffer first, [Very Important!] */
    423          1.1    jruoho 
    424          1.1    jruoho         *Value = 0;
    425          1.1    jruoho     }
    426          1.1    jruoho 
    427          1.1    jruoho     /*
    428          1.1    jruoho      * The four types of fields are:
    429          1.1    jruoho      *
    430          1.1    jruoho      * BufferField - Read/write from/to a Buffer
    431          1.1    jruoho      * RegionField - Read/write from/to a Operation Region.
    432          1.1    jruoho      * BankField   - Write to a Bank Register, then read/write from/to an
    433          1.1    jruoho      *               OperationRegion
    434          1.1    jruoho      * IndexField  - Write to an Index Register, then read/write from/to a
    435          1.1    jruoho      *               Data Register
    436          1.1    jruoho      */
    437          1.1    jruoho     switch (ObjDesc->Common.Type)
    438          1.1    jruoho     {
    439          1.1    jruoho     case ACPI_TYPE_BUFFER_FIELD:
    440          1.1    jruoho         /*
    441          1.1    jruoho          * If the BufferField arguments have not been previously evaluated,
    442          1.1    jruoho          * evaluate them now and save the results.
    443          1.1    jruoho          */
    444          1.1    jruoho         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
    445          1.1    jruoho         {
    446          1.1    jruoho             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
    447          1.1    jruoho             if (ACPI_FAILURE (Status))
    448          1.1    jruoho             {
    449          1.1    jruoho                 return_ACPI_STATUS (Status);
    450          1.1    jruoho             }
    451          1.1    jruoho         }
    452          1.1    jruoho 
    453          1.1    jruoho         if (ReadWrite == ACPI_READ)
    454          1.1    jruoho         {
    455          1.1    jruoho             /*
    456          1.1    jruoho              * Copy the data from the source buffer.
    457          1.1    jruoho              * Length is the field width in bytes.
    458          1.1    jruoho              */
    459  1.1.1.4.2.2     skrll             memcpy (Value,
    460          1.1    jruoho                 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
    461          1.1    jruoho                     ObjDesc->BufferField.BaseByteOffset +
    462          1.1    jruoho                     FieldDatumByteOffset,
    463          1.1    jruoho                 ObjDesc->CommonField.AccessByteWidth);
    464          1.1    jruoho         }
    465          1.1    jruoho         else
    466          1.1    jruoho         {
    467          1.1    jruoho             /*
    468          1.1    jruoho              * Copy the data to the target buffer.
    469          1.1    jruoho              * Length is the field width in bytes.
    470          1.1    jruoho              */
    471  1.1.1.4.2.2     skrll             memcpy ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
    472          1.1    jruoho                 ObjDesc->BufferField.BaseByteOffset +
    473          1.1    jruoho                 FieldDatumByteOffset,
    474          1.1    jruoho                 Value, ObjDesc->CommonField.AccessByteWidth);
    475          1.1    jruoho         }
    476          1.1    jruoho 
    477          1.1    jruoho         Status = AE_OK;
    478          1.1    jruoho         break;
    479          1.1    jruoho 
    480          1.1    jruoho     case ACPI_TYPE_LOCAL_BANK_FIELD:
    481          1.1    jruoho         /*
    482          1.1    jruoho          * Ensure that the BankValue is not beyond the capacity of
    483          1.1    jruoho          * the register
    484          1.1    jruoho          */
    485          1.1    jruoho         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
    486          1.1    jruoho                 (UINT64) ObjDesc->BankField.Value))
    487          1.1    jruoho         {
    488          1.1    jruoho             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
    489          1.1    jruoho         }
    490          1.1    jruoho 
    491          1.1    jruoho         /*
    492          1.1    jruoho          * For BankFields, we must write the BankValue to the BankRegister
    493          1.1    jruoho          * (itself a RegionField) before we can access the data.
    494          1.1    jruoho          */
    495          1.1    jruoho         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
    496          1.1    jruoho                     &ObjDesc->BankField.Value,
    497          1.1    jruoho                     sizeof (ObjDesc->BankField.Value));
    498          1.1    jruoho         if (ACPI_FAILURE (Status))
    499          1.1    jruoho         {
    500          1.1    jruoho             return_ACPI_STATUS (Status);
    501          1.1    jruoho         }
    502          1.1    jruoho 
    503          1.1    jruoho         /*
    504          1.1    jruoho          * Now that the Bank has been selected, fall through to the
    505          1.1    jruoho          * RegionField case and write the datum to the Operation Region
    506          1.1    jruoho          */
    507          1.1    jruoho 
    508          1.1    jruoho         /*lint -fallthrough */
    509          1.1    jruoho 
    510          1.1    jruoho     case ACPI_TYPE_LOCAL_REGION_FIELD:
    511          1.1    jruoho         /*
    512          1.1    jruoho          * For simple RegionFields, we just directly access the owning
    513          1.1    jruoho          * Operation Region.
    514          1.1    jruoho          */
    515          1.1    jruoho         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
    516          1.1    jruoho                     ReadWrite);
    517          1.1    jruoho         break;
    518          1.1    jruoho 
    519          1.1    jruoho     case ACPI_TYPE_LOCAL_INDEX_FIELD:
    520          1.1    jruoho         /*
    521          1.1    jruoho          * Ensure that the IndexValue is not beyond the capacity of
    522          1.1    jruoho          * the register
    523          1.1    jruoho          */
    524          1.1    jruoho         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
    525          1.1    jruoho                 (UINT64) ObjDesc->IndexField.Value))
    526          1.1    jruoho         {
    527          1.1    jruoho             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
    528          1.1    jruoho         }
    529          1.1    jruoho 
    530          1.1    jruoho         /* Write the index value to the IndexRegister (itself a RegionField) */
    531          1.1    jruoho 
    532          1.1    jruoho         FieldDatumByteOffset += ObjDesc->IndexField.Value;
    533          1.1    jruoho 
    534          1.1    jruoho         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    535          1.1    jruoho             "Write to Index Register: Value %8.8X\n",
    536          1.1    jruoho             FieldDatumByteOffset));
    537          1.1    jruoho 
    538          1.1    jruoho         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
    539          1.1    jruoho                     &FieldDatumByteOffset,
    540          1.1    jruoho                     sizeof (FieldDatumByteOffset));
    541          1.1    jruoho         if (ACPI_FAILURE (Status))
    542          1.1    jruoho         {
    543          1.1    jruoho             return_ACPI_STATUS (Status);
    544          1.1    jruoho         }
    545          1.1    jruoho 
    546          1.1    jruoho         if (ReadWrite == ACPI_READ)
    547          1.1    jruoho         {
    548          1.1    jruoho             /* Read the datum from the DataRegister */
    549          1.1    jruoho 
    550          1.1    jruoho             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    551          1.1    jruoho                 "Read from Data Register\n"));
    552          1.1    jruoho 
    553          1.1    jruoho             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
    554          1.1    jruoho                         Value, sizeof (UINT64));
    555          1.1    jruoho         }
    556          1.1    jruoho         else
    557          1.1    jruoho         {
    558          1.1    jruoho             /* Write the datum to the DataRegister */
    559          1.1    jruoho 
    560          1.1    jruoho             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    561          1.1    jruoho                 "Write to Data Register: Value %8.8X%8.8X\n",
    562          1.1    jruoho                 ACPI_FORMAT_UINT64 (*Value)));
    563          1.1    jruoho 
    564          1.1    jruoho             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
    565          1.1    jruoho                         Value, sizeof (UINT64));
    566          1.1    jruoho         }
    567          1.1    jruoho         break;
    568          1.1    jruoho 
    569          1.1    jruoho     default:
    570          1.1    jruoho 
    571          1.1    jruoho         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
    572          1.1    jruoho             ObjDesc->Common.Type));
    573          1.1    jruoho         Status = AE_AML_INTERNAL;
    574          1.1    jruoho         break;
    575          1.1    jruoho     }
    576          1.1    jruoho 
    577          1.1    jruoho     if (ACPI_SUCCESS (Status))
    578          1.1    jruoho     {
    579          1.1    jruoho         if (ReadWrite == ACPI_READ)
    580          1.1    jruoho         {
    581          1.1    jruoho             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    582          1.1    jruoho                 "Value Read %8.8X%8.8X, Width %u\n",
    583          1.1    jruoho                 ACPI_FORMAT_UINT64 (*Value),
    584          1.1    jruoho                 ObjDesc->CommonField.AccessByteWidth));
    585          1.1    jruoho         }
    586          1.1    jruoho         else
    587          1.1    jruoho         {
    588          1.1    jruoho             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    589          1.1    jruoho                 "Value Written %8.8X%8.8X, Width %u\n",
    590          1.1    jruoho                 ACPI_FORMAT_UINT64 (*Value),
    591          1.1    jruoho                 ObjDesc->CommonField.AccessByteWidth));
    592          1.1    jruoho         }
    593          1.1    jruoho     }
    594          1.1    jruoho 
    595          1.1    jruoho     return_ACPI_STATUS (Status);
    596          1.1    jruoho }
    597          1.1    jruoho 
    598          1.1    jruoho 
    599          1.1    jruoho /*******************************************************************************
    600          1.1    jruoho  *
    601          1.1    jruoho  * FUNCTION:    AcpiExWriteWithUpdateRule
    602          1.1    jruoho  *
    603          1.1    jruoho  * PARAMETERS:  ObjDesc                 - Field to be written
    604          1.1    jruoho  *              Mask                    - bitmask within field datum
    605          1.1    jruoho  *              FieldValue              - Value to write
    606          1.1    jruoho  *              FieldDatumByteOffset    - Offset of datum within field
    607          1.1    jruoho  *
    608          1.1    jruoho  * RETURN:      Status
    609          1.1    jruoho  *
    610          1.1    jruoho  * DESCRIPTION: Apply the field update rule to a field write
    611          1.1    jruoho  *
    612          1.1    jruoho  ******************************************************************************/
    613          1.1    jruoho 
    614          1.1    jruoho ACPI_STATUS
    615          1.1    jruoho AcpiExWriteWithUpdateRule (
    616          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    617          1.1    jruoho     UINT64                  Mask,
    618          1.1    jruoho     UINT64                  FieldValue,
    619          1.1    jruoho     UINT32                  FieldDatumByteOffset)
    620          1.1    jruoho {
    621          1.1    jruoho     ACPI_STATUS             Status = AE_OK;
    622          1.1    jruoho     UINT64                  MergedValue;
    623          1.1    jruoho     UINT64                  CurrentValue;
    624          1.1    jruoho 
    625          1.1    jruoho 
    626          1.1    jruoho     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
    627          1.1    jruoho 
    628          1.1    jruoho 
    629          1.1    jruoho     /* Start with the new bits  */
    630          1.1    jruoho 
    631          1.1    jruoho     MergedValue = FieldValue;
    632          1.1    jruoho 
    633          1.1    jruoho     /* If the mask is all ones, we don't need to worry about the update rule */
    634          1.1    jruoho 
    635          1.1    jruoho     if (Mask != ACPI_UINT64_MAX)
    636          1.1    jruoho     {
    637          1.1    jruoho         /* Decode the update rule */
    638          1.1    jruoho 
    639          1.1    jruoho         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
    640          1.1    jruoho         {
    641          1.1    jruoho         case AML_FIELD_UPDATE_PRESERVE:
    642          1.1    jruoho             /*
    643          1.1    jruoho              * Check if update rule needs to be applied (not if mask is all
    644          1.1    jruoho              * ones)  The left shift drops the bits we want to ignore.
    645          1.1    jruoho              */
    646          1.1    jruoho             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
    647          1.1    jruoho                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
    648          1.1    jruoho             {
    649          1.1    jruoho                 /*
    650          1.1    jruoho                  * Read the current contents of the byte/word/dword containing
    651          1.1    jruoho                  * the field, and merge with the new field value.
    652          1.1    jruoho                  */
    653          1.1    jruoho                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
    654          1.1    jruoho                             &CurrentValue, ACPI_READ);
    655          1.1    jruoho                 if (ACPI_FAILURE (Status))
    656          1.1    jruoho                 {
    657          1.1    jruoho                     return_ACPI_STATUS (Status);
    658          1.1    jruoho                 }
    659          1.1    jruoho 
    660          1.1    jruoho                 MergedValue |= (CurrentValue & ~Mask);
    661          1.1    jruoho             }
    662          1.1    jruoho             break;
    663          1.1    jruoho 
    664          1.1    jruoho         case AML_FIELD_UPDATE_WRITE_AS_ONES:
    665          1.1    jruoho 
    666          1.1    jruoho             /* Set positions outside the field to all ones */
    667          1.1    jruoho 
    668          1.1    jruoho             MergedValue |= ~Mask;
    669          1.1    jruoho             break;
    670          1.1    jruoho 
    671          1.1    jruoho         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
    672          1.1    jruoho 
    673          1.1    jruoho             /* Set positions outside the field to all zeros */
    674          1.1    jruoho 
    675          1.1    jruoho             MergedValue &= Mask;
    676          1.1    jruoho             break;
    677          1.1    jruoho 
    678          1.1    jruoho         default:
    679          1.1    jruoho 
    680          1.1    jruoho             ACPI_ERROR ((AE_INFO,
    681          1.1    jruoho                 "Unknown UpdateRule value: 0x%X",
    682          1.1    jruoho                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
    683          1.1    jruoho             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
    684          1.1    jruoho         }
    685          1.1    jruoho     }
    686          1.1    jruoho 
    687          1.1    jruoho     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    688          1.1    jruoho         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
    689          1.1    jruoho         ACPI_FORMAT_UINT64 (Mask),
    690          1.1    jruoho         FieldDatumByteOffset,
    691          1.1    jruoho         ObjDesc->CommonField.AccessByteWidth,
    692          1.1    jruoho         ACPI_FORMAT_UINT64 (FieldValue),
    693          1.1    jruoho         ACPI_FORMAT_UINT64 (MergedValue)));
    694          1.1    jruoho 
    695          1.1    jruoho     /* Write the merged value */
    696          1.1    jruoho 
    697          1.1    jruoho     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
    698          1.1    jruoho                 &MergedValue, ACPI_WRITE);
    699          1.1    jruoho 
    700          1.1    jruoho     return_ACPI_STATUS (Status);
    701          1.1    jruoho }
    702          1.1    jruoho 
    703          1.1    jruoho 
    704          1.1    jruoho /*******************************************************************************
    705          1.1    jruoho  *
    706          1.1    jruoho  * FUNCTION:    AcpiExExtractFromField
    707          1.1    jruoho  *
    708          1.1    jruoho  * PARAMETERS:  ObjDesc             - Field to be read
    709          1.1    jruoho  *              Buffer              - Where to store the field data
    710          1.1    jruoho  *              BufferLength        - Length of Buffer
    711          1.1    jruoho  *
    712          1.1    jruoho  * RETURN:      Status
    713          1.1    jruoho  *
    714          1.1    jruoho  * DESCRIPTION: Retrieve the current value of the given field
    715          1.1    jruoho  *
    716          1.1    jruoho  ******************************************************************************/
    717          1.1    jruoho 
    718          1.1    jruoho ACPI_STATUS
    719          1.1    jruoho AcpiExExtractFromField (
    720          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    721          1.1    jruoho     void                    *Buffer,
    722          1.1    jruoho     UINT32                  BufferLength)
    723          1.1    jruoho {
    724          1.1    jruoho     ACPI_STATUS             Status;
    725          1.1    jruoho     UINT64                  RawDatum;
    726          1.1    jruoho     UINT64                  MergedDatum;
    727          1.1    jruoho     UINT32                  FieldOffset = 0;
    728          1.1    jruoho     UINT32                  BufferOffset = 0;
    729          1.1    jruoho     UINT32                  BufferTailBits;
    730          1.1    jruoho     UINT32                  DatumCount;
    731          1.1    jruoho     UINT32                  FieldDatumCount;
    732          1.1    jruoho     UINT32                  AccessBitWidth;
    733          1.1    jruoho     UINT32                  i;
    734          1.1    jruoho 
    735          1.1    jruoho 
    736          1.1    jruoho     ACPI_FUNCTION_TRACE (ExExtractFromField);
    737          1.1    jruoho 
    738          1.1    jruoho 
    739          1.1    jruoho     /* Validate target buffer and clear it */
    740          1.1    jruoho 
    741          1.1    jruoho     if (BufferLength <
    742          1.1    jruoho         ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
    743          1.1    jruoho     {
    744          1.1    jruoho         ACPI_ERROR ((AE_INFO,
    745          1.1    jruoho             "Field size %u (bits) is too large for buffer (%u)",
    746          1.1    jruoho             ObjDesc->CommonField.BitLength, BufferLength));
    747          1.1    jruoho 
    748          1.1    jruoho         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
    749          1.1    jruoho     }
    750          1.1    jruoho 
    751  1.1.1.4.2.2     skrll     memset (Buffer, 0, BufferLength);
    752          1.1    jruoho     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
    753          1.1    jruoho 
    754          1.1    jruoho     /* Handle the simple case here */
    755          1.1    jruoho 
    756          1.1    jruoho     if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
    757          1.1    jruoho         (ObjDesc->CommonField.BitLength == AccessBitWidth))
    758          1.1    jruoho     {
    759      1.1.1.3  christos         if (BufferLength >= sizeof (UINT64))
    760      1.1.1.3  christos         {
    761      1.1.1.3  christos             Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
    762      1.1.1.3  christos         }
    763      1.1.1.3  christos         else
    764      1.1.1.3  christos         {
    765      1.1.1.3  christos             /* Use RawDatum (UINT64) to handle buffers < 64 bits */
    766      1.1.1.3  christos 
    767      1.1.1.3  christos             Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ);
    768  1.1.1.4.2.2     skrll             memcpy (Buffer, &RawDatum, BufferLength);
    769      1.1.1.3  christos         }
    770      1.1.1.3  christos 
    771          1.1    jruoho         return_ACPI_STATUS (Status);
    772          1.1    jruoho     }
    773          1.1    jruoho 
    774          1.1    jruoho /* TBD: Move to common setup code */
    775          1.1    jruoho 
    776          1.1    jruoho     /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
    777          1.1    jruoho 
    778          1.1    jruoho     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    779          1.1    jruoho     {
    780          1.1    jruoho         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
    781          1.1    jruoho         AccessBitWidth = sizeof (UINT64) * 8;
    782          1.1    jruoho     }
    783          1.1    jruoho 
    784          1.1    jruoho     /* Compute the number of datums (access width data items) */
    785          1.1    jruoho 
    786          1.1    jruoho     DatumCount = ACPI_ROUND_UP_TO (
    787          1.1    jruoho         ObjDesc->CommonField.BitLength, AccessBitWidth);
    788          1.1    jruoho 
    789          1.1    jruoho     FieldDatumCount = ACPI_ROUND_UP_TO (
    790          1.1    jruoho         ObjDesc->CommonField.BitLength +
    791          1.1    jruoho         ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
    792          1.1    jruoho 
    793          1.1    jruoho     /* Priming read from the field */
    794          1.1    jruoho 
    795          1.1    jruoho     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
    796          1.1    jruoho     if (ACPI_FAILURE (Status))
    797          1.1    jruoho     {
    798          1.1    jruoho         return_ACPI_STATUS (Status);
    799          1.1    jruoho     }
    800          1.1    jruoho     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
    801          1.1    jruoho 
    802          1.1    jruoho     /* Read the rest of the field */
    803          1.1    jruoho 
    804          1.1    jruoho     for (i = 1; i < FieldDatumCount; i++)
    805          1.1    jruoho     {
    806          1.1    jruoho         /* Get next input datum from the field */
    807          1.1    jruoho 
    808          1.1    jruoho         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
    809          1.1    jruoho         Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
    810          1.1    jruoho                     &RawDatum, ACPI_READ);
    811          1.1    jruoho         if (ACPI_FAILURE (Status))
    812          1.1    jruoho         {
    813          1.1    jruoho             return_ACPI_STATUS (Status);
    814          1.1    jruoho         }
    815          1.1    jruoho 
    816          1.1    jruoho         /*
    817          1.1    jruoho          * Merge with previous datum if necessary.
    818          1.1    jruoho          *
    819          1.1    jruoho          * Note: Before the shift, check if the shift value will be larger than
    820          1.1    jruoho          * the integer size. If so, there is no need to perform the operation.
    821          1.1    jruoho          * This avoids the differences in behavior between different compilers
    822          1.1    jruoho          * concerning shift values larger than the target data width.
    823          1.1    jruoho          */
    824          1.1    jruoho         if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
    825          1.1    jruoho             ACPI_INTEGER_BIT_SIZE)
    826          1.1    jruoho         {
    827          1.1    jruoho             MergedDatum |= RawDatum <<
    828          1.1    jruoho                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
    829          1.1    jruoho         }
    830          1.1    jruoho 
    831          1.1    jruoho         if (i == DatumCount)
    832          1.1    jruoho         {
    833          1.1    jruoho             break;
    834          1.1    jruoho         }
    835          1.1    jruoho 
    836          1.1    jruoho         /* Write merged datum to target buffer */
    837          1.1    jruoho 
    838  1.1.1.4.2.2     skrll         memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
    839          1.1    jruoho             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    840          1.1    jruoho                 BufferLength - BufferOffset));
    841          1.1    jruoho 
    842          1.1    jruoho         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
    843          1.1    jruoho         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
    844          1.1    jruoho     }
    845          1.1    jruoho 
    846          1.1    jruoho     /* Mask off any extra bits in the last datum */
    847          1.1    jruoho 
    848          1.1    jruoho     BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
    849          1.1    jruoho     if (BufferTailBits)
    850          1.1    jruoho     {
    851          1.1    jruoho         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
    852          1.1    jruoho     }
    853          1.1    jruoho 
    854          1.1    jruoho     /* Write the last datum to the buffer */
    855          1.1    jruoho 
    856  1.1.1.4.2.2     skrll     memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
    857          1.1    jruoho         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    858          1.1    jruoho             BufferLength - BufferOffset));
    859          1.1    jruoho 
    860          1.1    jruoho     return_ACPI_STATUS (AE_OK);
    861          1.1    jruoho }
    862          1.1    jruoho 
    863          1.1    jruoho 
    864          1.1    jruoho /*******************************************************************************
    865          1.1    jruoho  *
    866          1.1    jruoho  * FUNCTION:    AcpiExInsertIntoField
    867          1.1    jruoho  *
    868          1.1    jruoho  * PARAMETERS:  ObjDesc             - Field to be written
    869          1.1    jruoho  *              Buffer              - Data to be written
    870          1.1    jruoho  *              BufferLength        - Length of Buffer
    871          1.1    jruoho  *
    872          1.1    jruoho  * RETURN:      Status
    873          1.1    jruoho  *
    874          1.1    jruoho  * DESCRIPTION: Store the Buffer contents into the given field
    875          1.1    jruoho  *
    876          1.1    jruoho  ******************************************************************************/
    877          1.1    jruoho 
    878          1.1    jruoho ACPI_STATUS
    879          1.1    jruoho AcpiExInsertIntoField (
    880          1.1    jruoho     ACPI_OPERAND_OBJECT     *ObjDesc,
    881          1.1    jruoho     void                    *Buffer,
    882          1.1    jruoho     UINT32                  BufferLength)
    883          1.1    jruoho {
    884          1.1    jruoho     void                    *NewBuffer;
    885          1.1    jruoho     ACPI_STATUS             Status;
    886          1.1    jruoho     UINT64                  Mask;
    887          1.1    jruoho     UINT64                  WidthMask;
    888          1.1    jruoho     UINT64                  MergedDatum;
    889          1.1    jruoho     UINT64                  RawDatum = 0;
    890          1.1    jruoho     UINT32                  FieldOffset = 0;
    891          1.1    jruoho     UINT32                  BufferOffset = 0;
    892          1.1    jruoho     UINT32                  BufferTailBits;
    893          1.1    jruoho     UINT32                  DatumCount;
    894          1.1    jruoho     UINT32                  FieldDatumCount;
    895          1.1    jruoho     UINT32                  AccessBitWidth;
    896          1.1    jruoho     UINT32                  RequiredLength;
    897          1.1    jruoho     UINT32                  i;
    898          1.1    jruoho 
    899          1.1    jruoho 
    900          1.1    jruoho     ACPI_FUNCTION_TRACE (ExInsertIntoField);
    901          1.1    jruoho 
    902          1.1    jruoho 
    903          1.1    jruoho     /* Validate input buffer */
    904          1.1    jruoho 
    905          1.1    jruoho     NewBuffer = NULL;
    906          1.1    jruoho     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
    907          1.1    jruoho                         ObjDesc->CommonField.BitLength);
    908          1.1    jruoho     /*
    909          1.1    jruoho      * We must have a buffer that is at least as long as the field
    910      1.1.1.3  christos      * we are writing to. This is because individual fields are
    911          1.1    jruoho      * indivisible and partial writes are not supported -- as per
    912          1.1    jruoho      * the ACPI specification.
    913          1.1    jruoho      */
    914          1.1    jruoho     if (BufferLength < RequiredLength)
    915          1.1    jruoho     {
    916          1.1    jruoho         /* We need to create a new buffer */
    917          1.1    jruoho 
    918          1.1    jruoho         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
    919          1.1    jruoho         if (!NewBuffer)
    920          1.1    jruoho         {
    921          1.1    jruoho             return_ACPI_STATUS (AE_NO_MEMORY);
    922          1.1    jruoho         }
    923          1.1    jruoho 
    924          1.1    jruoho         /*
    925          1.1    jruoho          * Copy the original data to the new buffer, starting
    926      1.1.1.3  christos          * at Byte zero. All unused (upper) bytes of the
    927          1.1    jruoho          * buffer will be 0.
    928          1.1    jruoho          */
    929  1.1.1.4.2.2     skrll         memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength);
    930          1.1    jruoho         Buffer = NewBuffer;
    931          1.1    jruoho         BufferLength = RequiredLength;
    932          1.1    jruoho     }
    933          1.1    jruoho 
    934          1.1    jruoho /* TBD: Move to common setup code */
    935          1.1    jruoho 
    936          1.1    jruoho     /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
    937          1.1    jruoho     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    938          1.1    jruoho     {
    939          1.1    jruoho         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
    940          1.1    jruoho     }
    941          1.1    jruoho 
    942          1.1    jruoho     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
    943          1.1    jruoho 
    944          1.1    jruoho     /*
    945          1.1    jruoho      * Create the bitmasks used for bit insertion.
    946          1.1    jruoho      * Note: This if/else is used to bypass compiler differences with the
    947          1.1    jruoho      * shift operator
    948          1.1    jruoho      */
    949          1.1    jruoho     if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
    950          1.1    jruoho     {
    951          1.1    jruoho         WidthMask = ACPI_UINT64_MAX;
    952          1.1    jruoho     }
    953          1.1    jruoho     else
    954          1.1    jruoho     {
    955          1.1    jruoho         WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
    956          1.1    jruoho     }
    957          1.1    jruoho 
    958          1.1    jruoho     Mask = WidthMask &
    959          1.1    jruoho         ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
    960          1.1    jruoho 
    961          1.1    jruoho     /* Compute the number of datums (access width data items) */
    962          1.1    jruoho 
    963          1.1    jruoho     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
    964          1.1    jruoho         AccessBitWidth);
    965          1.1    jruoho 
    966          1.1    jruoho     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
    967          1.1    jruoho         ObjDesc->CommonField.StartFieldBitOffset,
    968          1.1    jruoho         AccessBitWidth);
    969          1.1    jruoho 
    970          1.1    jruoho     /* Get initial Datum from the input buffer */
    971          1.1    jruoho 
    972  1.1.1.4.2.2     skrll     memcpy (&RawDatum, Buffer,
    973          1.1    jruoho         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    974          1.1    jruoho             BufferLength - BufferOffset));
    975          1.1    jruoho 
    976          1.1    jruoho     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
    977          1.1    jruoho 
    978          1.1    jruoho     /* Write the entire field */
    979          1.1    jruoho 
    980          1.1    jruoho     for (i = 1; i < FieldDatumCount; i++)
    981          1.1    jruoho     {
    982          1.1    jruoho         /* Write merged datum to the target field */
    983          1.1    jruoho 
    984          1.1    jruoho         MergedDatum &= Mask;
    985          1.1    jruoho         Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
    986          1.1    jruoho                     MergedDatum, FieldOffset);
    987          1.1    jruoho         if (ACPI_FAILURE (Status))
    988          1.1    jruoho         {
    989          1.1    jruoho             goto Exit;
    990          1.1    jruoho         }
    991          1.1    jruoho 
    992          1.1    jruoho         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
    993          1.1    jruoho 
    994          1.1    jruoho         /*
    995          1.1    jruoho          * Start new output datum by merging with previous input datum
    996          1.1    jruoho          * if necessary.
    997          1.1    jruoho          *
    998          1.1    jruoho          * Note: Before the shift, check if the shift value will be larger than
    999          1.1    jruoho          * the integer size. If so, there is no need to perform the operation.
   1000          1.1    jruoho          * This avoids the differences in behavior between different compilers
   1001          1.1    jruoho          * concerning shift values larger than the target data width.
   1002          1.1    jruoho          */
   1003          1.1    jruoho         if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
   1004          1.1    jruoho             ACPI_INTEGER_BIT_SIZE)
   1005          1.1    jruoho         {
   1006          1.1    jruoho             MergedDatum = RawDatum >>
   1007          1.1    jruoho                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
   1008          1.1    jruoho         }
   1009          1.1    jruoho         else
   1010          1.1    jruoho         {
   1011          1.1    jruoho             MergedDatum = 0;
   1012          1.1    jruoho         }
   1013          1.1    jruoho 
   1014          1.1    jruoho         Mask = WidthMask;
   1015          1.1    jruoho 
   1016          1.1    jruoho         if (i == DatumCount)
   1017          1.1    jruoho         {
   1018          1.1    jruoho             break;
   1019          1.1    jruoho         }
   1020          1.1    jruoho 
   1021          1.1    jruoho         /* Get the next input datum from the buffer */
   1022          1.1    jruoho 
   1023          1.1    jruoho         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
   1024  1.1.1.4.2.2     skrll         memcpy (&RawDatum, ((char *) Buffer) + BufferOffset,
   1025          1.1    jruoho             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
   1026          1.1    jruoho                  BufferLength - BufferOffset));
   1027          1.1    jruoho 
   1028          1.1    jruoho         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
   1029          1.1    jruoho     }
   1030          1.1    jruoho 
   1031          1.1    jruoho     /* Mask off any extra bits in the last datum */
   1032          1.1    jruoho 
   1033          1.1    jruoho     BufferTailBits = (ObjDesc->CommonField.BitLength +
   1034          1.1    jruoho         ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
   1035          1.1    jruoho     if (BufferTailBits)
   1036          1.1    jruoho     {
   1037          1.1    jruoho         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
   1038          1.1    jruoho     }
   1039          1.1    jruoho 
   1040          1.1    jruoho     /* Write the last datum to the field */
   1041          1.1    jruoho 
   1042          1.1    jruoho     MergedDatum &= Mask;
   1043          1.1    jruoho     Status = AcpiExWriteWithUpdateRule (ObjDesc,
   1044          1.1    jruoho                 Mask, MergedDatum, FieldOffset);
   1045          1.1    jruoho 
   1046          1.1    jruoho Exit:
   1047          1.1    jruoho     /* Free temporary buffer if we used one */
   1048          1.1    jruoho 
   1049          1.1    jruoho     if (NewBuffer)
   1050          1.1    jruoho     {
   1051          1.1    jruoho         ACPI_FREE (NewBuffer);
   1052          1.1    jruoho     }
   1053          1.1    jruoho     return_ACPI_STATUS (Status);
   1054          1.1    jruoho }
   1055