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