exfldio.c revision 209746
167754Smsmith/****************************************************************************** 267754Smsmith * 377424Smsmith * Module Name: exfldio - Aml Field I/O 467754Smsmith * 567754Smsmith *****************************************************************************/ 667754Smsmith 767754Smsmith/****************************************************************************** 867754Smsmith * 967754Smsmith * 1. Copyright Notice 1067754Smsmith * 11202771Sjkim * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp. 1270243Smsmith * All rights reserved. 1367754Smsmith * 1467754Smsmith * 2. License 1567754Smsmith * 1667754Smsmith * 2.1. This is your license from Intel Corp. under its intellectual property 1767754Smsmith * rights. You may have additional license terms from the party that provided 1867754Smsmith * you this software, covering your right to use that party's intellectual 1967754Smsmith * property rights. 2067754Smsmith * 2167754Smsmith * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 2267754Smsmith * copy of the source code appearing in this file ("Covered Code") an 2367754Smsmith * irrevocable, perpetual, worldwide license under Intel's copyrights in the 2467754Smsmith * base code distributed originally by Intel ("Original Intel Code") to copy, 2567754Smsmith * make derivatives, distribute, use and display any portion of the Covered 2667754Smsmith * Code in any form, with the right to sublicense such rights; and 2767754Smsmith * 2867754Smsmith * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 2967754Smsmith * license (with the right to sublicense), under only those claims of Intel 3067754Smsmith * patents that are infringed by the Original Intel Code, to make, use, sell, 3167754Smsmith * offer to sell, and import the Covered Code and derivative works thereof 3267754Smsmith * solely to the minimum extent necessary to exercise the above copyright 3367754Smsmith * license, and in no event shall the patent license extend to any additions 3467754Smsmith * to or modifications of the Original Intel Code. No other license or right 3567754Smsmith * is granted directly or by implication, estoppel or otherwise; 3667754Smsmith * 3767754Smsmith * The above copyright and patent license is granted only if the following 3867754Smsmith * conditions are met: 3967754Smsmith * 4067754Smsmith * 3. Conditions 4167754Smsmith * 4267754Smsmith * 3.1. Redistribution of Source with Rights to Further Distribute Source. 4367754Smsmith * Redistribution of source code of any substantial portion of the Covered 4467754Smsmith * Code or modification with rights to further distribute source must include 4567754Smsmith * the above Copyright Notice, the above License, this list of Conditions, 4667754Smsmith * and the following Disclaimer and Export Compliance provision. In addition, 4767754Smsmith * Licensee must cause all Covered Code to which Licensee contributes to 4867754Smsmith * contain a file documenting the changes Licensee made to create that Covered 4967754Smsmith * Code and the date of any change. Licensee must include in that file the 5067754Smsmith * documentation of any changes made by any predecessor Licensee. Licensee 5167754Smsmith * must include a prominent statement that the modification is derived, 5267754Smsmith * directly or indirectly, from Original Intel Code. 5367754Smsmith * 5467754Smsmith * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 5567754Smsmith * Redistribution of source code of any substantial portion of the Covered 5667754Smsmith * Code or modification without rights to further distribute source must 5767754Smsmith * include the following Disclaimer and Export Compliance provision in the 5867754Smsmith * documentation and/or other materials provided with distribution. In 5967754Smsmith * addition, Licensee may not authorize further sublicense of source of any 6067754Smsmith * portion of the Covered Code, and must include terms to the effect that the 6167754Smsmith * license from Licensee to its licensee is limited to the intellectual 6267754Smsmith * property embodied in the software Licensee provides to its licensee, and 6367754Smsmith * not to intellectual property embodied in modifications its licensee may 6467754Smsmith * make. 6567754Smsmith * 6667754Smsmith * 3.3. Redistribution of Executable. Redistribution in executable form of any 6767754Smsmith * substantial portion of the Covered Code or modification must reproduce the 6867754Smsmith * above Copyright Notice, and the following Disclaimer and Export Compliance 6967754Smsmith * provision in the documentation and/or other materials provided with the 7067754Smsmith * distribution. 7167754Smsmith * 7267754Smsmith * 3.4. Intel retains all right, title, and interest in and to the Original 7367754Smsmith * Intel Code. 7467754Smsmith * 7567754Smsmith * 3.5. Neither the name Intel nor any other trademark owned or controlled by 7667754Smsmith * Intel shall be used in advertising or otherwise to promote the sale, use or 7767754Smsmith * other dealings in products derived from or relating to the Covered Code 7867754Smsmith * without prior written authorization from Intel. 7967754Smsmith * 8067754Smsmith * 4. Disclaimer and Export Compliance 8167754Smsmith * 8267754Smsmith * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 8367754Smsmith * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 8467754Smsmith * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 8567754Smsmith * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 8667754Smsmith * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 8767754Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 8867754Smsmith * PARTICULAR PURPOSE. 8967754Smsmith * 9067754Smsmith * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 9167754Smsmith * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 9267754Smsmith * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 9367754Smsmith * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 9467754Smsmith * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 9567754Smsmith * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 9667754Smsmith * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 9767754Smsmith * LIMITED REMEDY. 9867754Smsmith * 9967754Smsmith * 4.3. Licensee shall not export, either directly or indirectly, any of this 10067754Smsmith * software or system incorporating such software without first obtaining any 10167754Smsmith * required license or other approval from the U. S. Department of Commerce or 10267754Smsmith * any other agency or department of the United States Government. In the 10367754Smsmith * event Licensee exports any such software from the United States or 10467754Smsmith * re-exports any such software from a foreign destination, Licensee shall 10567754Smsmith * ensure that the distribution and export/re-export of the software is in 10667754Smsmith * compliance with all laws, regulations, orders, or other restrictions of the 10767754Smsmith * U.S. Export Administration Regulations. Licensee agrees that neither it nor 10867754Smsmith * any of its subsidiaries will export/re-export any technical data, process, 10967754Smsmith * software, or service, directly or indirectly, to any country for which the 11067754Smsmith * United States government or any agency thereof requires an export license, 11167754Smsmith * other governmental approval, or letter of assurance, without first obtaining 11267754Smsmith * such license, approval or letter. 11367754Smsmith * 11467754Smsmith *****************************************************************************/ 11567754Smsmith 11667754Smsmith 11777424Smsmith#define __EXFLDIO_C__ 11867754Smsmith 119193341Sjkim#include <contrib/dev/acpica/include/acpi.h> 120193341Sjkim#include <contrib/dev/acpica/include/accommon.h> 121193341Sjkim#include <contrib/dev/acpica/include/acinterp.h> 122193341Sjkim#include <contrib/dev/acpica/include/amlcode.h> 123193341Sjkim#include <contrib/dev/acpica/include/acevents.h> 124193341Sjkim#include <contrib/dev/acpica/include/acdispat.h> 12567754Smsmith 12667754Smsmith 12777424Smsmith#define _COMPONENT ACPI_EXECUTER 12891116Smsmith ACPI_MODULE_NAME ("exfldio") 12967754Smsmith 130151937Sjkim/* Local prototypes */ 13167754Smsmith 132151937Sjkimstatic ACPI_STATUS 133151937SjkimAcpiExFieldDatumIo ( 134151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 135151937Sjkim UINT32 FieldDatumByteOffset, 136202771Sjkim UINT64 *Value, 137151937Sjkim UINT32 ReadWrite); 138151937Sjkim 139151937Sjkimstatic BOOLEAN 140151937SjkimAcpiExRegisterOverflow ( 141151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 142202771Sjkim UINT64 Value); 143151937Sjkim 144151937Sjkimstatic ACPI_STATUS 145151937SjkimAcpiExSetupRegion ( 146151937Sjkim ACPI_OPERAND_OBJECT *ObjDesc, 147151937Sjkim UINT32 FieldDatumByteOffset); 148151937Sjkim 149151937Sjkim 15067754Smsmith/******************************************************************************* 15167754Smsmith * 15287031Smsmith * FUNCTION: AcpiExSetupRegion 15367754Smsmith * 154151937Sjkim * PARAMETERS: ObjDesc - Field to be read or written 15587031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 15687031Smsmith * parent field 15767754Smsmith * 15867754Smsmith * RETURN: Status 15967754Smsmith * 16077424Smsmith * DESCRIPTION: Common processing for AcpiExExtractFromField and 161123315Snjl * AcpiExInsertIntoField. Initialize the Region if necessary and 162123315Snjl * validate the request. 16367754Smsmith * 16467754Smsmith ******************************************************************************/ 16567754Smsmith 166151937Sjkimstatic ACPI_STATUS 16787031SmsmithAcpiExSetupRegion ( 16867754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 16977424Smsmith UINT32 FieldDatumByteOffset) 17067754Smsmith{ 17177424Smsmith ACPI_STATUS Status = AE_OK; 17277424Smsmith ACPI_OPERAND_OBJECT *RgnDesc; 17367754Smsmith 17467754Smsmith 175167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset); 17667754Smsmith 17783174Smsmith 17877424Smsmith RgnDesc = ObjDesc->CommonField.RegionObj; 17967754Smsmith 180107325Siwasaki /* We must have a valid region */ 181107325Siwasaki 182193267Sjkim if (RgnDesc->Common.Type != ACPI_TYPE_REGION) 18377424Smsmith { 184204773Sjkim ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", 185193267Sjkim RgnDesc->Common.Type, 18699679Siwasaki AcpiUtGetObjectTypeName (RgnDesc))); 18799679Siwasaki 18877424Smsmith return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 18977424Smsmith } 19067754Smsmith 19177424Smsmith /* 19277424Smsmith * If the Region Address and Length have not been previously evaluated, 19377424Smsmith * evaluate them now and save the results. 19477424Smsmith */ 195123315Snjl if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) 19667754Smsmith { 19777424Smsmith Status = AcpiDsGetRegionArguments (RgnDesc); 19877424Smsmith if (ACPI_FAILURE (Status)) 19977424Smsmith { 20077424Smsmith return_ACPI_STATUS (Status); 20177424Smsmith } 20267754Smsmith } 20367754Smsmith 204167802Sjkim /* 205197104Sjkim * Exit now for SMBus or IPMI address space, it has a non-linear address space 206167802Sjkim * and the request cannot be directly validated 207167802Sjkim */ 208197104Sjkim if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 209197104Sjkim RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI) 210107325Siwasaki { 211197104Sjkim /* SMBus or IPMI has a non-linear address space */ 212107325Siwasaki 213107325Siwasaki return_ACPI_STATUS (AE_OK); 214107325Siwasaki } 215107325Siwasaki 216123315Snjl#ifdef ACPI_UNDER_DEVELOPMENT 21777424Smsmith /* 218123315Snjl * If the Field access is AnyAcc, we can now compute the optimal 219123315Snjl * access (because we know know the length of the parent region) 220123315Snjl */ 221123315Snjl if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 222123315Snjl { 223123315Snjl if (ACPI_FAILURE (Status)) 224123315Snjl { 225123315Snjl return_ACPI_STATUS (Status); 226123315Snjl } 227123315Snjl } 228123315Snjl#endif 229123315Snjl 230123315Snjl /* 23177424Smsmith * Validate the request. The entire request from the byte offset for a 23277424Smsmith * length of one field datum (access width) must fit within the region. 23377424Smsmith * (Region length is specified in bytes) 23477424Smsmith */ 235167802Sjkim if (RgnDesc->Region.Length < 236167802Sjkim (ObjDesc->CommonField.BaseByteOffset + 237167802Sjkim FieldDatumByteOffset + 238167802Sjkim ObjDesc->CommonField.AccessByteWidth)) 23977424Smsmith { 240138287Smarks if (AcpiGbl_EnableInterpreterSlack) 241138287Smarks { 242138287Smarks /* 243138287Smarks * Slack mode only: We will go ahead and allow access to this 244138287Smarks * field if it is within the region length rounded up to the next 245193267Sjkim * access width boundary. ACPI_SIZE cast for 64-bit compile. 246138287Smarks */ 247138287Smarks if (ACPI_ROUND_UP (RgnDesc->Region.Length, 248167802Sjkim ObjDesc->CommonField.AccessByteWidth) >= 249193267Sjkim ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset + 250193267Sjkim ObjDesc->CommonField.AccessByteWidth + 251193267Sjkim FieldDatumByteOffset)) 252138287Smarks { 253138287Smarks return_ACPI_STATUS (AE_OK); 254138287Smarks } 255138287Smarks } 256138287Smarks 25777424Smsmith if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) 25877424Smsmith { 25983174Smsmith /* 26077424Smsmith * This is the case where the AccessType (AccWord, etc.) is wider 26177424Smsmith * than the region itself. For example, a region of length one 26277424Smsmith * byte, and a field with Dword access specified. 26377424Smsmith */ 264167802Sjkim ACPI_ERROR ((AE_INFO, 265204773Sjkim "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)", 266123315Snjl AcpiUtGetNodeName (ObjDesc->CommonField.Node), 267123315Snjl ObjDesc->CommonField.AccessByteWidth, 268151937Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 269151937Sjkim RgnDesc->Region.Length)); 27077424Smsmith } 27177424Smsmith 27277424Smsmith /* 27377424Smsmith * Offset rounded up to next multiple of field width 27477424Smsmith * exceeds region length, indicate an error 27577424Smsmith */ 276167802Sjkim ACPI_ERROR ((AE_INFO, 277204773Sjkim "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)", 278123315Snjl AcpiUtGetNodeName (ObjDesc->CommonField.Node), 279123315Snjl ObjDesc->CommonField.BaseByteOffset, 28091116Smsmith FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, 281151937Sjkim AcpiUtGetNodeName (RgnDesc->Region.Node), 282151937Sjkim RgnDesc->Region.Length)); 28377424Smsmith 28477424Smsmith return_ACPI_STATUS (AE_AML_REGION_LIMIT); 28577424Smsmith } 28677424Smsmith 28777424Smsmith return_ACPI_STATUS (AE_OK); 28877424Smsmith} 28977424Smsmith 29077424Smsmith 29177424Smsmith/******************************************************************************* 29277424Smsmith * 29387031Smsmith * FUNCTION: AcpiExAccessRegion 29477424Smsmith * 295151937Sjkim * PARAMETERS: ObjDesc - Field to be read 29687031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 29787031Smsmith * parent field 298151937Sjkim * Value - Where to store value (must at least 299202771Sjkim * 64 bits) 300107325Siwasaki * Function - Read or Write flag plus other region- 301107325Siwasaki * dependent flags 30277424Smsmith * 30377424Smsmith * RETURN: Status 30477424Smsmith * 30587031Smsmith * DESCRIPTION: Read or Write a single field datum to an Operation Region. 30677424Smsmith * 30777424Smsmith ******************************************************************************/ 30877424Smsmith 30977424SmsmithACPI_STATUS 31087031SmsmithAcpiExAccessRegion ( 31177424Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 31277424Smsmith UINT32 FieldDatumByteOffset, 313202771Sjkim UINT64 *Value, 314107325Siwasaki UINT32 Function) 31577424Smsmith{ 31677424Smsmith ACPI_STATUS Status; 31777424Smsmith ACPI_OPERAND_OBJECT *RgnDesc; 318193267Sjkim UINT32 RegionOffset; 31977424Smsmith 32077424Smsmith 321167802Sjkim ACPI_FUNCTION_TRACE (ExAccessRegion); 32277424Smsmith 32377424Smsmith 324114237Snjl /* 325107325Siwasaki * Ensure that the region operands are fully evaluated and verify 326107325Siwasaki * the validity of the request 327107325Siwasaki */ 328107325Siwasaki Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); 329107325Siwasaki if (ACPI_FAILURE (Status)) 330107325Siwasaki { 331107325Siwasaki return_ACPI_STATUS (Status); 332107325Siwasaki } 333107325Siwasaki 33487031Smsmith /* 33587031Smsmith * The physical address of this field datum is: 33687031Smsmith * 33787031Smsmith * 1) The base of the region, plus 33887031Smsmith * 2) The base offset of the field, plus 33987031Smsmith * 3) The current offset into the field 34087031Smsmith */ 34187031Smsmith RgnDesc = ObjDesc->CommonField.RegionObj; 342193267Sjkim RegionOffset = 343193267Sjkim ObjDesc->CommonField.BaseByteOffset + 344193267Sjkim FieldDatumByteOffset; 34587031Smsmith 346107325Siwasaki if ((Function & ACPI_IO_MASK) == ACPI_READ) 34767754Smsmith { 34887031Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); 34967754Smsmith } 35087031Smsmith else 35187031Smsmith { 35287031Smsmith ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); 35387031Smsmith } 35467754Smsmith 35587031Smsmith ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, 356167802Sjkim " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", 35787031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 35887031Smsmith RgnDesc->Region.SpaceId, 35991116Smsmith ObjDesc->CommonField.AccessByteWidth, 36087031Smsmith ObjDesc->CommonField.BaseByteOffset, 36187031Smsmith FieldDatumByteOffset, 362193267Sjkim ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset)))); 36367754Smsmith 36487031Smsmith /* Invoke the appropriate AddressSpace/OpRegion handler */ 36577424Smsmith 366193267Sjkim Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, RegionOffset, 367151937Sjkim ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); 36887031Smsmith 36987031Smsmith if (ACPI_FAILURE (Status)) 37087031Smsmith { 37187031Smsmith if (Status == AE_NOT_IMPLEMENTED) 37287031Smsmith { 373167802Sjkim ACPI_ERROR ((AE_INFO, 374204773Sjkim "Region %s(0x%X) not implemented", 37587031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 37687031Smsmith RgnDesc->Region.SpaceId)); 37787031Smsmith } 37887031Smsmith else if (Status == AE_NOT_EXIST) 37987031Smsmith { 380167802Sjkim ACPI_ERROR ((AE_INFO, 381204773Sjkim "Region %s(0x%X) has no handler", 38287031Smsmith AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 38387031Smsmith RgnDesc->Region.SpaceId)); 38487031Smsmith } 38587031Smsmith } 38687031Smsmith 38787031Smsmith return_ACPI_STATUS (Status); 38887031Smsmith} 38987031Smsmith 39087031Smsmith 39187031Smsmith/******************************************************************************* 39287031Smsmith * 39387031Smsmith * FUNCTION: AcpiExRegisterOverflow 39487031Smsmith * 395151937Sjkim * PARAMETERS: ObjDesc - Register(Field) to be written 39687031Smsmith * Value - Value to be stored 39787031Smsmith * 39887031Smsmith * RETURN: TRUE if value overflows the field, FALSE otherwise 39987031Smsmith * 40087031Smsmith * DESCRIPTION: Check if a value is out of range of the field being written. 40187031Smsmith * Used to check if the values written to Index and Bank registers 40287031Smsmith * are out of range. Normally, the value is simply truncated 40387031Smsmith * to fit the field, but this case is most likely a serious 40487031Smsmith * coding error in the ASL. 40587031Smsmith * 40687031Smsmith ******************************************************************************/ 40787031Smsmith 408151937Sjkimstatic BOOLEAN 40987031SmsmithAcpiExRegisterOverflow ( 41087031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 411202771Sjkim UINT64 Value) 41287031Smsmith{ 41387031Smsmith 41491116Smsmith if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) 41591116Smsmith { 41691116Smsmith /* 41791116Smsmith * The field is large enough to hold the maximum integer, so we can 41891116Smsmith * never overflow it. 41991116Smsmith */ 42091116Smsmith return (FALSE); 42191116Smsmith } 42291116Smsmith 423202771Sjkim if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength)) 42487031Smsmith { 42591116Smsmith /* 42691116Smsmith * The Value is larger than the maximum value that can fit into 42791116Smsmith * the register. 42891116Smsmith */ 42987031Smsmith return (TRUE); 43087031Smsmith } 43187031Smsmith 43291116Smsmith /* The Value will fit into the field with no truncation */ 43391116Smsmith 43487031Smsmith return (FALSE); 43587031Smsmith} 43687031Smsmith 43787031Smsmith 43887031Smsmith/******************************************************************************* 43987031Smsmith * 44087031Smsmith * FUNCTION: AcpiExFieldDatumIo 44187031Smsmith * 442151937Sjkim * PARAMETERS: ObjDesc - Field to be read 44387031Smsmith * FieldDatumByteOffset - Byte offset of this datum within the 44487031Smsmith * parent field 445151937Sjkim * Value - Where to store value (must be 64 bits) 44687031Smsmith * ReadWrite - Read or Write flag 44787031Smsmith * 44887031Smsmith * RETURN: Status 44987031Smsmith * 45087031Smsmith * DESCRIPTION: Read or Write a single datum of a field. The FieldType is 45187031Smsmith * demultiplexed here to handle the different types of fields 45287031Smsmith * (BufferField, RegionField, IndexField, BankField) 45387031Smsmith * 45487031Smsmith ******************************************************************************/ 45587031Smsmith 456151937Sjkimstatic ACPI_STATUS 45787031SmsmithAcpiExFieldDatumIo ( 45887031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 45987031Smsmith UINT32 FieldDatumByteOffset, 460202771Sjkim UINT64 *Value, 46187031Smsmith UINT32 ReadWrite) 46287031Smsmith{ 46387031Smsmith ACPI_STATUS Status; 464202771Sjkim UINT64 LocalValue; 46587031Smsmith 46687031Smsmith 467167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset); 46887031Smsmith 46987031Smsmith 47087031Smsmith if (ReadWrite == ACPI_READ) 47187031Smsmith { 47287031Smsmith if (!Value) 47387031Smsmith { 47487031Smsmith LocalValue = 0; 475151937Sjkim 476151937Sjkim /* To support reads without saving return value */ 477151937Sjkim Value = &LocalValue; 47887031Smsmith } 47987031Smsmith 48087031Smsmith /* Clear the entire return buffer first, [Very Important!] */ 48187031Smsmith 48287031Smsmith *Value = 0; 48387031Smsmith } 48487031Smsmith 48587031Smsmith /* 48687031Smsmith * The four types of fields are: 48787031Smsmith * 488122944Snjl * BufferField - Read/write from/to a Buffer 489122944Snjl * RegionField - Read/write from/to a Operation Region. 490151937Sjkim * BankField - Write to a Bank Register, then read/write from/to an 491151937Sjkim * OperationRegion 492151937Sjkim * IndexField - Write to an Index Register, then read/write from/to a 493151937Sjkim * Data Register 49487031Smsmith */ 495193267Sjkim switch (ObjDesc->Common.Type) 49677424Smsmith { 49777424Smsmith case ACPI_TYPE_BUFFER_FIELD: 49877424Smsmith /* 49987031Smsmith * If the BufferField arguments have not been previously evaluated, 50087031Smsmith * evaluate them now and save the results. 50177424Smsmith */ 50287031Smsmith if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 50387031Smsmith { 50487031Smsmith Status = AcpiDsGetBufferFieldArguments (ObjDesc); 50587031Smsmith if (ACPI_FAILURE (Status)) 50687031Smsmith { 50787031Smsmith return_ACPI_STATUS (Status); 50887031Smsmith } 50987031Smsmith } 51087031Smsmith 51187031Smsmith if (ReadWrite == ACPI_READ) 51287031Smsmith { 51387031Smsmith /* 51487031Smsmith * Copy the data from the source buffer. 51587031Smsmith * Length is the field width in bytes. 51687031Smsmith */ 517151937Sjkim ACPI_MEMCPY (Value, 518151937Sjkim (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 519151937Sjkim ObjDesc->BufferField.BaseByteOffset + 520151937Sjkim FieldDatumByteOffset, 521151937Sjkim ObjDesc->CommonField.AccessByteWidth); 52287031Smsmith } 52387031Smsmith else 52487031Smsmith { 52587031Smsmith /* 52687031Smsmith * Copy the data to the target buffer. 52787031Smsmith * Length is the field width in bytes. 52887031Smsmith */ 529151937Sjkim ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 530167802Sjkim ObjDesc->BufferField.BaseByteOffset + 531167802Sjkim FieldDatumByteOffset, 532167802Sjkim Value, ObjDesc->CommonField.AccessByteWidth); 53387031Smsmith } 53487031Smsmith 53577424Smsmith Status = AE_OK; 53677424Smsmith break; 53767754Smsmith 53867754Smsmith 539107325Siwasaki case ACPI_TYPE_LOCAL_BANK_FIELD: 54067754Smsmith 541151937Sjkim /* 542151937Sjkim * Ensure that the BankValue is not beyond the capacity of 543151937Sjkim * the register 544151937Sjkim */ 54587031Smsmith if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 546202771Sjkim (UINT64) ObjDesc->BankField.Value)) 54787031Smsmith { 54887031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 54987031Smsmith } 55087031Smsmith 55177424Smsmith /* 55287031Smsmith * For BankFields, we must write the BankValue to the BankRegister 55387031Smsmith * (itself a RegionField) before we can access the data. 55477424Smsmith */ 55587031Smsmith Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 556167802Sjkim &ObjDesc->BankField.Value, 557167802Sjkim sizeof (ObjDesc->BankField.Value)); 55877424Smsmith if (ACPI_FAILURE (Status)) 55977424Smsmith { 56077424Smsmith return_ACPI_STATUS (Status); 56177424Smsmith } 56267754Smsmith 56377424Smsmith /* 56487031Smsmith * Now that the Bank has been selected, fall through to the 56587031Smsmith * RegionField case and write the datum to the Operation Region 56677424Smsmith */ 56777424Smsmith 56899679Siwasaki /*lint -fallthrough */ 56977424Smsmith 57077424Smsmith 571107325Siwasaki case ACPI_TYPE_LOCAL_REGION_FIELD: 57287031Smsmith /* 57387031Smsmith * For simple RegionFields, we just directly access the owning 57487031Smsmith * Operation Region. 57587031Smsmith */ 57687031Smsmith Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 577167802Sjkim ReadWrite); 57887031Smsmith break; 57987031Smsmith 58087031Smsmith 581107325Siwasaki case ACPI_TYPE_LOCAL_INDEX_FIELD: 58287031Smsmith 58387031Smsmith 584151937Sjkim /* 585151937Sjkim * Ensure that the IndexValue is not beyond the capacity of 586151937Sjkim * the register 587151937Sjkim */ 58887031Smsmith if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 589202771Sjkim (UINT64) ObjDesc->IndexField.Value)) 59077424Smsmith { 59187031Smsmith return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 59277424Smsmith } 59387031Smsmith 59487031Smsmith /* Write the index value to the IndexRegister (itself a RegionField) */ 59587031Smsmith 596122944Snjl FieldDatumByteOffset += ObjDesc->IndexField.Value; 597122944Snjl 598122944Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 599167802Sjkim "Write to Index Register: Value %8.8X\n", 600167802Sjkim FieldDatumByteOffset)); 601122944Snjl 60287031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 603167802Sjkim &FieldDatumByteOffset, 604167802Sjkim sizeof (FieldDatumByteOffset)); 60587031Smsmith if (ACPI_FAILURE (Status)) 60687031Smsmith { 60787031Smsmith return_ACPI_STATUS (Status); 60887031Smsmith } 60987031Smsmith 61087031Smsmith if (ReadWrite == ACPI_READ) 61187031Smsmith { 61287031Smsmith /* Read the datum from the DataRegister */ 61387031Smsmith 614193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 615193267Sjkim "Read from Data Register\n")); 616193267Sjkim 61787031Smsmith Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 618202771Sjkim Value, sizeof (UINT64)); 61987031Smsmith } 62087031Smsmith else 62187031Smsmith { 622122944Snjl /* Write the datum to the DataRegister */ 62387031Smsmith 624193267Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 625193267Sjkim "Write to Data Register: Value %8.8X%8.8X\n", 626193267Sjkim ACPI_FORMAT_UINT64 (*Value))); 627193267Sjkim 62887031Smsmith Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 629202771Sjkim Value, sizeof (UINT64)); 63087031Smsmith } 63177424Smsmith break; 63277424Smsmith 63377424Smsmith 63477424Smsmith default: 63577424Smsmith 636204773Sjkim ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u", 637193267Sjkim ObjDesc->Common.Type)); 63877424Smsmith Status = AE_AML_INTERNAL; 63977424Smsmith break; 64067754Smsmith } 64167754Smsmith 64287031Smsmith if (ACPI_SUCCESS (Status)) 64387031Smsmith { 64487031Smsmith if (ReadWrite == ACPI_READ) 64587031Smsmith { 646151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 647209746Sjkim "Value Read %8.8X%8.8X, Width %u\n", 648151937Sjkim ACPI_FORMAT_UINT64 (*Value), 649151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 65087031Smsmith } 65187031Smsmith else 65287031Smsmith { 653151937Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 654209746Sjkim "Value Written %8.8X%8.8X, Width %u\n", 655151937Sjkim ACPI_FORMAT_UINT64 (*Value), 656151937Sjkim ObjDesc->CommonField.AccessByteWidth)); 65787031Smsmith } 65887031Smsmith } 65977424Smsmith 66087031Smsmith return_ACPI_STATUS (Status); 66187031Smsmith} 66277424Smsmith 66387031Smsmith 66487031Smsmith/******************************************************************************* 66587031Smsmith * 66687031Smsmith * FUNCTION: AcpiExWriteWithUpdateRule 66787031Smsmith * 668151937Sjkim * PARAMETERS: ObjDesc - Field to be written 669151937Sjkim * Mask - bitmask within field datum 670151937Sjkim * FieldValue - Value to write 671151937Sjkim * FieldDatumByteOffset - Offset of datum within field 67287031Smsmith * 67387031Smsmith * RETURN: Status 67487031Smsmith * 67587031Smsmith * DESCRIPTION: Apply the field update rule to a field write 67687031Smsmith * 67787031Smsmith ******************************************************************************/ 67887031Smsmith 67987031SmsmithACPI_STATUS 68087031SmsmithAcpiExWriteWithUpdateRule ( 68187031Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 682202771Sjkim UINT64 Mask, 683202771Sjkim UINT64 FieldValue, 68487031Smsmith UINT32 FieldDatumByteOffset) 68587031Smsmith{ 68687031Smsmith ACPI_STATUS Status = AE_OK; 687202771Sjkim UINT64 MergedValue; 688202771Sjkim UINT64 CurrentValue; 68987031Smsmith 69087031Smsmith 691167802Sjkim ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask); 69287031Smsmith 69387031Smsmith 69487031Smsmith /* Start with the new bits */ 69587031Smsmith 69687031Smsmith MergedValue = FieldValue; 69787031Smsmith 69887031Smsmith /* If the mask is all ones, we don't need to worry about the update rule */ 69987031Smsmith 700202771Sjkim if (Mask != ACPI_UINT64_MAX) 70187031Smsmith { 70287031Smsmith /* Decode the update rule */ 70387031Smsmith 70487031Smsmith switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 70587031Smsmith { 70687031Smsmith case AML_FIELD_UPDATE_PRESERVE: 70787031Smsmith /* 70887031Smsmith * Check if update rule needs to be applied (not if mask is all 70987031Smsmith * ones) The left shift drops the bits we want to ignore. 71087031Smsmith */ 71191116Smsmith if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 71291116Smsmith ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 71387031Smsmith { 71487031Smsmith /* 71587031Smsmith * Read the current contents of the byte/word/dword containing 71687031Smsmith * the field, and merge with the new field value. 71787031Smsmith */ 71887031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 719167802Sjkim &CurrentValue, ACPI_READ); 720123315Snjl if (ACPI_FAILURE (Status)) 721123315Snjl { 722123315Snjl return_ACPI_STATUS (Status); 723123315Snjl } 724123315Snjl 72587031Smsmith MergedValue |= (CurrentValue & ~Mask); 72687031Smsmith } 72787031Smsmith break; 72887031Smsmith 72987031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ONES: 73087031Smsmith 73187031Smsmith /* Set positions outside the field to all ones */ 73287031Smsmith 73387031Smsmith MergedValue |= ~Mask; 73487031Smsmith break; 73587031Smsmith 73687031Smsmith case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 73787031Smsmith 73887031Smsmith /* Set positions outside the field to all zeros */ 73987031Smsmith 74087031Smsmith MergedValue &= Mask; 74187031Smsmith break; 74287031Smsmith 74387031Smsmith default: 744123315Snjl 745167802Sjkim ACPI_ERROR ((AE_INFO, 746204773Sjkim "Unknown UpdateRule value: 0x%X", 74787031Smsmith (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 74887031Smsmith return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 74987031Smsmith } 75087031Smsmith } 75187031Smsmith 752123315Snjl ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 753123315Snjl "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 754123315Snjl ACPI_FORMAT_UINT64 (Mask), 755123315Snjl FieldDatumByteOffset, 756123315Snjl ObjDesc->CommonField.AccessByteWidth, 757123315Snjl ACPI_FORMAT_UINT64 (FieldValue), 758123315Snjl ACPI_FORMAT_UINT64 (MergedValue))); 759123315Snjl 76087031Smsmith /* Write the merged value */ 76187031Smsmith 76287031Smsmith Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 763167802Sjkim &MergedValue, ACPI_WRITE); 76487031Smsmith 76577424Smsmith return_ACPI_STATUS (Status); 76677424Smsmith} 76777424Smsmith 76877424Smsmith 76977424Smsmith/******************************************************************************* 77077424Smsmith * 77177424Smsmith * FUNCTION: AcpiExExtractFromField 77267754Smsmith * 773131440Smarks * PARAMETERS: ObjDesc - Field to be read 774131440Smarks * Buffer - Where to store the field data 775131440Smarks * BufferLength - Length of Buffer 77667754Smsmith * 77767754Smsmith * RETURN: Status 77867754Smsmith * 779131440Smarks * DESCRIPTION: Retrieve the current value of the given field 78067754Smsmith * 78167754Smsmith ******************************************************************************/ 78267754Smsmith 78367754SmsmithACPI_STATUS 78477424SmsmithAcpiExExtractFromField ( 78567754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 78667754Smsmith void *Buffer, 78777424Smsmith UINT32 BufferLength) 78867754Smsmith{ 78967754Smsmith ACPI_STATUS Status; 790202771Sjkim UINT64 RawDatum; 791202771Sjkim UINT64 MergedDatum; 792151937Sjkim UINT32 FieldOffset = 0; 793151937Sjkim UINT32 BufferOffset = 0; 794151937Sjkim UINT32 BufferTailBits; 79577424Smsmith UINT32 DatumCount; 796151937Sjkim UINT32 FieldDatumCount; 797123315Snjl UINT32 i; 79867754Smsmith 79967754Smsmith 800167802Sjkim ACPI_FUNCTION_TRACE (ExExtractFromField); 80167754Smsmith 80277424Smsmith 803151937Sjkim /* Validate target buffer and clear it */ 80477424Smsmith 805167802Sjkim if (BufferLength < 806167802Sjkim ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) 807151937Sjkim { 808167802Sjkim ACPI_ERROR ((AE_INFO, 809204773Sjkim "Field size %u (bits) is too large for buffer (%u)", 810151937Sjkim ObjDesc->CommonField.BitLength, BufferLength)); 811151937Sjkim 812151937Sjkim return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 813151937Sjkim } 814151937Sjkim ACPI_MEMSET (Buffer, 0, BufferLength); 815151937Sjkim 816151937Sjkim /* Compute the number of datums (access width data items) */ 817151937Sjkim 818151937Sjkim DatumCount = ACPI_ROUND_UP_TO ( 819151937Sjkim ObjDesc->CommonField.BitLength, 820151937Sjkim ObjDesc->CommonField.AccessBitWidth); 821151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO ( 822151937Sjkim ObjDesc->CommonField.BitLength + 823151937Sjkim ObjDesc->CommonField.StartFieldBitOffset, 824151937Sjkim ObjDesc->CommonField.AccessBitWidth); 825151937Sjkim 826151937Sjkim /* Priming read from the field */ 827151937Sjkim 828151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); 829131440Smarks if (ACPI_FAILURE (Status)) 830123315Snjl { 831131440Smarks return_ACPI_STATUS (Status); 832123315Snjl } 833151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 834123315Snjl 835151937Sjkim /* Read the rest of the field */ 83667754Smsmith 837151937Sjkim for (i = 1; i < FieldDatumCount; i++) 838151937Sjkim { 839151937Sjkim /* Get next input datum from the field */ 84067754Smsmith 841151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 842151937Sjkim Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, 843167802Sjkim &RawDatum, ACPI_READ); 844123315Snjl if (ACPI_FAILURE (Status)) 845123315Snjl { 846123315Snjl return_ACPI_STATUS (Status); 847123315Snjl } 84867754Smsmith 849167802Sjkim /* 850167802Sjkim * Merge with previous datum if necessary. 851167802Sjkim * 852167802Sjkim * Note: Before the shift, check if the shift value will be larger than 853167802Sjkim * the integer size. If so, there is no need to perform the operation. 854167802Sjkim * This avoids the differences in behavior between different compilers 855167802Sjkim * concerning shift values larger than the target data width. 856167802Sjkim */ 857167802Sjkim if ((ObjDesc->CommonField.AccessBitWidth - 858167802Sjkim ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE) 859167802Sjkim { 860167802Sjkim MergedDatum |= RawDatum << 861167802Sjkim (ObjDesc->CommonField.AccessBitWidth - 862167802Sjkim ObjDesc->CommonField.StartFieldBitOffset); 863167802Sjkim } 86467754Smsmith 865151937Sjkim if (i == DatumCount) 86667754Smsmith { 867151937Sjkim break; 86877424Smsmith } 86967754Smsmith 870151937Sjkim /* Write merged datum to target buffer */ 87171867Smsmith 872151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 873151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 874167802Sjkim BufferLength - BufferOffset)); 87567754Smsmith 876151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 877151937Sjkim MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 878151937Sjkim } 879123315Snjl 880151937Sjkim /* Mask off any extra bits in the last datum */ 881123315Snjl 882151937Sjkim BufferTailBits = ObjDesc->CommonField.BitLength % 883151937Sjkim ObjDesc->CommonField.AccessBitWidth; 884151937Sjkim if (BufferTailBits) 885151937Sjkim { 886151937Sjkim MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 887123315Snjl } 888123315Snjl 889151937Sjkim /* Write the last datum to the buffer */ 890123315Snjl 891151937Sjkim ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 892151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 893167802Sjkim BufferLength - BufferOffset)); 894123315Snjl 89577424Smsmith return_ACPI_STATUS (AE_OK); 89667754Smsmith} 89767754Smsmith 89867754Smsmith 89967754Smsmith/******************************************************************************* 90067754Smsmith * 90177424Smsmith * FUNCTION: AcpiExInsertIntoField 90267754Smsmith * 903131440Smarks * PARAMETERS: ObjDesc - Field to be written 904131440Smarks * Buffer - Data to be written 905131440Smarks * BufferLength - Length of Buffer 90667754Smsmith * 90767754Smsmith * RETURN: Status 90867754Smsmith * 909131440Smarks * DESCRIPTION: Store the Buffer contents into the given field 91067754Smsmith * 91177424Smsmith ******************************************************************************/ 91267754Smsmith 91367754SmsmithACPI_STATUS 91477424SmsmithAcpiExInsertIntoField ( 91567754Smsmith ACPI_OPERAND_OBJECT *ObjDesc, 91667754Smsmith void *Buffer, 91777424Smsmith UINT32 BufferLength) 91867754Smsmith{ 91967754Smsmith ACPI_STATUS Status; 920202771Sjkim UINT64 Mask; 921202771Sjkim UINT64 WidthMask; 922202771Sjkim UINT64 MergedDatum; 923202771Sjkim UINT64 RawDatum = 0; 924151937Sjkim UINT32 FieldOffset = 0; 925151937Sjkim UINT32 BufferOffset = 0; 926151937Sjkim UINT32 BufferTailBits; 92777424Smsmith UINT32 DatumCount; 928151937Sjkim UINT32 FieldDatumCount; 929151937Sjkim UINT32 i; 930193267Sjkim UINT32 RequiredLength; 931193267Sjkim void *NewBuffer; 93267754Smsmith 93367754Smsmith 934167802Sjkim ACPI_FUNCTION_TRACE (ExInsertIntoField); 93567754Smsmith 93667754Smsmith 937151937Sjkim /* Validate input buffer */ 938131440Smarks 939193267Sjkim NewBuffer = NULL; 940193267Sjkim RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 941193267Sjkim ObjDesc->CommonField.BitLength); 942193267Sjkim /* 943193267Sjkim * We must have a buffer that is at least as long as the field 944193267Sjkim * we are writing to. This is because individual fields are 945193267Sjkim * indivisible and partial writes are not supported -- as per 946193267Sjkim * the ACPI specification. 947193267Sjkim */ 948193267Sjkim if (BufferLength < RequiredLength) 94977424Smsmith { 950193267Sjkim /* We need to create a new buffer */ 951151937Sjkim 952193267Sjkim NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); 953193267Sjkim if (!NewBuffer) 954193267Sjkim { 955193267Sjkim return_ACPI_STATUS (AE_NO_MEMORY); 956193267Sjkim } 957193267Sjkim 958193267Sjkim /* 959193267Sjkim * Copy the original data to the new buffer, starting 960193267Sjkim * at Byte zero. All unused (upper) bytes of the 961193267Sjkim * buffer will be 0. 962193267Sjkim */ 963193267Sjkim ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength); 964193267Sjkim Buffer = NewBuffer; 965193267Sjkim BufferLength = RequiredLength; 96677424Smsmith } 96767754Smsmith 968167802Sjkim /* 969167802Sjkim * Create the bitmasks used for bit insertion. 970167802Sjkim * Note: This if/else is used to bypass compiler differences with the 971167802Sjkim * shift operator 972167802Sjkim */ 973167802Sjkim if (ObjDesc->CommonField.AccessBitWidth == ACPI_INTEGER_BIT_SIZE) 974167802Sjkim { 975202771Sjkim WidthMask = ACPI_UINT64_MAX; 976167802Sjkim } 977167802Sjkim else 978167802Sjkim { 979167802Sjkim WidthMask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.AccessBitWidth); 980167802Sjkim } 981167802Sjkim 982167802Sjkim Mask = WidthMask & 983167802Sjkim ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 984167802Sjkim 985151937Sjkim /* Compute the number of datums (access width data items) */ 98667754Smsmith 987151937Sjkim DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, 988151937Sjkim ObjDesc->CommonField.AccessBitWidth); 989167802Sjkim 990151937Sjkim FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + 991151937Sjkim ObjDesc->CommonField.StartFieldBitOffset, 992151937Sjkim ObjDesc->CommonField.AccessBitWidth); 99367754Smsmith 994151937Sjkim /* Get initial Datum from the input buffer */ 99567754Smsmith 996151937Sjkim ACPI_MEMCPY (&RawDatum, Buffer, 997151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 998167802Sjkim BufferLength - BufferOffset)); 99967754Smsmith 1000151937Sjkim MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 100167754Smsmith 1002151937Sjkim /* Write the entire field */ 100367754Smsmith 1004151937Sjkim for (i = 1; i < FieldDatumCount; i++) 100567754Smsmith { 1006151937Sjkim /* Write merged datum to the target field */ 100767754Smsmith 1008151937Sjkim MergedDatum &= Mask; 1009151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, 1010151937Sjkim MergedDatum, FieldOffset); 1011151937Sjkim if (ACPI_FAILURE (Status)) 1012151937Sjkim { 1013193267Sjkim goto Exit; 1014151937Sjkim } 1015123315Snjl 1016151937Sjkim FieldOffset += ObjDesc->CommonField.AccessByteWidth; 101767754Smsmith 1018167802Sjkim /* 1019167802Sjkim * Start new output datum by merging with previous input datum 1020167802Sjkim * if necessary. 1021167802Sjkim * 1022167802Sjkim * Note: Before the shift, check if the shift value will be larger than 1023167802Sjkim * the integer size. If so, there is no need to perform the operation. 1024167802Sjkim * This avoids the differences in behavior between different compilers 1025167802Sjkim * concerning shift values larger than the target data width. 1026167802Sjkim */ 1027167802Sjkim if ((ObjDesc->CommonField.AccessBitWidth - 1028167802Sjkim ObjDesc->CommonField.StartFieldBitOffset) < ACPI_INTEGER_BIT_SIZE) 1029167802Sjkim { 1030167802Sjkim MergedDatum = RawDatum >> 1031167802Sjkim (ObjDesc->CommonField.AccessBitWidth - 1032167802Sjkim ObjDesc->CommonField.StartFieldBitOffset); 1033167802Sjkim } 1034167802Sjkim else 1035167802Sjkim { 1036167802Sjkim MergedDatum = 0; 1037167802Sjkim } 1038167802Sjkim 1039167802Sjkim Mask = WidthMask; 1040167802Sjkim 1041151937Sjkim if (i == DatumCount) 104267754Smsmith { 1043151937Sjkim break; 104467754Smsmith } 104577424Smsmith 1046151937Sjkim /* Get the next input datum from the buffer */ 104767754Smsmith 1048151937Sjkim BufferOffset += ObjDesc->CommonField.AccessByteWidth; 1049151937Sjkim ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, 1050151937Sjkim ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 1051151937Sjkim BufferLength - BufferOffset)); 1052151937Sjkim MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 1053151937Sjkim } 105467754Smsmith 1055151937Sjkim /* Mask off any extra bits in the last datum */ 105667754Smsmith 1057151937Sjkim BufferTailBits = (ObjDesc->CommonField.BitLength + 1058151937Sjkim ObjDesc->CommonField.StartFieldBitOffset) % 1059151937Sjkim ObjDesc->CommonField.AccessBitWidth; 1060151937Sjkim if (BufferTailBits) 1061151937Sjkim { 1062151937Sjkim Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 1063151937Sjkim } 1064123315Snjl 1065151937Sjkim /* Write the last datum to the field */ 106667754Smsmith 1067151937Sjkim MergedDatum &= Mask; 1068151937Sjkim Status = AcpiExWriteWithUpdateRule (ObjDesc, 1069151937Sjkim Mask, MergedDatum, FieldOffset); 107067754Smsmith 1071193267SjkimExit: 1072193267Sjkim /* Free temporary buffer if we used one */ 1073193267Sjkim 1074193267Sjkim if (NewBuffer) 1075193267Sjkim { 1076193267Sjkim ACPI_FREE (NewBuffer); 1077193267Sjkim } 107867754Smsmith return_ACPI_STATUS (Status); 107967754Smsmith} 108067754Smsmith 108167754Smsmith 1082