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 483107325Siwasaki case ACPI_TYPE_LOCAL_BANK_FIELD: 484151937Sjkim /* 485151937Sjkim * Ensure that the BankValue is not beyond the capacity of 486151937Sjkim * the register 487151937Sjkim */ 48887031Smsmith if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 489202771Sjkim (UINT64) ObjDesc->BankField.Value)) 49087031Smsmith { 49187031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 49287031Smsmith } 49387031Smsmith 49477424Smsmith /* 49587031Smsmith * For BankFields, we must write the BankValue to the BankRegister 49687031Smsmith * (itself a RegionField) before we can access the data. 49777424Smsmith */ 49887031Smsmith Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 499167802Sjkim &ObjDesc->BankField.Value, 500167802Sjkim sizeof (ObjDesc->BankField.Value)); 50177424Smsmith if (ACPI_FAILURE (Status)) 50277424Smsmith { 50377424Smsmith return_ACPI_STATUS (Status); 50477424Smsmith } 50567754Smsmith 50677424Smsmith /* 50787031Smsmith * Now that the Bank has been selected, fall through to the 50887031Smsmith * RegionField case and write the datum to the Operation Region 50977424Smsmith */ 51077424Smsmith 51199679Siwasaki /*lint -fallthrough */ 51277424Smsmith 513107325Siwasaki case ACPI_TYPE_LOCAL_REGION_FIELD: 51487031Smsmith /* 51587031Smsmith * For simple RegionFields, we just directly access the owning 51687031Smsmith * Operation Region. 51787031Smsmith */ 51887031Smsmith Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 519167802Sjkim ReadWrite); 52087031Smsmith break; 52187031Smsmith 522107325Siwasaki case ACPI_TYPE_LOCAL_INDEX_FIELD: 523151937Sjkim /* 524151937Sjkim * Ensure that the IndexValue is not beyond the capacity of 525151937Sjkim * the register 526151937Sjkim */ 52787031Smsmith if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 528202771Sjkim (UINT64) ObjDesc->IndexField.Value)) 52977424Smsmith { 53087031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 53177424Smsmith } 53287031Smsmith 53387031Smsmith /* Write the index value to the IndexRegister (itself a RegionField) */ 53487031Smsmith 535122944Snjl FieldDatumByteOffset += ObjDesc->IndexField.Value; 536122944Snjl 537122944Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 538167802Sjkim "Write to Index Register: Value %8.8X\n", 539167802Sjkim FieldDatumByteOffset)); 540122944Snjl 54187031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 542167802Sjkim &FieldDatumByteOffset, 543167802Sjkim sizeof (FieldDatumByteOffset)); 54487031Smsmith if (ACPI_FAILURE (Status)) 54587031Smsmith { 54687031Smsmith return_ACPI_STATUS (Status); 54787031Smsmith } 54887031Smsmith 54987031Smsmith if (ReadWrite == ACPI_READ) 55087031Smsmith { 55187031Smsmith /* Read the datum from the DataRegister */ 55287031Smsmith 553193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 554193267Sjkim "Read from Data Register\n")); 555193267Sjkim 55687031Smsmith Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 557202771Sjkim Value, sizeof (UINT64)); 55887031Smsmith } 55987031Smsmith else 56087031Smsmith { 561122944Snjl /* Write the datum to the DataRegister */ 56287031Smsmith 563193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 564193267Sjkim "Write to Data Register: Value %8.8X%8.8X\n", 565193267Sjkim ACPI_FORMAT_UINT64 (*Value))); 566193267Sjkim 56787031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 568202771Sjkim Value, sizeof (UINT64)); 56987031Smsmith } 57077424Smsmith break; 57177424Smsmith 57277424Smsmith default: 57377424Smsmith 574204773Sjkim ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u", 575193267Sjkim ObjDesc->Common.Type)); 57677424Smsmith Status = AE_AML_INTERNAL; 57777424Smsmith break; 57867754Smsmith } 57967754Smsmith 58087031Smsmith if (ACPI_SUCCESS (Status)) 58187031Smsmith { 58287031Smsmith if (ReadWrite == ACPI_READ) 58387031Smsmith { 584151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 585209746Sjkim "Value Read %8.8X%8.8X, Width %u\n", 586151937Sjkim ACPI_FORMAT_UINT64 (*Value), 587151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 58887031Smsmith } 58987031Smsmith else 59087031Smsmith { 591151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 592209746Sjkim "Value Written %8.8X%8.8X, Width %u\n", 593151937Sjkim ACPI_FORMAT_UINT64 (*Value), 594151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 59587031Smsmith } 59687031Smsmith } 59777424Smsmith 59887031Smsmith return_ACPI_STATUS (Status); 59987031Smsmith} 60077424Smsmith 60187031Smsmith 60287031Smsmith/******************************************************************************* 60387031Smsmith * 60487031Smsmith * FUNCTION: AcpiExWriteWithUpdateRule 60587031Smsmith * 606151937Sjkim * PARAMETERS: ObjDesc - Field to be written 607151937Sjkim * Mask - bitmask within field datum 608151937Sjkim * FieldValue - Value to write 609151937Sjkim * FieldDatumByteOffset - Offset of datum within field 61087031Smsmith * 61187031Smsmith * RETURN: Status 61287031Smsmith * 61387031Smsmith * DESCRIPTION: Apply the field update rule to a field write 61487031Smsmith * 61587031Smsmith ******************************************************************************/ 61687031Smsmith 61787031SmsmithACPI_STATUS 61887031SmsmithAcpiExWriteWithUpdateRule ( 61987031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 620202771Sjkim UINT64 Mask, 621202771Sjkim UINT64 FieldValue, 62287031Smsmith UINT32 FieldDatumByteOffset) 62387031Smsmith{ 62487031Smsmith ACPI_STATUS Status = AE_OK; 625202771Sjkim UINT64 MergedValue; 626202771Sjkim UINT64 CurrentValue; 62787031Smsmith 62887031Smsmith 629167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask); 63087031Smsmith 63187031Smsmith 63287031Smsmith /* Start with the new bits */ 63387031Smsmith 63487031Smsmith MergedValue = FieldValue; 63587031Smsmith 63687031Smsmith /* If the mask is all ones, we don't need to worry about the update rule */ 63787031Smsmith 638202771Sjkim if (Mask != ACPI_UINT64_MAX) 63987031Smsmith { 64087031Smsmith /* Decode the update rule */ 64187031Smsmith 64287031Smsmith switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 64387031Smsmith { 64487031Smsmith case AML_FIELD_UPDATE_PRESERVE: 64587031Smsmith /* 64687031Smsmith * Check if update rule needs to be applied (not if mask is all 64787031Smsmith * ones) The left shift drops the bits we want to ignore. 64887031Smsmith */ 64991116Smsmith if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 65091116Smsmith ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 65187031Smsmith { 65287031Smsmith /* 65387031Smsmith * Read the current contents of the byte/word/dword containing 65487031Smsmith * the field, and merge with the new field value. 65587031Smsmith */ 65687031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 657167802Sjkim &CurrentValue, ACPI_READ); 658123315Snjl if (ACPI_FAILURE (Status)) 659123315Snjl { 660123315Snjl return_ACPI_STATUS (Status); 661123315Snjl } 662123315Snjl 66387031Smsmith MergedValue |= (CurrentValue & ~Mask); 66487031Smsmith } 66587031Smsmith break; 66687031Smsmith 66787031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ONES: 66887031Smsmith 66987031Smsmith /* Set positions outside the field to all ones */ 67087031Smsmith 67187031Smsmith MergedValue |= ~Mask; 67287031Smsmith break; 67387031Smsmith 67487031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 67587031Smsmith 67687031Smsmith /* Set positions outside the field to all zeros */ 67787031Smsmith 67887031Smsmith MergedValue &= Mask; 67987031Smsmith break; 68087031Smsmith 68187031Smsmith default: 682123315Snjl 683167802Sjkim ACPI_ERROR ((AE_INFO, 684204773Sjkim "Unknown UpdateRule value: 0x%X", 68587031Smsmith (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 68687031Smsmith return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 68787031Smsmith } 68887031Smsmith } 68987031Smsmith 690123315Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 691123315Snjl "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 692123315Snjl ACPI_FORMAT_UINT64 (Mask), 693123315Snjl FieldDatumByteOffset, 694123315Snjl ObjDesc->CommonField.AccessByteWidth, 695123315Snjl ACPI_FORMAT_UINT64 (FieldValue), 696123315Snjl ACPI_FORMAT_UINT64 (MergedValue))); 697123315Snjl 69887031Smsmith /* Write the merged value */ 69987031Smsmith 70087031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 701167802Sjkim &MergedValue, ACPI_WRITE); 70287031Smsmith 70377424Smsmith return_ACPI_STATUS (Status); 70477424Smsmith} 70577424Smsmith 70677424Smsmith 70777424Smsmith/******************************************************************************* 70877424Smsmith * 70977424Smsmith * FUNCTION: AcpiExExtractFromField 71067754Smsmith * 711131440Smarks * PARAMETERS: ObjDesc - Field to be read 712131440Smarks * Buffer - Where to store the field data 713131440Smarks * BufferLength - Length of Buffer 71467754Smsmith * 71567754Smsmith * RETURN: Status 71667754Smsmith * 717131440Smarks * DESCRIPTION: Retrieve the current value of the given field 71867754Smsmith * 71967754Smsmith ******************************************************************************/ 72067754Smsmith 72167754SmsmithACPI_STATUS 72277424SmsmithAcpiExExtractFromField ( 72367754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 72467754Smsmith void *Buffer, 72577424Smsmith UINT32 BufferLength) 72667754Smsmith{ 72767754Smsmith ACPI_STATUS Status; 728202771Sjkim UINT64 RawDatum; 729202771Sjkim UINT64 MergedDatum; 730151937Sjkim UINT32 FieldOffset = 0; 731151937Sjkim UINT32 BufferOffset = 0; 732151937Sjkim UINT32 BufferTailBits; 73377424Smsmith UINT32 DatumCount; 734151937Sjkim UINT32 FieldDatumCount; 735210976Sjkim UINT32 AccessBitWidth; 736123315Snjl UINT32 i; 73767754Smsmith 73867754Smsmith 739167802Sjkim ACPI_FUNCTION_TRACE (ExExtractFromField); 74067754Smsmith 74177424Smsmith 742151937Sjkim /* Validate target buffer and clear it */ 74377424Smsmith 744167802Sjkim if (BufferLength < 745210976Sjkim ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) 746151937Sjkim { 747167802Sjkim ACPI_ERROR ((AE_INFO, 748204773Sjkim "Field size %u (bits) is too large for buffer (%u)", 749151937Sjkim ObjDesc->CommonField.BitLength, BufferLength)); 750151937Sjkim 751151937Sjkim return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 752151937Sjkim } 753210976Sjkim 754151937Sjkim ACPI_MEMSET (Buffer, 0, BufferLength); 755210976Sjkim AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 756151937Sjkim 757210976Sjkim /* Handle the simple case here */ 758210976Sjkim 759210976Sjkim if ((ObjDesc->CommonField.StartFieldBitOffset == 0) && 760210976Sjkim (ObjDesc->CommonField.BitLength == AccessBitWidth)) 761210976Sjkim { 762249663Sjkim if (BufferLength >= sizeof (UINT64)) 763249663Sjkim { 764249663Sjkim Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ); 765249663Sjkim } 766249663Sjkim else 767249663Sjkim { 768249663Sjkim /* Use RawDatum (UINT64) to handle buffers < 64 bits */ 769249663Sjkim 770249663Sjkim Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ); 771249663Sjkim ACPI_MEMCPY (Buffer, &RawDatum, BufferLength); 772249663Sjkim } 773249663Sjkim 774210976Sjkim return_ACPI_STATUS (Status); 775210976Sjkim } 776210976Sjkim 777210976Sjkim/* TBD: Move to common setup code */ 778210976Sjkim 779210976Sjkim /* Field algorithm is limited to sizeof(UINT64), truncate if needed */ 780210976Sjkim 781210976Sjkim if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 782210976Sjkim { 783210976Sjkim ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 784210976Sjkim AccessBitWidth = sizeof (UINT64) * 8; 785210976Sjkim } 786210976Sjkim 787151937Sjkim /* Compute the number of datums (access width data items) */ 788151937Sjkim 789151937Sjkim DatumCount = ACPI_ROUND_UP_TO ( 790210976Sjkim ObjDesc->CommonField.BitLength, AccessBitWidth); 791210976Sjkim 792151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO ( 793210976Sjkim ObjDesc->CommonField.BitLength + 794210976Sjkim ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); 795151937Sjkim 796151937Sjkim /* Priming read from the field */ 797151937Sjkim 798151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); 799131440Smarks if (ACPI_FAILURE (Status)) 800123315Snjl { 801131440Smarks return_ACPI_STATUS (Status); 802123315Snjl } 803151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 804123315Snjl 805151937Sjkim /* Read the rest of the field */ 80667754Smsmith 807151937Sjkim for (i = 1; i < FieldDatumCount; i++) 808151937Sjkim { 809151937Sjkim /* Get next input datum from the field */ 81067754Smsmith 811151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 812151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, 813167802Sjkim &RawDatum, ACPI_READ); 814123315Snjl if (ACPI_FAILURE (Status)) 815123315Snjl { 816123315Snjl return_ACPI_STATUS (Status); 817123315Snjl } 81867754Smsmith 819167802Sjkim /* 820167802Sjkim * Merge with previous datum if necessary. 821167802Sjkim * 822167802Sjkim * Note: Before the shift, check if the shift value will be larger than 823167802Sjkim * the integer size. If so, there is no need to perform the operation. 824167802Sjkim * This avoids the differences in behavior between different compilers 825167802Sjkim * concerning shift values larger than the target data width. 826167802Sjkim */ 827210976Sjkim if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset < 828210976Sjkim ACPI_INTEGER_BIT_SIZE) 829167802Sjkim { 830167802Sjkim MergedDatum |= RawDatum << 831210976Sjkim (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 832167802Sjkim } 83367754Smsmith 834151937Sjkim if (i == DatumCount) 83567754Smsmith { 836151937Sjkim break; 83777424Smsmith } 83867754Smsmith 839151937Sjkim /* Write merged datum to target buffer */ 84071867Smsmith 841151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 842151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 843167802Sjkim BufferLength - BufferOffset)); 84467754Smsmith 845151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 846151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 847151937Sjkim } 848123315Snjl 849151937Sjkim /* Mask off any extra bits in the last datum */ 850123315Snjl 851210976Sjkim BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth; 852151937Sjkim if (BufferTailBits) 853151937Sjkim { 854151937Sjkim MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 855123315Snjl } 856123315Snjl 857151937Sjkim /* Write the last datum to the buffer */ 858123315Snjl 859151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 860151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 861167802Sjkim BufferLength - BufferOffset)); 862123315Snjl 86377424Smsmith return_ACPI_STATUS (AE_OK); 86467754Smsmith} 86567754Smsmith 86667754Smsmith 86767754Smsmith/******************************************************************************* 86867754Smsmith * 86977424Smsmith * FUNCTION: AcpiExInsertIntoField 87067754Smsmith * 871131440Smarks * PARAMETERS: ObjDesc - Field to be written 872131440Smarks * Buffer - Data to be written 873131440Smarks * BufferLength - Length of Buffer 87467754Smsmith * 87567754Smsmith * RETURN: Status 87667754Smsmith * 877131440Smarks * DESCRIPTION: Store the Buffer contents into the given field 87867754Smsmith * 87977424Smsmith ******************************************************************************/ 88067754Smsmith 88167754SmsmithACPI_STATUS 88277424SmsmithAcpiExInsertIntoField ( 88367754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 88467754Smsmith void *Buffer, 88577424Smsmith UINT32 BufferLength) 88667754Smsmith{ 887210976Sjkim void *NewBuffer; 88867754Smsmith ACPI_STATUS Status; 889202771Sjkim UINT64 Mask; 890202771Sjkim UINT64 WidthMask; 891202771Sjkim UINT64 MergedDatum; 892202771Sjkim UINT64 RawDatum = 0; 893151937Sjkim UINT32 FieldOffset = 0; 894151937Sjkim UINT32 BufferOffset = 0; 895151937Sjkim UINT32 BufferTailBits; 89677424Smsmith UINT32 DatumCount; 897151937Sjkim UINT32 FieldDatumCount; 898210976Sjkim UINT32 AccessBitWidth; 899210976Sjkim UINT32 RequiredLength; 900151937Sjkim UINT32 i; 90167754Smsmith 90267754Smsmith 903167802Sjkim ACPI_FUNCTION_TRACE (ExInsertIntoField); 90467754Smsmith 90567754Smsmith 906151937Sjkim /* Validate input buffer */ 907131440Smarks 908193267Sjkim NewBuffer = NULL; 909193267Sjkim RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 910193267Sjkim ObjDesc->CommonField.BitLength); 911193267Sjkim /* 912193267Sjkim * We must have a buffer that is at least as long as the field 913241973Sjkim * we are writing to. This is because individual fields are 914193267Sjkim * indivisible and partial writes are not supported -- as per 915193267Sjkim * the ACPI specification. 916193267Sjkim */ 917193267Sjkim if (BufferLength < RequiredLength) 91877424Smsmith { 919193267Sjkim /* We need to create a new buffer */ 920151937Sjkim 921193267Sjkim NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); 922193267Sjkim if (!NewBuffer) 923193267Sjkim { 924193267Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 925193267Sjkim } 926193267Sjkim 927193267Sjkim /* 928193267Sjkim * Copy the original data to the new buffer, starting 929241973Sjkim * at Byte zero. All unused (upper) bytes of the 930193267Sjkim * buffer will be 0. 931193267Sjkim */ 932193267Sjkim ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength); 933193267Sjkim Buffer = NewBuffer; 934193267Sjkim BufferLength = RequiredLength; 93577424Smsmith } 93667754Smsmith 937210976Sjkim/* TBD: Move to common setup code */ 938210976Sjkim 939210976Sjkim /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ 940210976Sjkim if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 941210976Sjkim { 942210976Sjkim ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 943210976Sjkim } 944210976Sjkim 945210976Sjkim AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 946210976Sjkim 947167802Sjkim /* 948167802Sjkim * Create the bitmasks used for bit insertion. 949167802Sjkim * Note: This if/else is used to bypass compiler differences with the 950167802Sjkim * shift operator 951167802Sjkim */ 952210976Sjkim if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE) 953167802Sjkim { 954202771Sjkim WidthMask = ACPI_UINT64_MAX; 955167802Sjkim } 956167802Sjkim else 957167802Sjkim { 958210976Sjkim WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth); 959167802Sjkim } 960167802Sjkim 961167802Sjkim Mask = WidthMask & 962210976Sjkim ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 963167802Sjkim 964151937Sjkim /* Compute the number of datums (access width data items) */ 96567754Smsmith 966151937Sjkim DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, 967210976Sjkim AccessBitWidth); 968167802Sjkim 969151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + 970210976Sjkim ObjDesc->CommonField.StartFieldBitOffset, 971210976Sjkim AccessBitWidth); 97267754Smsmith 973151937Sjkim /* Get initial Datum from the input buffer */ 97467754Smsmith 975151937Sjkim ACPI_MEMCPY (&RawDatum, Buffer, 976151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 977167802Sjkim BufferLength - BufferOffset)); 97867754Smsmith 979151937Sjkim MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 98067754Smsmith 981151937Sjkim /* Write the entire field */ 98267754Smsmith 983151937Sjkim for (i = 1; i < FieldDatumCount; i++) 98467754Smsmith { 985151937Sjkim /* Write merged datum to the target field */ 98667754Smsmith 987151937Sjkim MergedDatum &= Mask; 988151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, 989151937Sjkim MergedDatum, FieldOffset); 990151937Sjkim if (ACPI_FAILURE (Status)) 991151937Sjkim { 992193267Sjkim goto Exit; 993151937Sjkim } 994123315Snjl 995151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 99667754Smsmith 997167802Sjkim /* 998167802Sjkim * Start new output datum by merging with previous input datum 999167802Sjkim * if necessary. 1000167802Sjkim * 1001167802Sjkim * Note: Before the shift, check if the shift value will be larger than 1002167802Sjkim * the integer size. If so, there is no need to perform the operation. 1003167802Sjkim * This avoids the differences in behavior between different compilers 1004167802Sjkim * concerning shift values larger than the target data width. 1005167802Sjkim */ 1006210976Sjkim if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < 1007210976Sjkim ACPI_INTEGER_BIT_SIZE) 1008167802Sjkim { 1009167802Sjkim MergedDatum = RawDatum >> 1010210976Sjkim (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 1011167802Sjkim } 1012167802Sjkim else 1013167802Sjkim { 1014167802Sjkim MergedDatum = 0; 1015167802Sjkim } 1016167802Sjkim 1017167802Sjkim Mask = WidthMask; 1018167802Sjkim 1019151937Sjkim if (i == DatumCount) 102067754Smsmith { 1021151937Sjkim break; 102267754Smsmith } 102377424Smsmith 1024151937Sjkim /* Get the next input datum from the buffer */ 102567754Smsmith 1026151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 1027151937Sjkim ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, 1028151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 1029210976Sjkim BufferLength - BufferOffset)); 1030210976Sjkim 1031151937Sjkim MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 1032151937Sjkim } 103367754Smsmith 1034151937Sjkim /* Mask off any extra bits in the last datum */ 103567754Smsmith 1036151937Sjkim BufferTailBits = (ObjDesc->CommonField.BitLength + 1037210976Sjkim ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth; 1038151937Sjkim if (BufferTailBits) 1039151937Sjkim { 1040151937Sjkim Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 1041151937Sjkim } 1042123315Snjl 1043151937Sjkim /* Write the last datum to the field */ 104467754Smsmith 1045151937Sjkim MergedDatum &= Mask; 1046151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, 1047151937Sjkim Mask, MergedDatum, FieldOffset); 104867754Smsmith 1049193267SjkimExit: 1050193267Sjkim /* Free temporary buffer if we used one */ 1051193267Sjkim 1052193267Sjkim if (NewBuffer) 1053193267Sjkim { 1054193267Sjkim ACPI_FREE (NewBuffer); 1055193267Sjkim } 105667754Smsmith return_ACPI_STATUS (Status); 105767754Smsmith} 1058