exfldio.c revision 245582
167754Smsmith/****************************************************************************** 267754Smsmith * 377424Smsmith * Module Name: exfldio - Aml Field I/O 467754Smsmith * 567754Smsmith *****************************************************************************/ 667754Smsmith 7217365Sjkim/* 8245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp. 970243Smsmith * All rights reserved. 1067754Smsmith * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 2567754Smsmith * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 2967754Smsmith * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 4367754Smsmith 4467754Smsmith 4577424Smsmith#define __EXFLDIO_C__ 4667754Smsmith 47193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 48193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 49193341Sjkim#include <contrib/dev/acpica/include/acinterp.h> 50193341Sjkim#include <contrib/dev/acpica/include/amlcode.h> 51193341Sjkim#include <contrib/dev/acpica/include/acevents.h> 52193341Sjkim#include <contrib/dev/acpica/include/acdispat.h> 5367754Smsmith 5467754Smsmith 5577424Smsmith#define _COMPONENT ACPI_EXECUTER 5691116Smsmith ACPI_MODULE_NAME ("exfldio") 5767754Smsmith 58151937Sjkim/* Local prototypes */ 5967754Smsmith 60151937Sjkimstatic ACPI_STATUS 61151937SjkimAcpiExFieldDatumIo ( 62151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 63151937Sjkim UINT32 FieldDatumByteOffset, 64202771Sjkim UINT64 *Value, 65151937Sjkim UINT32 ReadWrite); 66151937Sjkim 67151937Sjkimstatic BOOLEAN 68151937SjkimAcpiExRegisterOverflow ( 69151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 70202771Sjkim UINT64 Value); 71151937Sjkim 72151937Sjkimstatic ACPI_STATUS 73151937SjkimAcpiExSetupRegion ( 74151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 75151937Sjkim UINT32 FieldDatumByteOffset); 76151937Sjkim 77151937Sjkim 7867754Smsmith/******************************************************************************* 7967754Smsmith * 8087031Smsmith * FUNCTION: AcpiExSetupRegion 8167754Smsmith * 82151937Sjkim * PARAMETERS: ObjDesc - Field to be read or written 8387031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 8487031Smsmith * parent field 8567754Smsmith * 8667754Smsmith * RETURN: Status 8767754Smsmith * 8877424Smsmith * DESCRIPTION: Common processing for AcpiExExtractFromField and 89241973Sjkim * AcpiExInsertIntoField. Initialize the Region if necessary and 90123315Snjl * validate the request. 9167754Smsmith * 9267754Smsmith ******************************************************************************/ 9367754Smsmith 94151937Sjkimstatic ACPI_STATUS 9587031SmsmithAcpiExSetupRegion ( 9667754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 9777424Smsmith UINT32 FieldDatumByteOffset) 9867754Smsmith{ 9977424Smsmith ACPI_STATUS Status = AE_OK; 10077424Smsmith ACPI_OPERAND_OBJECT *RgnDesc; 101228110Sjkim UINT8 SpaceId; 10267754Smsmith 10367754Smsmith 104167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset); 10567754Smsmith 10683174Smsmith 10777424Smsmith RgnDesc = ObjDesc->CommonField.RegionObj; 10867754Smsmith 109107325Siwasaki /* We must have a valid region */ 110107325Siwasaki 111193267Sjkim if (RgnDesc->Common.Type != ACPI_TYPE_REGION) 11277424Smsmith { 113204773Sjkim ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", 114193267Sjkim RgnDesc->Common.Type, 11599679Siwasaki AcpiUtGetObjectTypeName (RgnDesc))); 11699679Siwasaki 11777424Smsmith return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 11877424Smsmith } 11967754Smsmith 120228110Sjkim SpaceId = RgnDesc->Region.SpaceId; 121228110Sjkim 122228110Sjkim /* Validate the Space ID */ 123228110Sjkim 124228110Sjkim if (!AcpiIsValidSpaceId (SpaceId)) 125228110Sjkim { 126228110Sjkim ACPI_ERROR ((AE_INFO, "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId)); 127228110Sjkim return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID); 128228110Sjkim } 129228110Sjkim 13077424Smsmith /* 13177424Smsmith * If the Region Address and Length have not been previously evaluated, 13277424Smsmith * evaluate them now and save the results. 13377424Smsmith */ 134123315Snjl if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) 13567754Smsmith { 13677424Smsmith Status = AcpiDsGetRegionArguments (RgnDesc); 13777424Smsmith if (ACPI_FAILURE (Status)) 13877424Smsmith { 13977424Smsmith return_ACPI_STATUS (Status); 14077424Smsmith } 14167754Smsmith } 14267754Smsmith 143167802Sjkim /* 144228110Sjkim * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear 145210976Sjkim * address space and the request cannot be directly validated 146167802Sjkim */ 147228110Sjkim if (SpaceId == ACPI_ADR_SPACE_SMBUS || 148228110Sjkim SpaceId == ACPI_ADR_SPACE_GSBUS || 149228110Sjkim SpaceId == ACPI_ADR_SPACE_IPMI) 150107325Siwasaki { 151197104Sjkim /* SMBus or IPMI has a non-linear address space */ 152107325Siwasaki 153107325Siwasaki return_ACPI_STATUS (AE_OK); 154107325Siwasaki } 155107325Siwasaki 156123315Snjl#ifdef ACPI_UNDER_DEVELOPMENT 15777424Smsmith /* 158123315Snjl * If the Field access is AnyAcc, we can now compute the optimal 159123315Snjl * access (because we know know the length of the parent region) 160123315Snjl */ 161123315Snjl if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 162123315Snjl { 163123315Snjl if (ACPI_FAILURE (Status)) 164123315Snjl { 165123315Snjl return_ACPI_STATUS (Status); 166123315Snjl } 167123315Snjl } 168123315Snjl#endif 169123315Snjl 170123315Snjl /* 171241973Sjkim * Validate the request. The entire request from the byte offset for a 17277424Smsmith * length of one field datum (access width) must fit within the region. 17377424Smsmith * (Region length is specified in bytes) 17477424Smsmith */ 175167802Sjkim if (RgnDesc->Region.Length < 176210976Sjkim (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset + 177167802Sjkim ObjDesc->CommonField.AccessByteWidth)) 17877424Smsmith { 179138287Smarks if (AcpiGbl_EnableInterpreterSlack) 180138287Smarks { 181138287Smarks /* 182138287Smarks * Slack mode only: We will go ahead and allow access to this 183138287Smarks * field if it is within the region length rounded up to the next 184193267Sjkim * access width boundary. ACPI_SIZE cast for 64-bit compile. 185138287Smarks */ 186138287Smarks if (ACPI_ROUND_UP (RgnDesc->Region.Length, 187167802Sjkim ObjDesc->CommonField.AccessByteWidth) >= 188193267Sjkim ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset + 189193267Sjkim ObjDesc->CommonField.AccessByteWidth + 190193267Sjkim FieldDatumByteOffset)) 191138287Smarks { 192138287Smarks return_ACPI_STATUS (AE_OK); 193138287Smarks } 194138287Smarks } 195138287Smarks 19677424Smsmith if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) 19777424Smsmith { 19883174Smsmith /* 19977424Smsmith * This is the case where the AccessType (AccWord, etc.) is wider 200241973Sjkim * than the region itself. For example, a region of length one 20177424Smsmith * byte, and a field with Dword access specified. 20277424Smsmith */ 203167802Sjkim ACPI_ERROR ((AE_INFO, 204204773Sjkim "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)", 205123315Snjl AcpiUtGetNodeName (ObjDesc->CommonField.Node), 206123315Snjl ObjDesc->CommonField.AccessByteWidth, 207151937Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 208151937Sjkim RgnDesc->Region.Length)); 20977424Smsmith } 21077424Smsmith 21177424Smsmith /* 21277424Smsmith * Offset rounded up to next multiple of field width 21377424Smsmith * exceeds region length, indicate an error 21477424Smsmith */ 215167802Sjkim ACPI_ERROR ((AE_INFO, 216204773Sjkim "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)", 217123315Snjl AcpiUtGetNodeName (ObjDesc->CommonField.Node), 218123315Snjl ObjDesc->CommonField.BaseByteOffset, 21991116Smsmith FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, 220151937Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 221151937Sjkim RgnDesc->Region.Length)); 22277424Smsmith 22377424Smsmith return_ACPI_STATUS (AE_AML_REGION_LIMIT); 22477424Smsmith } 22577424Smsmith 22677424Smsmith return_ACPI_STATUS (AE_OK); 22777424Smsmith} 22877424Smsmith 22977424Smsmith 23077424Smsmith/******************************************************************************* 23177424Smsmith * 23287031Smsmith * FUNCTION: AcpiExAccessRegion 23377424Smsmith * 234151937Sjkim * PARAMETERS: ObjDesc - Field to be read 23587031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 23687031Smsmith * parent field 237151937Sjkim * Value - Where to store value (must at least 238202771Sjkim * 64 bits) 239107325Siwasaki * Function - Read or Write flag plus other region- 240107325Siwasaki * dependent flags 24177424Smsmith * 24277424Smsmith * RETURN: Status 24377424Smsmith * 24487031Smsmith * DESCRIPTION: Read or Write a single field datum to an Operation Region. 24577424Smsmith * 24677424Smsmith ******************************************************************************/ 24777424Smsmith 24877424SmsmithACPI_STATUS 24987031SmsmithAcpiExAccessRegion ( 25077424Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 25177424Smsmith UINT32 FieldDatumByteOffset, 252202771Sjkim UINT64 *Value, 253107325Siwasaki UINT32 Function) 25477424Smsmith{ 25577424Smsmith ACPI_STATUS Status; 25677424Smsmith ACPI_OPERAND_OBJECT *RgnDesc; 257193267Sjkim UINT32 RegionOffset; 25877424Smsmith 25977424Smsmith 260167802Sjkim ACPI_FUNCTION_TRACE (ExAccessRegion); 26177424Smsmith 26277424Smsmith 263114237Snjl /* 264107325Siwasaki * Ensure that the region operands are fully evaluated and verify 265107325Siwasaki * the validity of the request 266107325Siwasaki */ 267107325Siwasaki Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); 268107325Siwasaki if (ACPI_FAILURE (Status)) 269107325Siwasaki { 270107325Siwasaki return_ACPI_STATUS (Status); 271107325Siwasaki } 272107325Siwasaki 27387031Smsmith /* 27487031Smsmith * The physical address of this field datum is: 27587031Smsmith * 27687031Smsmith * 1) The base of the region, plus 27787031Smsmith * 2) The base offset of the field, plus 27887031Smsmith * 3) The current offset into the field 27987031Smsmith */ 28087031Smsmith RgnDesc = ObjDesc->CommonField.RegionObj; 281193267Sjkim RegionOffset = 282193267Sjkim ObjDesc->CommonField.BaseByteOffset + 283193267Sjkim FieldDatumByteOffset; 28487031Smsmith 285107325Siwasaki if ((Function & ACPI_IO_MASK) == ACPI_READ) 28667754Smsmith { 28787031Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); 28867754Smsmith } 28987031Smsmith else 29087031Smsmith { 29187031Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); 29287031Smsmith } 29367754Smsmith 29487031Smsmith ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, 295167802Sjkim " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", 29687031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 29787031Smsmith RgnDesc->Region.SpaceId, 29891116Smsmith ObjDesc->CommonField.AccessByteWidth, 29987031Smsmith ObjDesc->CommonField.BaseByteOffset, 30087031Smsmith FieldDatumByteOffset, 301193267Sjkim ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset)))); 30267754Smsmith 30387031Smsmith /* Invoke the appropriate AddressSpace/OpRegion handler */ 30477424Smsmith 305228110Sjkim Status = AcpiEvAddressSpaceDispatch (RgnDesc, ObjDesc, 306228110Sjkim Function, RegionOffset, 307151937Sjkim ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); 30887031Smsmith 30987031Smsmith if (ACPI_FAILURE (Status)) 31087031Smsmith { 31187031Smsmith if (Status == AE_NOT_IMPLEMENTED) 31287031Smsmith { 313167802Sjkim ACPI_ERROR ((AE_INFO, 314218590Sjkim "Region %s (ID=%u) not implemented", 31587031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 31687031Smsmith RgnDesc->Region.SpaceId)); 31787031Smsmith } 31887031Smsmith else if (Status == AE_NOT_EXIST) 31987031Smsmith { 320167802Sjkim ACPI_ERROR ((AE_INFO, 321218590Sjkim "Region %s (ID=%u) has no handler", 32287031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 32387031Smsmith RgnDesc->Region.SpaceId)); 32487031Smsmith } 32587031Smsmith } 32687031Smsmith 32787031Smsmith return_ACPI_STATUS (Status); 32887031Smsmith} 32987031Smsmith 33087031Smsmith 33187031Smsmith/******************************************************************************* 33287031Smsmith * 33387031Smsmith * FUNCTION: AcpiExRegisterOverflow 33487031Smsmith * 335151937Sjkim * PARAMETERS: ObjDesc - Register(Field) to be written 33687031Smsmith * Value - Value to be stored 33787031Smsmith * 33887031Smsmith * RETURN: TRUE if value overflows the field, FALSE otherwise 33987031Smsmith * 34087031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written. 34187031Smsmith * Used to check if the values written to Index and Bank registers 342241973Sjkim * are out of range. Normally, the value is simply truncated 34387031Smsmith * to fit the field, but this case is most likely a serious 34487031Smsmith * coding error in the ASL. 34587031Smsmith * 34687031Smsmith ******************************************************************************/ 34787031Smsmith 348151937Sjkimstatic BOOLEAN 34987031SmsmithAcpiExRegisterOverflow ( 35087031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 351202771Sjkim UINT64 Value) 35287031Smsmith{ 35387031Smsmith 35491116Smsmith if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) 35591116Smsmith { 35691116Smsmith /* 35791116Smsmith * The field is large enough to hold the maximum integer, so we can 35891116Smsmith * never overflow it. 35991116Smsmith */ 36091116Smsmith return (FALSE); 36191116Smsmith } 36291116Smsmith 363202771Sjkim if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength)) 36487031Smsmith { 36591116Smsmith /* 36691116Smsmith * The Value is larger than the maximum value that can fit into 36791116Smsmith * the register. 36891116Smsmith */ 369228110Sjkim ACPI_ERROR ((AE_INFO, 370228110Sjkim "Index value 0x%8.8X%8.8X overflows field width 0x%X", 371228110Sjkim ACPI_FORMAT_UINT64 (Value), 372228110Sjkim ObjDesc->CommonField.BitLength)); 373228110Sjkim 37487031Smsmith return (TRUE); 37587031Smsmith } 37687031Smsmith 37791116Smsmith /* The Value will fit into the field with no truncation */ 37891116Smsmith 37987031Smsmith return (FALSE); 38087031Smsmith} 38187031Smsmith 38287031Smsmith 38387031Smsmith/******************************************************************************* 38487031Smsmith * 38587031Smsmith * FUNCTION: AcpiExFieldDatumIo 38687031Smsmith * 387151937Sjkim * PARAMETERS: ObjDesc - Field to be read 38887031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 38987031Smsmith * parent field 390151937Sjkim * Value - Where to store value (must be 64 bits) 39187031Smsmith * ReadWrite - Read or Write flag 39287031Smsmith * 39387031Smsmith * RETURN: Status 39487031Smsmith * 395241973Sjkim * DESCRIPTION: Read or Write a single datum of a field. The FieldType is 39687031Smsmith * demultiplexed here to handle the different types of fields 39787031Smsmith * (BufferField, RegionField, IndexField, BankField) 39887031Smsmith * 39987031Smsmith ******************************************************************************/ 40087031Smsmith 401151937Sjkimstatic ACPI_STATUS 40287031SmsmithAcpiExFieldDatumIo ( 40387031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 40487031Smsmith UINT32 FieldDatumByteOffset, 405202771Sjkim UINT64 *Value, 40687031Smsmith UINT32 ReadWrite) 40787031Smsmith{ 40887031Smsmith ACPI_STATUS Status; 409202771Sjkim UINT64 LocalValue; 41087031Smsmith 41187031Smsmith 412167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset); 41387031Smsmith 41487031Smsmith 41587031Smsmith if (ReadWrite == ACPI_READ) 41687031Smsmith { 41787031Smsmith if (!Value) 41887031Smsmith { 41987031Smsmith LocalValue = 0; 420151937Sjkim 421151937Sjkim /* To support reads without saving return value */ 422151937Sjkim Value = &LocalValue; 42387031Smsmith } 42487031Smsmith 42587031Smsmith /* Clear the entire return buffer first, [Very Important!] */ 42687031Smsmith 42787031Smsmith *Value = 0; 42887031Smsmith } 42987031Smsmith 43087031Smsmith /* 43187031Smsmith * The four types of fields are: 43287031Smsmith * 433122944Snjl * BufferField - Read/write from/to a Buffer 434122944Snjl * RegionField - Read/write from/to a Operation Region. 435151937Sjkim * BankField - Write to a Bank Register, then read/write from/to an 436151937Sjkim * OperationRegion 437151937Sjkim * IndexField - Write to an Index Register, then read/write from/to a 438151937Sjkim * Data Register 43987031Smsmith */ 440193267Sjkim switch (ObjDesc->Common.Type) 44177424Smsmith { 44277424Smsmith case ACPI_TYPE_BUFFER_FIELD: 44377424Smsmith /* 44487031Smsmith * If the BufferField arguments have not been previously evaluated, 44587031Smsmith * evaluate them now and save the results. 44677424Smsmith */ 44787031Smsmith if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 44887031Smsmith { 44987031Smsmith Status = AcpiDsGetBufferFieldArguments (ObjDesc); 45087031Smsmith if (ACPI_FAILURE (Status)) 45187031Smsmith { 45287031Smsmith return_ACPI_STATUS (Status); 45387031Smsmith } 45487031Smsmith } 45587031Smsmith 45687031Smsmith if (ReadWrite == ACPI_READ) 45787031Smsmith { 45887031Smsmith /* 45987031Smsmith * Copy the data from the source buffer. 46087031Smsmith * Length is the field width in bytes. 46187031Smsmith */ 462151937Sjkim ACPI_MEMCPY (Value, 463151937Sjkim (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 464151937Sjkim ObjDesc->BufferField.BaseByteOffset + 465151937Sjkim FieldDatumByteOffset, 466151937Sjkim ObjDesc->CommonField.AccessByteWidth); 46787031Smsmith } 46887031Smsmith else 46987031Smsmith { 47087031Smsmith /* 47187031Smsmith * Copy the data to the target buffer. 47287031Smsmith * Length is the field width in bytes. 47387031Smsmith */ 474151937Sjkim ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 475167802Sjkim ObjDesc->BufferField.BaseByteOffset + 476167802Sjkim FieldDatumByteOffset, 477167802Sjkim Value, ObjDesc->CommonField.AccessByteWidth); 47887031Smsmith } 47987031Smsmith 48077424Smsmith Status = AE_OK; 48177424Smsmith break; 48267754Smsmith 48367754Smsmith 484107325Siwasaki case ACPI_TYPE_LOCAL_BANK_FIELD: 48567754Smsmith 486151937Sjkim /* 487151937Sjkim * Ensure that the BankValue is not beyond the capacity of 488151937Sjkim * the register 489151937Sjkim */ 49087031Smsmith if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 491202771Sjkim (UINT64) ObjDesc->BankField.Value)) 49287031Smsmith { 49387031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 49487031Smsmith } 49587031Smsmith 49677424Smsmith /* 49787031Smsmith * For BankFields, we must write the BankValue to the BankRegister 49887031Smsmith * (itself a RegionField) before we can access the data. 49977424Smsmith */ 50087031Smsmith Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 501167802Sjkim &ObjDesc->BankField.Value, 502167802Sjkim sizeof (ObjDesc->BankField.Value)); 50377424Smsmith if (ACPI_FAILURE (Status)) 50477424Smsmith { 50577424Smsmith return_ACPI_STATUS (Status); 50677424Smsmith } 50767754Smsmith 50877424Smsmith /* 50987031Smsmith * Now that the Bank has been selected, fall through to the 51087031Smsmith * RegionField case and write the datum to the Operation Region 51177424Smsmith */ 51277424Smsmith 51399679Siwasaki /*lint -fallthrough */ 51477424Smsmith 51577424Smsmith 516107325Siwasaki case ACPI_TYPE_LOCAL_REGION_FIELD: 51787031Smsmith /* 51887031Smsmith * For simple RegionFields, we just directly access the owning 51987031Smsmith * Operation Region. 52087031Smsmith */ 52187031Smsmith Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 522167802Sjkim ReadWrite); 52387031Smsmith break; 52487031Smsmith 52587031Smsmith 526107325Siwasaki case ACPI_TYPE_LOCAL_INDEX_FIELD: 52787031Smsmith 52887031Smsmith 529151937Sjkim /* 530151937Sjkim * Ensure that the IndexValue is not beyond the capacity of 531151937Sjkim * the register 532151937Sjkim */ 53387031Smsmith if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 534202771Sjkim (UINT64) ObjDesc->IndexField.Value)) 53577424Smsmith { 53687031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 53777424Smsmith } 53887031Smsmith 53987031Smsmith /* Write the index value to the IndexRegister (itself a RegionField) */ 54087031Smsmith 541122944Snjl FieldDatumByteOffset += ObjDesc->IndexField.Value; 542122944Snjl 543122944Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 544167802Sjkim "Write to Index Register: Value %8.8X\n", 545167802Sjkim FieldDatumByteOffset)); 546122944Snjl 54787031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 548167802Sjkim &FieldDatumByteOffset, 549167802Sjkim sizeof (FieldDatumByteOffset)); 55087031Smsmith if (ACPI_FAILURE (Status)) 55187031Smsmith { 55287031Smsmith return_ACPI_STATUS (Status); 55387031Smsmith } 55487031Smsmith 55587031Smsmith if (ReadWrite == ACPI_READ) 55687031Smsmith { 55787031Smsmith /* Read the datum from the DataRegister */ 55887031Smsmith 559193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 560193267Sjkim "Read from Data Register\n")); 561193267Sjkim 56287031Smsmith Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 563202771Sjkim Value, sizeof (UINT64)); 56487031Smsmith } 56587031Smsmith else 56687031Smsmith { 567122944Snjl /* Write the datum to the DataRegister */ 56887031Smsmith 569193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 570193267Sjkim "Write to Data Register: Value %8.8X%8.8X\n", 571193267Sjkim ACPI_FORMAT_UINT64 (*Value))); 572193267Sjkim 57387031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 574202771Sjkim Value, sizeof (UINT64)); 57587031Smsmith } 57677424Smsmith break; 57777424Smsmith 57877424Smsmith 57977424Smsmith default: 58077424Smsmith 581204773Sjkim ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u", 582193267Sjkim ObjDesc->Common.Type)); 58377424Smsmith Status = AE_AML_INTERNAL; 58477424Smsmith break; 58567754Smsmith } 58667754Smsmith 58787031Smsmith if (ACPI_SUCCESS (Status)) 58887031Smsmith { 58987031Smsmith if (ReadWrite == ACPI_READ) 59087031Smsmith { 591151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 592209746Sjkim "Value Read %8.8X%8.8X, Width %u\n", 593151937Sjkim ACPI_FORMAT_UINT64 (*Value), 594151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 59587031Smsmith } 59687031Smsmith else 59787031Smsmith { 598151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 599209746Sjkim "Value Written %8.8X%8.8X, Width %u\n", 600151937Sjkim ACPI_FORMAT_UINT64 (*Value), 601151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 60287031Smsmith } 60387031Smsmith } 60477424Smsmith 60587031Smsmith return_ACPI_STATUS (Status); 60687031Smsmith} 60777424Smsmith 60887031Smsmith 60987031Smsmith/******************************************************************************* 61087031Smsmith * 61187031Smsmith * FUNCTION: AcpiExWriteWithUpdateRule 61287031Smsmith * 613151937Sjkim * PARAMETERS: ObjDesc - Field to be written 614151937Sjkim * Mask - bitmask within field datum 615151937Sjkim * FieldValue - Value to write 616151937Sjkim * FieldDatumByteOffset - Offset of datum within field 61787031Smsmith * 61887031Smsmith * RETURN: Status 61987031Smsmith * 62087031Smsmith * DESCRIPTION: Apply the field update rule to a field write 62187031Smsmith * 62287031Smsmith ******************************************************************************/ 62387031Smsmith 62487031SmsmithACPI_STATUS 62587031SmsmithAcpiExWriteWithUpdateRule ( 62687031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 627202771Sjkim UINT64 Mask, 628202771Sjkim UINT64 FieldValue, 62987031Smsmith UINT32 FieldDatumByteOffset) 63087031Smsmith{ 63187031Smsmith ACPI_STATUS Status = AE_OK; 632202771Sjkim UINT64 MergedValue; 633202771Sjkim UINT64 CurrentValue; 63487031Smsmith 63587031Smsmith 636167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask); 63787031Smsmith 63887031Smsmith 63987031Smsmith /* Start with the new bits */ 64087031Smsmith 64187031Smsmith MergedValue = FieldValue; 64287031Smsmith 64387031Smsmith /* If the mask is all ones, we don't need to worry about the update rule */ 64487031Smsmith 645202771Sjkim if (Mask != ACPI_UINT64_MAX) 64687031Smsmith { 64787031Smsmith /* Decode the update rule */ 64887031Smsmith 64987031Smsmith switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 65087031Smsmith { 65187031Smsmith case AML_FIELD_UPDATE_PRESERVE: 65287031Smsmith /* 65387031Smsmith * Check if update rule needs to be applied (not if mask is all 65487031Smsmith * ones) The left shift drops the bits we want to ignore. 65587031Smsmith */ 65691116Smsmith if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 65791116Smsmith ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 65887031Smsmith { 65987031Smsmith /* 66087031Smsmith * Read the current contents of the byte/word/dword containing 66187031Smsmith * the field, and merge with the new field value. 66287031Smsmith */ 66387031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 664167802Sjkim &CurrentValue, ACPI_READ); 665123315Snjl if (ACPI_FAILURE (Status)) 666123315Snjl { 667123315Snjl return_ACPI_STATUS (Status); 668123315Snjl } 669123315Snjl 67087031Smsmith MergedValue |= (CurrentValue & ~Mask); 67187031Smsmith } 67287031Smsmith break; 67387031Smsmith 67487031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ONES: 67587031Smsmith 67687031Smsmith /* Set positions outside the field to all ones */ 67787031Smsmith 67887031Smsmith MergedValue |= ~Mask; 67987031Smsmith break; 68087031Smsmith 68187031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 68287031Smsmith 68387031Smsmith /* Set positions outside the field to all zeros */ 68487031Smsmith 68587031Smsmith MergedValue &= Mask; 68687031Smsmith break; 68787031Smsmith 68887031Smsmith default: 689123315Snjl 690167802Sjkim ACPI_ERROR ((AE_INFO, 691204773Sjkim "Unknown UpdateRule value: 0x%X", 69287031Smsmith (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 69387031Smsmith return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 69487031Smsmith } 69587031Smsmith } 69687031Smsmith 697123315Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 698123315Snjl "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 699123315Snjl ACPI_FORMAT_UINT64 (Mask), 700123315Snjl FieldDatumByteOffset, 701123315Snjl ObjDesc->CommonField.AccessByteWidth, 702123315Snjl ACPI_FORMAT_UINT64 (FieldValue), 703123315Snjl ACPI_FORMAT_UINT64 (MergedValue))); 704123315Snjl 70587031Smsmith /* Write the merged value */ 70687031Smsmith 70787031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 708167802Sjkim &MergedValue, ACPI_WRITE); 70987031Smsmith 71077424Smsmith return_ACPI_STATUS (Status); 71177424Smsmith} 71277424Smsmith 71377424Smsmith 71477424Smsmith/******************************************************************************* 71577424Smsmith * 71677424Smsmith * FUNCTION: AcpiExExtractFromField 71767754Smsmith * 718131440Smarks * PARAMETERS: ObjDesc - Field to be read 719131440Smarks * Buffer - Where to store the field data 720131440Smarks * BufferLength - Length of Buffer 72167754Smsmith * 72267754Smsmith * RETURN: Status 72367754Smsmith * 724131440Smarks * DESCRIPTION: Retrieve the current value of the given field 72567754Smsmith * 72667754Smsmith ******************************************************************************/ 72767754Smsmith 72867754SmsmithACPI_STATUS 72977424SmsmithAcpiExExtractFromField ( 73067754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 73167754Smsmith void *Buffer, 73277424Smsmith UINT32 BufferLength) 73367754Smsmith{ 73467754Smsmith ACPI_STATUS Status; 735202771Sjkim UINT64 RawDatum; 736202771Sjkim UINT64 MergedDatum; 737151937Sjkim UINT32 FieldOffset = 0; 738151937Sjkim UINT32 BufferOffset = 0; 739151937Sjkim UINT32 BufferTailBits; 74077424Smsmith UINT32 DatumCount; 741151937Sjkim UINT32 FieldDatumCount; 742210976Sjkim UINT32 AccessBitWidth; 743123315Snjl UINT32 i; 74467754Smsmith 74567754Smsmith 746167802Sjkim ACPI_FUNCTION_TRACE (ExExtractFromField); 74767754Smsmith 74877424Smsmith 749151937Sjkim /* Validate target buffer and clear it */ 75077424Smsmith 751167802Sjkim if (BufferLength < 752210976Sjkim ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) 753151937Sjkim { 754167802Sjkim ACPI_ERROR ((AE_INFO, 755204773Sjkim "Field size %u (bits) is too large for buffer (%u)", 756151937Sjkim ObjDesc->CommonField.BitLength, BufferLength)); 757151937Sjkim 758151937Sjkim return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 759151937Sjkim } 760210976Sjkim 761151937Sjkim ACPI_MEMSET (Buffer, 0, BufferLength); 762210976Sjkim AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 763151937Sjkim 764210976Sjkim /* Handle the simple case here */ 765210976Sjkim 766210976Sjkim if ((ObjDesc->CommonField.StartFieldBitOffset == 0) && 767210976Sjkim (ObjDesc->CommonField.BitLength == AccessBitWidth)) 768210976Sjkim { 769210976Sjkim Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ); 770210976Sjkim return_ACPI_STATUS (Status); 771210976Sjkim } 772210976Sjkim 773210976Sjkim/* TBD: Move to common setup code */ 774210976Sjkim 775210976Sjkim /* Field algorithm is limited to sizeof(UINT64), truncate if needed */ 776210976Sjkim 777210976Sjkim if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 778210976Sjkim { 779210976Sjkim ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 780210976Sjkim AccessBitWidth = sizeof (UINT64) * 8; 781210976Sjkim } 782210976Sjkim 783151937Sjkim /* Compute the number of datums (access width data items) */ 784151937Sjkim 785151937Sjkim DatumCount = ACPI_ROUND_UP_TO ( 786210976Sjkim ObjDesc->CommonField.BitLength, AccessBitWidth); 787210976Sjkim 788151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO ( 789210976Sjkim ObjDesc->CommonField.BitLength + 790210976Sjkim ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); 791151937Sjkim 792151937Sjkim /* Priming read from the field */ 793151937Sjkim 794151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); 795131440Smarks if (ACPI_FAILURE (Status)) 796123315Snjl { 797131440Smarks return_ACPI_STATUS (Status); 798123315Snjl } 799151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 800123315Snjl 801151937Sjkim /* Read the rest of the field */ 80267754Smsmith 803151937Sjkim for (i = 1; i < FieldDatumCount; i++) 804151937Sjkim { 805151937Sjkim /* Get next input datum from the field */ 80667754Smsmith 807151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 808151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, 809167802Sjkim &RawDatum, ACPI_READ); 810123315Snjl if (ACPI_FAILURE (Status)) 811123315Snjl { 812123315Snjl return_ACPI_STATUS (Status); 813123315Snjl } 81467754Smsmith 815167802Sjkim /* 816167802Sjkim * Merge with previous datum if necessary. 817167802Sjkim * 818167802Sjkim * Note: Before the shift, check if the shift value will be larger than 819167802Sjkim * the integer size. If so, there is no need to perform the operation. 820167802Sjkim * This avoids the differences in behavior between different compilers 821167802Sjkim * concerning shift values larger than the target data width. 822167802Sjkim */ 823210976Sjkim if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset < 824210976Sjkim ACPI_INTEGER_BIT_SIZE) 825167802Sjkim { 826167802Sjkim MergedDatum |= RawDatum << 827210976Sjkim (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 828167802Sjkim } 82967754Smsmith 830151937Sjkim if (i == DatumCount) 83167754Smsmith { 832151937Sjkim break; 83377424Smsmith } 83467754Smsmith 835151937Sjkim /* Write merged datum to target buffer */ 83671867Smsmith 837151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 838151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 839167802Sjkim BufferLength - BufferOffset)); 84067754Smsmith 841151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 842151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 843151937Sjkim } 844123315Snjl 845151937Sjkim /* Mask off any extra bits in the last datum */ 846123315Snjl 847210976Sjkim BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth; 848151937Sjkim if (BufferTailBits) 849151937Sjkim { 850151937Sjkim MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 851123315Snjl } 852123315Snjl 853151937Sjkim /* Write the last datum to the buffer */ 854123315Snjl 855151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 856151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 857167802Sjkim BufferLength - BufferOffset)); 858123315Snjl 85977424Smsmith return_ACPI_STATUS (AE_OK); 86067754Smsmith} 86167754Smsmith 86267754Smsmith 86367754Smsmith/******************************************************************************* 86467754Smsmith * 86577424Smsmith * FUNCTION: AcpiExInsertIntoField 86667754Smsmith * 867131440Smarks * PARAMETERS: ObjDesc - Field to be written 868131440Smarks * Buffer - Data to be written 869131440Smarks * BufferLength - Length of Buffer 87067754Smsmith * 87167754Smsmith * RETURN: Status 87267754Smsmith * 873131440Smarks * DESCRIPTION: Store the Buffer contents into the given field 87467754Smsmith * 87577424Smsmith ******************************************************************************/ 87667754Smsmith 87767754SmsmithACPI_STATUS 87877424SmsmithAcpiExInsertIntoField ( 87967754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 88067754Smsmith void *Buffer, 88177424Smsmith UINT32 BufferLength) 88267754Smsmith{ 883210976Sjkim void *NewBuffer; 88467754Smsmith ACPI_STATUS Status; 885202771Sjkim UINT64 Mask; 886202771Sjkim UINT64 WidthMask; 887202771Sjkim UINT64 MergedDatum; 888202771Sjkim UINT64 RawDatum = 0; 889151937Sjkim UINT32 FieldOffset = 0; 890151937Sjkim UINT32 BufferOffset = 0; 891151937Sjkim UINT32 BufferTailBits; 89277424Smsmith UINT32 DatumCount; 893151937Sjkim UINT32 FieldDatumCount; 894210976Sjkim UINT32 AccessBitWidth; 895210976Sjkim UINT32 RequiredLength; 896151937Sjkim UINT32 i; 89767754Smsmith 89867754Smsmith 899167802Sjkim ACPI_FUNCTION_TRACE (ExInsertIntoField); 90067754Smsmith 90167754Smsmith 902151937Sjkim /* Validate input buffer */ 903131440Smarks 904193267Sjkim NewBuffer = NULL; 905193267Sjkim RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 906193267Sjkim ObjDesc->CommonField.BitLength); 907193267Sjkim /* 908193267Sjkim * We must have a buffer that is at least as long as the field 909241973Sjkim * we are writing to. This is because individual fields are 910193267Sjkim * indivisible and partial writes are not supported -- as per 911193267Sjkim * the ACPI specification. 912193267Sjkim */ 913193267Sjkim if (BufferLength < RequiredLength) 91477424Smsmith { 915193267Sjkim /* We need to create a new buffer */ 916151937Sjkim 917193267Sjkim NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); 918193267Sjkim if (!NewBuffer) 919193267Sjkim { 920193267Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 921193267Sjkim } 922193267Sjkim 923193267Sjkim /* 924193267Sjkim * Copy the original data to the new buffer, starting 925241973Sjkim * at Byte zero. All unused (upper) bytes of the 926193267Sjkim * buffer will be 0. 927193267Sjkim */ 928193267Sjkim ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength); 929193267Sjkim Buffer = NewBuffer; 930193267Sjkim BufferLength = RequiredLength; 93177424Smsmith } 93267754Smsmith 933210976Sjkim/* TBD: Move to common setup code */ 934210976Sjkim 935210976Sjkim /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ 936210976Sjkim if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 937210976Sjkim { 938210976Sjkim ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 939210976Sjkim } 940210976Sjkim 941210976Sjkim AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 942210976Sjkim 943167802Sjkim /* 944167802Sjkim * Create the bitmasks used for bit insertion. 945167802Sjkim * Note: This if/else is used to bypass compiler differences with the 946167802Sjkim * shift operator 947167802Sjkim */ 948210976Sjkim if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE) 949167802Sjkim { 950202771Sjkim WidthMask = ACPI_UINT64_MAX; 951167802Sjkim } 952167802Sjkim else 953167802Sjkim { 954210976Sjkim WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth); 955167802Sjkim } 956167802Sjkim 957167802Sjkim Mask = WidthMask & 958210976Sjkim ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 959167802Sjkim 960151937Sjkim /* Compute the number of datums (access width data items) */ 96167754Smsmith 962151937Sjkim DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, 963210976Sjkim AccessBitWidth); 964167802Sjkim 965151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + 966210976Sjkim ObjDesc->CommonField.StartFieldBitOffset, 967210976Sjkim AccessBitWidth); 96867754Smsmith 969151937Sjkim /* Get initial Datum from the input buffer */ 97067754Smsmith 971151937Sjkim ACPI_MEMCPY (&RawDatum, Buffer, 972151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 973167802Sjkim BufferLength - BufferOffset)); 97467754Smsmith 975151937Sjkim MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 97667754Smsmith 977151937Sjkim /* Write the entire field */ 97867754Smsmith 979151937Sjkim for (i = 1; i < FieldDatumCount; i++) 98067754Smsmith { 981151937Sjkim /* Write merged datum to the target field */ 98267754Smsmith 983151937Sjkim MergedDatum &= Mask; 984151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, 985151937Sjkim MergedDatum, FieldOffset); 986151937Sjkim if (ACPI_FAILURE (Status)) 987151937Sjkim { 988193267Sjkim goto Exit; 989151937Sjkim } 990123315Snjl 991151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 99267754Smsmith 993167802Sjkim /* 994167802Sjkim * Start new output datum by merging with previous input datum 995167802Sjkim * if necessary. 996167802Sjkim * 997167802Sjkim * Note: Before the shift, check if the shift value will be larger than 998167802Sjkim * the integer size. If so, there is no need to perform the operation. 999167802Sjkim * This avoids the differences in behavior between different compilers 1000167802Sjkim * concerning shift values larger than the target data width. 1001167802Sjkim */ 1002210976Sjkim if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < 1003210976Sjkim ACPI_INTEGER_BIT_SIZE) 1004167802Sjkim { 1005167802Sjkim MergedDatum = RawDatum >> 1006210976Sjkim (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 1007167802Sjkim } 1008167802Sjkim else 1009167802Sjkim { 1010167802Sjkim MergedDatum = 0; 1011167802Sjkim } 1012167802Sjkim 1013167802Sjkim Mask = WidthMask; 1014167802Sjkim 1015151937Sjkim if (i == DatumCount) 101667754Smsmith { 1017151937Sjkim break; 101867754Smsmith } 101977424Smsmith 1020151937Sjkim /* Get the next input datum from the buffer */ 102167754Smsmith 1022151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 1023151937Sjkim ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, 1024151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 1025210976Sjkim BufferLength - BufferOffset)); 1026210976Sjkim 1027151937Sjkim MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 1028151937Sjkim } 102967754Smsmith 1030151937Sjkim /* Mask off any extra bits in the last datum */ 103167754Smsmith 1032151937Sjkim BufferTailBits = (ObjDesc->CommonField.BitLength + 1033210976Sjkim ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth; 1034151937Sjkim if (BufferTailBits) 1035151937Sjkim { 1036151937Sjkim Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 1037151937Sjkim } 1038123315Snjl 1039151937Sjkim /* Write the last datum to the field */ 104067754Smsmith 1041151937Sjkim MergedDatum &= Mask; 1042151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, 1043151937Sjkim Mask, MergedDatum, FieldOffset); 104467754Smsmith 1045193267SjkimExit: 1046193267Sjkim /* Free temporary buffer if we used one */ 1047193267Sjkim 1048193267Sjkim if (NewBuffer) 1049193267Sjkim { 1050193267Sjkim ACPI_FREE (NewBuffer); 1051193267Sjkim } 105267754Smsmith return_ACPI_STATUS (Status); 105367754Smsmith} 1054