Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenexfldio.c
Go to the documentation of this file.
00001 /****************************************************************************** 00002 * 00003 * Module Name: exfldio - Aml Field I/O 00004 * 00005 *****************************************************************************/ 00006 00007 /****************************************************************************** 00008 * 00009 * 1. Copyright Notice 00010 * 00011 * Some or all of this work - Copyright (c) 1999 - 2011, Intel Corp. 00012 * All rights reserved. 00013 * 00014 * 2. License 00015 * 00016 * 2.1. This is your license from Intel Corp. under its intellectual property 00017 * rights. You may have additional license terms from the party that provided 00018 * you this software, covering your right to use that party's intellectual 00019 * property rights. 00020 * 00021 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 00022 * copy of the source code appearing in this file ("Covered Code") an 00023 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 00024 * base code distributed originally by Intel ("Original Intel Code") to copy, 00025 * make derivatives, distribute, use and display any portion of the Covered 00026 * Code in any form, with the right to sublicense such rights; and 00027 * 00028 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 00029 * license (with the right to sublicense), under only those claims of Intel 00030 * patents that are infringed by the Original Intel Code, to make, use, sell, 00031 * offer to sell, and import the Covered Code and derivative works thereof 00032 * solely to the minimum extent necessary to exercise the above copyright 00033 * license, and in no event shall the patent license extend to any additions 00034 * to or modifications of the Original Intel Code. No other license or right 00035 * is granted directly or by implication, estoppel or otherwise; 00036 * 00037 * The above copyright and patent license is granted only if the following 00038 * conditions are met: 00039 * 00040 * 3. Conditions 00041 * 00042 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 00043 * Redistribution of source code of any substantial portion of the Covered 00044 * Code or modification with rights to further distribute source must include 00045 * the above Copyright Notice, the above License, this list of Conditions, 00046 * and the following Disclaimer and Export Compliance provision. In addition, 00047 * Licensee must cause all Covered Code to which Licensee contributes to 00048 * contain a file documenting the changes Licensee made to create that Covered 00049 * Code and the date of any change. Licensee must include in that file the 00050 * documentation of any changes made by any predecessor Licensee. Licensee 00051 * must include a prominent statement that the modification is derived, 00052 * directly or indirectly, from Original Intel Code. 00053 * 00054 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 00055 * Redistribution of source code of any substantial portion of the Covered 00056 * Code or modification without rights to further distribute source must 00057 * include the following Disclaimer and Export Compliance provision in the 00058 * documentation and/or other materials provided with distribution. In 00059 * addition, Licensee may not authorize further sublicense of source of any 00060 * portion of the Covered Code, and must include terms to the effect that the 00061 * license from Licensee to its licensee is limited to the intellectual 00062 * property embodied in the software Licensee provides to its licensee, and 00063 * not to intellectual property embodied in modifications its licensee may 00064 * make. 00065 * 00066 * 3.3. Redistribution of Executable. Redistribution in executable form of any 00067 * substantial portion of the Covered Code or modification must reproduce the 00068 * above Copyright Notice, and the following Disclaimer and Export Compliance 00069 * provision in the documentation and/or other materials provided with the 00070 * distribution. 00071 * 00072 * 3.4. Intel retains all right, title, and interest in and to the Original 00073 * Intel Code. 00074 * 00075 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 00076 * Intel shall be used in advertising or otherwise to promote the sale, use or 00077 * other dealings in products derived from or relating to the Covered Code 00078 * without prior written authorization from Intel. 00079 * 00080 * 4. Disclaimer and Export Compliance 00081 * 00082 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 00083 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 00084 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 00085 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 00086 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 00087 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 00088 * PARTICULAR PURPOSE. 00089 * 00090 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 00091 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 00092 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 00093 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 00094 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 00095 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 00096 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 00097 * LIMITED REMEDY. 00098 * 00099 * 4.3. Licensee shall not export, either directly or indirectly, any of this 00100 * software or system incorporating such software without first obtaining any 00101 * required license or other approval from the U. S. Department of Commerce or 00102 * any other agency or department of the United States Government. In the 00103 * event Licensee exports any such software from the United States or 00104 * re-exports any such software from a foreign destination, Licensee shall 00105 * ensure that the distribution and export/re-export of the software is in 00106 * compliance with all laws, regulations, orders, or other restrictions of the 00107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 00108 * any of its subsidiaries will export/re-export any technical data, process, 00109 * software, or service, directly or indirectly, to any country for which the 00110 * United States government or any agency thereof requires an export license, 00111 * other governmental approval, or letter of assurance, without first obtaining 00112 * such license, approval or letter. 00113 * 00114 *****************************************************************************/ 00115 00116 00117 #define __EXFLDIO_C__ 00118 00119 #include "acpi.h" 00120 #include "accommon.h" 00121 #include "acinterp.h" 00122 #include "amlcode.h" 00123 #include "acevents.h" 00124 #include "acdispat.h" 00125 00126 00127 #define _COMPONENT ACPI_EXECUTER 00128 ACPI_MODULE_NAME ("exfldio") 00129 00130 /* Local prototypes */ 00131 00132 static ACPI_STATUS 00133 AcpiExFieldDatumIo ( 00134 ACPI_OPERAND_OBJECT *ObjDesc, 00135 UINT32 FieldDatumByteOffset, 00136 UINT64 *Value, 00137 UINT32 ReadWrite); 00138 00139 static BOOLEAN 00140 AcpiExRegisterOverflow ( 00141 ACPI_OPERAND_OBJECT *ObjDesc, 00142 UINT64 Value); 00143 00144 static ACPI_STATUS 00145 AcpiExSetupRegion ( 00146 ACPI_OPERAND_OBJECT *ObjDesc, 00147 UINT32 FieldDatumByteOffset); 00148 00149 00150 /******************************************************************************* 00151 * 00152 * FUNCTION: AcpiExSetupRegion 00153 * 00154 * PARAMETERS: ObjDesc - Field to be read or written 00155 * FieldDatumByteOffset - Byte offset of this datum within the 00156 * parent field 00157 * 00158 * RETURN: Status 00159 * 00160 * DESCRIPTION: Common processing for AcpiExExtractFromField and 00161 * AcpiExInsertIntoField. Initialize the Region if necessary and 00162 * validate the request. 00163 * 00164 ******************************************************************************/ 00165 00166 static ACPI_STATUS 00167 AcpiExSetupRegion ( 00168 ACPI_OPERAND_OBJECT *ObjDesc, 00169 UINT32 FieldDatumByteOffset) 00170 { 00171 ACPI_STATUS Status = AE_OK; 00172 ACPI_OPERAND_OBJECT *RgnDesc; 00173 00174 00175 ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset); 00176 00177 00178 RgnDesc = ObjDesc->CommonField.RegionObj; 00179 00180 /* We must have a valid region */ 00181 00182 if (RgnDesc->Common.Type != ACPI_TYPE_REGION) 00183 { 00184 ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)", 00185 RgnDesc->Common.Type, 00186 AcpiUtGetObjectTypeName (RgnDesc))); 00187 00188 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 00189 } 00190 00191 /* 00192 * If the Region Address and Length have not been previously evaluated, 00193 * evaluate them now and save the results. 00194 */ 00195 if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) 00196 { 00197 Status = AcpiDsGetRegionArguments (RgnDesc); 00198 if (ACPI_FAILURE (Status)) 00199 { 00200 return_ACPI_STATUS (Status); 00201 } 00202 } 00203 00204 /* 00205 * Exit now for SMBus or IPMI address space, it has a non-linear 00206 * address space and the request cannot be directly validated 00207 */ 00208 if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 00209 RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI) 00210 { 00211 /* SMBus or IPMI has a non-linear address space */ 00212 00213 return_ACPI_STATUS (AE_OK); 00214 } 00215 00216 #ifdef ACPI_UNDER_DEVELOPMENT 00217 /* 00218 * If the Field access is AnyAcc, we can now compute the optimal 00219 * access (because we know know the length of the parent region) 00220 */ 00221 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 00222 { 00223 if (ACPI_FAILURE (Status)) 00224 { 00225 return_ACPI_STATUS (Status); 00226 } 00227 } 00228 #endif 00229 00230 /* 00231 * Validate the request. The entire request from the byte offset for a 00232 * length of one field datum (access width) must fit within the region. 00233 * (Region length is specified in bytes) 00234 */ 00235 if (RgnDesc->Region.Length < 00236 (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset + 00237 ObjDesc->CommonField.AccessByteWidth)) 00238 { 00239 if (AcpiGbl_EnableInterpreterSlack) 00240 { 00241 /* 00242 * Slack mode only: We will go ahead and allow access to this 00243 * field if it is within the region length rounded up to the next 00244 * access width boundary. ACPI_SIZE cast for 64-bit compile. 00245 */ 00246 if (ACPI_ROUND_UP (RgnDesc->Region.Length, 00247 ObjDesc->CommonField.AccessByteWidth) >= 00248 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset + 00249 ObjDesc->CommonField.AccessByteWidth + 00250 FieldDatumByteOffset)) 00251 { 00252 return_ACPI_STATUS (AE_OK); 00253 } 00254 } 00255 00256 if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) 00257 { 00258 /* 00259 * This is the case where the AccessType (AccWord, etc.) is wider 00260 * than the region itself. For example, a region of length one 00261 * byte, and a field with Dword access specified. 00262 */ 00263 ACPI_ERROR ((AE_INFO, 00264 "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)", 00265 AcpiUtGetNodeName (ObjDesc->CommonField.Node), 00266 ObjDesc->CommonField.AccessByteWidth, 00267 AcpiUtGetNodeName (RgnDesc->Region.Node), 00268 RgnDesc->Region.Length)); 00269 } 00270 00271 /* 00272 * Offset rounded up to next multiple of field width 00273 * exceeds region length, indicate an error 00274 */ 00275 ACPI_ERROR ((AE_INFO, 00276 "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)", 00277 AcpiUtGetNodeName (ObjDesc->CommonField.Node), 00278 ObjDesc->CommonField.BaseByteOffset, 00279 FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, 00280 AcpiUtGetNodeName (RgnDesc->Region.Node), 00281 RgnDesc->Region.Length)); 00282 00283 return_ACPI_STATUS (AE_AML_REGION_LIMIT); 00284 } 00285 00286 return_ACPI_STATUS (AE_OK); 00287 } 00288 00289 00290 /******************************************************************************* 00291 * 00292 * FUNCTION: AcpiExAccessRegion 00293 * 00294 * PARAMETERS: ObjDesc - Field to be read 00295 * FieldDatumByteOffset - Byte offset of this datum within the 00296 * parent field 00297 * Value - Where to store value (must at least 00298 * 64 bits) 00299 * Function - Read or Write flag plus other region- 00300 * dependent flags 00301 * 00302 * RETURN: Status 00303 * 00304 * DESCRIPTION: Read or Write a single field datum to an Operation Region. 00305 * 00306 ******************************************************************************/ 00307 00308 ACPI_STATUS 00309 AcpiExAccessRegion ( 00310 ACPI_OPERAND_OBJECT *ObjDesc, 00311 UINT32 FieldDatumByteOffset, 00312 UINT64 *Value, 00313 UINT32 Function) 00314 { 00315 ACPI_STATUS Status; 00316 ACPI_OPERAND_OBJECT *RgnDesc; 00317 UINT32 RegionOffset; 00318 00319 00320 ACPI_FUNCTION_TRACE (ExAccessRegion); 00321 00322 00323 /* 00324 * Ensure that the region operands are fully evaluated and verify 00325 * the validity of the request 00326 */ 00327 Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); 00328 if (ACPI_FAILURE (Status)) 00329 { 00330 return_ACPI_STATUS (Status); 00331 } 00332 00333 /* 00334 * The physical address of this field datum is: 00335 * 00336 * 1) The base of the region, plus 00337 * 2) The base offset of the field, plus 00338 * 3) The current offset into the field 00339 */ 00340 RgnDesc = ObjDesc->CommonField.RegionObj; 00341 RegionOffset = 00342 ObjDesc->CommonField.BaseByteOffset + 00343 FieldDatumByteOffset; 00344 00345 if ((Function & ACPI_IO_MASK) == ACPI_READ) 00346 { 00347 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); 00348 } 00349 else 00350 { 00351 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); 00352 } 00353 00354 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, 00355 " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n", 00356 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 00357 RgnDesc->Region.SpaceId, 00358 ObjDesc->CommonField.AccessByteWidth, 00359 ObjDesc->CommonField.BaseByteOffset, 00360 FieldDatumByteOffset, 00361 ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset)))); 00362 00363 /* Invoke the appropriate AddressSpace/OpRegion handler */ 00364 00365 Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, RegionOffset, 00366 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); 00367 00368 if (ACPI_FAILURE (Status)) 00369 { 00370 if (Status == AE_NOT_IMPLEMENTED) 00371 { 00372 ACPI_ERROR ((AE_INFO, 00373 "Region %s (ID=%u) not implemented", 00374 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 00375 RgnDesc->Region.SpaceId)); 00376 } 00377 else if (Status == AE_NOT_EXIST) 00378 { 00379 ACPI_ERROR ((AE_INFO, 00380 "Region %s (ID=%u) has no handler", 00381 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 00382 RgnDesc->Region.SpaceId)); 00383 } 00384 } 00385 00386 return_ACPI_STATUS (Status); 00387 } 00388 00389 00390 /******************************************************************************* 00391 * 00392 * FUNCTION: AcpiExRegisterOverflow 00393 * 00394 * PARAMETERS: ObjDesc - Register(Field) to be written 00395 * Value - Value to be stored 00396 * 00397 * RETURN: TRUE if value overflows the field, FALSE otherwise 00398 * 00399 * DESCRIPTION: Check if a value is out of range of the field being written. 00400 * Used to check if the values written to Index and Bank registers 00401 * are out of range. Normally, the value is simply truncated 00402 * to fit the field, but this case is most likely a serious 00403 * coding error in the ASL. 00404 * 00405 ******************************************************************************/ 00406 00407 static BOOLEAN 00408 AcpiExRegisterOverflow ( 00409 ACPI_OPERAND_OBJECT *ObjDesc, 00410 UINT64 Value) 00411 { 00412 00413 if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) 00414 { 00415 /* 00416 * The field is large enough to hold the maximum integer, so we can 00417 * never overflow it. 00418 */ 00419 return (FALSE); 00420 } 00421 00422 if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength)) 00423 { 00424 /* 00425 * The Value is larger than the maximum value that can fit into 00426 * the register. 00427 */ 00428 return (TRUE); 00429 } 00430 00431 /* The Value will fit into the field with no truncation */ 00432 00433 return (FALSE); 00434 } 00435 00436 00437 /******************************************************************************* 00438 * 00439 * FUNCTION: AcpiExFieldDatumIo 00440 * 00441 * PARAMETERS: ObjDesc - Field to be read 00442 * FieldDatumByteOffset - Byte offset of this datum within the 00443 * parent field 00444 * Value - Where to store value (must be 64 bits) 00445 * ReadWrite - Read or Write flag 00446 * 00447 * RETURN: Status 00448 * 00449 * DESCRIPTION: Read or Write a single datum of a field. The FieldType is 00450 * demultiplexed here to handle the different types of fields 00451 * (BufferField, RegionField, IndexField, BankField) 00452 * 00453 ******************************************************************************/ 00454 00455 static ACPI_STATUS 00456 AcpiExFieldDatumIo ( 00457 ACPI_OPERAND_OBJECT *ObjDesc, 00458 UINT32 FieldDatumByteOffset, 00459 UINT64 *Value, 00460 UINT32 ReadWrite) 00461 { 00462 ACPI_STATUS Status; 00463 UINT64 LocalValue; 00464 00465 00466 ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset); 00467 00468 00469 if (ReadWrite == ACPI_READ) 00470 { 00471 if (!Value) 00472 { 00473 LocalValue = 0; 00474 00475 /* To support reads without saving return value */ 00476 Value = &LocalValue; 00477 } 00478 00479 /* Clear the entire return buffer first, [Very Important!] */ 00480 00481 *Value = 0; 00482 } 00483 00484 /* 00485 * The four types of fields are: 00486 * 00487 * BufferField - Read/write from/to a Buffer 00488 * RegionField - Read/write from/to a Operation Region. 00489 * BankField - Write to a Bank Register, then read/write from/to an 00490 * OperationRegion 00491 * IndexField - Write to an Index Register, then read/write from/to a 00492 * Data Register 00493 */ 00494 switch (ObjDesc->Common.Type) 00495 { 00496 case ACPI_TYPE_BUFFER_FIELD: 00497 /* 00498 * If the BufferField arguments have not been previously evaluated, 00499 * evaluate them now and save the results. 00500 */ 00501 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 00502 { 00503 Status = AcpiDsGetBufferFieldArguments (ObjDesc); 00504 if (ACPI_FAILURE (Status)) 00505 { 00506 return_ACPI_STATUS (Status); 00507 } 00508 } 00509 00510 if (ReadWrite == ACPI_READ) 00511 { 00512 /* 00513 * Copy the data from the source buffer. 00514 * Length is the field width in bytes. 00515 */ 00516 ACPI_MEMCPY (Value, 00517 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 00518 ObjDesc->BufferField.BaseByteOffset + 00519 FieldDatumByteOffset, 00520 ObjDesc->CommonField.AccessByteWidth); 00521 } 00522 else 00523 { 00524 /* 00525 * Copy the data to the target buffer. 00526 * Length is the field width in bytes. 00527 */ 00528 ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer + 00529 ObjDesc->BufferField.BaseByteOffset + 00530 FieldDatumByteOffset, 00531 Value, ObjDesc->CommonField.AccessByteWidth); 00532 } 00533 00534 Status = AE_OK; 00535 break; 00536 00537 00538 case ACPI_TYPE_LOCAL_BANK_FIELD: 00539 00540 /* 00541 * Ensure that the BankValue is not beyond the capacity of 00542 * the register 00543 */ 00544 if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 00545 (UINT64) ObjDesc->BankField.Value)) 00546 { 00547 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 00548 } 00549 00550 /* 00551 * For BankFields, we must write the BankValue to the BankRegister 00552 * (itself a RegionField) before we can access the data. 00553 */ 00554 Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 00555 &ObjDesc->BankField.Value, 00556 sizeof (ObjDesc->BankField.Value)); 00557 if (ACPI_FAILURE (Status)) 00558 { 00559 return_ACPI_STATUS (Status); 00560 } 00561 00562 /* 00563 * Now that the Bank has been selected, fall through to the 00564 * RegionField case and write the datum to the Operation Region 00565 */ 00566 00567 /*lint -fallthrough */ 00568 00569 00570 case ACPI_TYPE_LOCAL_REGION_FIELD: 00571 /* 00572 * For simple RegionFields, we just directly access the owning 00573 * Operation Region. 00574 */ 00575 Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 00576 ReadWrite); 00577 break; 00578 00579 00580 case ACPI_TYPE_LOCAL_INDEX_FIELD: 00581 00582 00583 /* 00584 * Ensure that the IndexValue is not beyond the capacity of 00585 * the register 00586 */ 00587 if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 00588 (UINT64) ObjDesc->IndexField.Value)) 00589 { 00590 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 00591 } 00592 00593 /* Write the index value to the IndexRegister (itself a RegionField) */ 00594 00595 FieldDatumByteOffset += ObjDesc->IndexField.Value; 00596 00597 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 00598 "Write to Index Register: Value %8.8X\n", 00599 FieldDatumByteOffset)); 00600 00601 Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 00602 &FieldDatumByteOffset, 00603 sizeof (FieldDatumByteOffset)); 00604 if (ACPI_FAILURE (Status)) 00605 { 00606 return_ACPI_STATUS (Status); 00607 } 00608 00609 if (ReadWrite == ACPI_READ) 00610 { 00611 /* Read the datum from the DataRegister */ 00612 00613 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 00614 "Read from Data Register\n")); 00615 00616 Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 00617 Value, sizeof (UINT64)); 00618 } 00619 else 00620 { 00621 /* Write the datum to the DataRegister */ 00622 00623 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 00624 "Write to Data Register: Value %8.8X%8.8X\n", 00625 ACPI_FORMAT_UINT64 (*Value))); 00626 00627 Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 00628 Value, sizeof (UINT64)); 00629 } 00630 break; 00631 00632 00633 default: 00634 00635 ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u", 00636 ObjDesc->Common.Type)); 00637 Status = AE_AML_INTERNAL; 00638 break; 00639 } 00640 00641 if (ACPI_SUCCESS (Status)) 00642 { 00643 if (ReadWrite == ACPI_READ) 00644 { 00645 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 00646 "Value Read %8.8X%8.8X, Width %u\n", 00647 ACPI_FORMAT_UINT64 (*Value), 00648 ObjDesc->CommonField.AccessByteWidth)); 00649 } 00650 else 00651 { 00652 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 00653 "Value Written %8.8X%8.8X, Width %u\n", 00654 ACPI_FORMAT_UINT64 (*Value), 00655 ObjDesc->CommonField.AccessByteWidth)); 00656 } 00657 } 00658 00659 return_ACPI_STATUS (Status); 00660 } 00661 00662 00663 /******************************************************************************* 00664 * 00665 * FUNCTION: AcpiExWriteWithUpdateRule 00666 * 00667 * PARAMETERS: ObjDesc - Field to be written 00668 * Mask - bitmask within field datum 00669 * FieldValue - Value to write 00670 * FieldDatumByteOffset - Offset of datum within field 00671 * 00672 * RETURN: Status 00673 * 00674 * DESCRIPTION: Apply the field update rule to a field write 00675 * 00676 ******************************************************************************/ 00677 00678 ACPI_STATUS 00679 AcpiExWriteWithUpdateRule ( 00680 ACPI_OPERAND_OBJECT *ObjDesc, 00681 UINT64 Mask, 00682 UINT64 FieldValue, 00683 UINT32 FieldDatumByteOffset) 00684 { 00685 ACPI_STATUS Status = AE_OK; 00686 UINT64 MergedValue; 00687 UINT64 CurrentValue; 00688 00689 00690 ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask); 00691 00692 00693 /* Start with the new bits */ 00694 00695 MergedValue = FieldValue; 00696 00697 /* If the mask is all ones, we don't need to worry about the update rule */ 00698 00699 if (Mask != ACPI_UINT64_MAX) 00700 { 00701 /* Decode the update rule */ 00702 00703 switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 00704 { 00705 case AML_FIELD_UPDATE_PRESERVE: 00706 /* 00707 * Check if update rule needs to be applied (not if mask is all 00708 * ones) The left shift drops the bits we want to ignore. 00709 */ 00710 if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 00711 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 00712 { 00713 /* 00714 * Read the current contents of the byte/word/dword containing 00715 * the field, and merge with the new field value. 00716 */ 00717 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 00718 &CurrentValue, ACPI_READ); 00719 if (ACPI_FAILURE (Status)) 00720 { 00721 return_ACPI_STATUS (Status); 00722 } 00723 00724 MergedValue |= (CurrentValue & ~Mask); 00725 } 00726 break; 00727 00728 case AML_FIELD_UPDATE_WRITE_AS_ONES: 00729 00730 /* Set positions outside the field to all ones */ 00731 00732 MergedValue |= ~Mask; 00733 break; 00734 00735 case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 00736 00737 /* Set positions outside the field to all zeros */ 00738 00739 MergedValue &= Mask; 00740 break; 00741 00742 default: 00743 00744 ACPI_ERROR ((AE_INFO, 00745 "Unknown UpdateRule value: 0x%X", 00746 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 00747 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 00748 } 00749 } 00750 00751 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 00752 "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 00753 ACPI_FORMAT_UINT64 (Mask), 00754 FieldDatumByteOffset, 00755 ObjDesc->CommonField.AccessByteWidth, 00756 ACPI_FORMAT_UINT64 (FieldValue), 00757 ACPI_FORMAT_UINT64 (MergedValue))); 00758 00759 /* Write the merged value */ 00760 00761 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 00762 &MergedValue, ACPI_WRITE); 00763 00764 return_ACPI_STATUS (Status); 00765 } 00766 00767 00768 /******************************************************************************* 00769 * 00770 * FUNCTION: AcpiExExtractFromField 00771 * 00772 * PARAMETERS: ObjDesc - Field to be read 00773 * Buffer - Where to store the field data 00774 * BufferLength - Length of Buffer 00775 * 00776 * RETURN: Status 00777 * 00778 * DESCRIPTION: Retrieve the current value of the given field 00779 * 00780 ******************************************************************************/ 00781 00782 ACPI_STATUS 00783 AcpiExExtractFromField ( 00784 ACPI_OPERAND_OBJECT *ObjDesc, 00785 void *Buffer, 00786 UINT32 BufferLength) 00787 { 00788 ACPI_STATUS Status; 00789 UINT64 RawDatum; 00790 UINT64 MergedDatum; 00791 UINT32 FieldOffset = 0; 00792 UINT32 BufferOffset = 0; 00793 UINT32 BufferTailBits; 00794 UINT32 DatumCount; 00795 UINT32 FieldDatumCount; 00796 UINT32 AccessBitWidth; 00797 UINT32 i; 00798 00799 00800 ACPI_FUNCTION_TRACE (ExExtractFromField); 00801 00802 00803 /* Validate target buffer and clear it */ 00804 00805 if (BufferLength < 00806 ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength)) 00807 { 00808 ACPI_ERROR ((AE_INFO, 00809 "Field size %u (bits) is too large for buffer (%u)", 00810 ObjDesc->CommonField.BitLength, BufferLength)); 00811 00812 return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 00813 } 00814 00815 ACPI_MEMSET (Buffer, 0, BufferLength); 00816 AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 00817 00818 /* Handle the simple case here */ 00819 00820 if ((ObjDesc->CommonField.StartFieldBitOffset == 0) && 00821 (ObjDesc->CommonField.BitLength == AccessBitWidth)) 00822 { 00823 Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ); 00824 return_ACPI_STATUS (Status); 00825 } 00826 00827 /* TBD: Move to common setup code */ 00828 00829 /* Field algorithm is limited to sizeof(UINT64), truncate if needed */ 00830 00831 if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 00832 { 00833 ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 00834 AccessBitWidth = sizeof (UINT64) * 8; 00835 } 00836 00837 /* Compute the number of datums (access width data items) */ 00838 00839 DatumCount = ACPI_ROUND_UP_TO ( 00840 ObjDesc->CommonField.BitLength, AccessBitWidth); 00841 00842 FieldDatumCount = ACPI_ROUND_UP_TO ( 00843 ObjDesc->CommonField.BitLength + 00844 ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth); 00845 00846 /* Priming read from the field */ 00847 00848 Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ); 00849 if (ACPI_FAILURE (Status)) 00850 { 00851 return_ACPI_STATUS (Status); 00852 } 00853 MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 00854 00855 /* Read the rest of the field */ 00856 00857 for (i = 1; i < FieldDatumCount; i++) 00858 { 00859 /* Get next input datum from the field */ 00860 00861 FieldOffset += ObjDesc->CommonField.AccessByteWidth; 00862 Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, 00863 &RawDatum, ACPI_READ); 00864 if (ACPI_FAILURE (Status)) 00865 { 00866 return_ACPI_STATUS (Status); 00867 } 00868 00869 /* 00870 * Merge with previous datum if necessary. 00871 * 00872 * Note: Before the shift, check if the shift value will be larger than 00873 * the integer size. If so, there is no need to perform the operation. 00874 * This avoids the differences in behavior between different compilers 00875 * concerning shift values larger than the target data width. 00876 */ 00877 if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset < 00878 ACPI_INTEGER_BIT_SIZE) 00879 { 00880 MergedDatum |= RawDatum << 00881 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 00882 } 00883 00884 if (i == DatumCount) 00885 { 00886 break; 00887 } 00888 00889 /* Write merged datum to target buffer */ 00890 00891 ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 00892 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 00893 BufferLength - BufferOffset)); 00894 00895 BufferOffset += ObjDesc->CommonField.AccessByteWidth; 00896 MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset; 00897 } 00898 00899 /* Mask off any extra bits in the last datum */ 00900 00901 BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth; 00902 if (BufferTailBits) 00903 { 00904 MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 00905 } 00906 00907 /* Write the last datum to the buffer */ 00908 00909 ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum, 00910 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 00911 BufferLength - BufferOffset)); 00912 00913 return_ACPI_STATUS (AE_OK); 00914 } 00915 00916 00917 /******************************************************************************* 00918 * 00919 * FUNCTION: AcpiExInsertIntoField 00920 * 00921 * PARAMETERS: ObjDesc - Field to be written 00922 * Buffer - Data to be written 00923 * BufferLength - Length of Buffer 00924 * 00925 * RETURN: Status 00926 * 00927 * DESCRIPTION: Store the Buffer contents into the given field 00928 * 00929 ******************************************************************************/ 00930 00931 ACPI_STATUS 00932 AcpiExInsertIntoField ( 00933 ACPI_OPERAND_OBJECT *ObjDesc, 00934 void *Buffer, 00935 UINT32 BufferLength) 00936 { 00937 void *NewBuffer; 00938 ACPI_STATUS Status; 00939 UINT64 Mask; 00940 UINT64 WidthMask; 00941 UINT64 MergedDatum; 00942 UINT64 RawDatum = 0; 00943 UINT32 FieldOffset = 0; 00944 UINT32 BufferOffset = 0; 00945 UINT32 BufferTailBits; 00946 UINT32 DatumCount; 00947 UINT32 FieldDatumCount; 00948 UINT32 AccessBitWidth; 00949 UINT32 RequiredLength; 00950 UINT32 i; 00951 00952 00953 ACPI_FUNCTION_TRACE (ExInsertIntoField); 00954 00955 00956 /* Validate input buffer */ 00957 00958 NewBuffer = NULL; 00959 RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 00960 ObjDesc->CommonField.BitLength); 00961 /* 00962 * We must have a buffer that is at least as long as the field 00963 * we are writing to. This is because individual fields are 00964 * indivisible and partial writes are not supported -- as per 00965 * the ACPI specification. 00966 */ 00967 if (BufferLength < RequiredLength) 00968 { 00969 /* We need to create a new buffer */ 00970 00971 NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength); 00972 if (!NewBuffer) 00973 { 00974 return_ACPI_STATUS (AE_NO_MEMORY); 00975 } 00976 00977 /* 00978 * Copy the original data to the new buffer, starting 00979 * at Byte zero. All unused (upper) bytes of the 00980 * buffer will be 0. 00981 */ 00982 ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength); 00983 Buffer = NewBuffer; 00984 BufferLength = RequiredLength; 00985 } 00986 00987 /* TBD: Move to common setup code */ 00988 00989 /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */ 00990 if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64)) 00991 { 00992 ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64); 00993 } 00994 00995 AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth); 00996 00997 /* 00998 * Create the bitmasks used for bit insertion. 00999 * Note: This if/else is used to bypass compiler differences with the 01000 * shift operator 01001 */ 01002 if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE) 01003 { 01004 WidthMask = ACPI_UINT64_MAX; 01005 } 01006 else 01007 { 01008 WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth); 01009 } 01010 01011 Mask = WidthMask & 01012 ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 01013 01014 /* Compute the number of datums (access width data items) */ 01015 01016 DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength, 01017 AccessBitWidth); 01018 01019 FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength + 01020 ObjDesc->CommonField.StartFieldBitOffset, 01021 AccessBitWidth); 01022 01023 /* Get initial Datum from the input buffer */ 01024 01025 ACPI_MEMCPY (&RawDatum, Buffer, 01026 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 01027 BufferLength - BufferOffset)); 01028 01029 MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 01030 01031 /* Write the entire field */ 01032 01033 for (i = 1; i < FieldDatumCount; i++) 01034 { 01035 /* Write merged datum to the target field */ 01036 01037 MergedDatum &= Mask; 01038 Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, 01039 MergedDatum, FieldOffset); 01040 if (ACPI_FAILURE (Status)) 01041 { 01042 goto Exit; 01043 } 01044 01045 FieldOffset += ObjDesc->CommonField.AccessByteWidth; 01046 01047 /* 01048 * Start new output datum by merging with previous input datum 01049 * if necessary. 01050 * 01051 * Note: Before the shift, check if the shift value will be larger than 01052 * the integer size. If so, there is no need to perform the operation. 01053 * This avoids the differences in behavior between different compilers 01054 * concerning shift values larger than the target data width. 01055 */ 01056 if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) < 01057 ACPI_INTEGER_BIT_SIZE) 01058 { 01059 MergedDatum = RawDatum >> 01060 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset); 01061 } 01062 else 01063 { 01064 MergedDatum = 0; 01065 } 01066 01067 Mask = WidthMask; 01068 01069 if (i == DatumCount) 01070 { 01071 break; 01072 } 01073 01074 /* Get the next input datum from the buffer */ 01075 01076 BufferOffset += ObjDesc->CommonField.AccessByteWidth; 01077 ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset, 01078 ACPI_MIN(ObjDesc->CommonField.AccessByteWidth, 01079 BufferLength - BufferOffset)); 01080 01081 MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset; 01082 } 01083 01084 /* Mask off any extra bits in the last datum */ 01085 01086 BufferTailBits = (ObjDesc->CommonField.BitLength + 01087 ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth; 01088 if (BufferTailBits) 01089 { 01090 Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits); 01091 } 01092 01093 /* Write the last datum to the field */ 01094 01095 MergedDatum &= Mask; 01096 Status = AcpiExWriteWithUpdateRule (ObjDesc, 01097 Mask, MergedDatum, FieldOffset); 01098 01099 Exit: 01100 /* Free temporary buffer if we used one */ 01101 01102 if (NewBuffer) 01103 { 01104 ACPI_FREE (NewBuffer); 01105 } 01106 return_ACPI_STATUS (Status); 01107 } 01108 01109 Generated on Tue May 22 2012 04:31:07 for ReactOS by
1.7.6.1
|