exfldio.c revision 73561
150476Speter/****************************************************************************** 221611Swosch * 321611Swosch * Module Name: amfldio - Aml Field I/O 421611Swosch * $Revision: 39 $ 521611Swosch * 618052Sbde *****************************************************************************/ 721611Swosch 836494Sbde/****************************************************************************** 918052Sbde * 1036494Sbde * 1. Copyright Notice 1176576Smarkm * 1239412Sphk * Some or all of this work - Copyright (c) 1999, 2000, 2001, Intel Corp. 1336494Sbde * All rights reserved. 1476515Sbde * 1569227Sbrian * 2. License 1636494Sbde * 1739259Sgibbs * 2.1. This is your license from Intel Corp. under its intellectual property 1836575Speter * rights. You may have additional license terms from the party that provided 1976515Sbde * you this software, covering your right to use that party's intellectual 2036494Sbde * property rights. 2136494Sbde * 2257461Smarkm * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 2336494Sbde * copy of the source code appearing in this file ("Covered Code") an 2436575Speter * irrevocable, perpetual, worldwide license under Intel's copyrights in the 2576515Sbde * base code distributed originally by Intel ("Original Intel Code") to copy, 2639259Sgibbs * make derivatives, distribute, use and display any portion of the Covered 2736494Sbde * Code in any form, with the right to sublicense such rights; and 2836494Sbde * 2936494Sbde * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 3074535Sdes * license (with the right to sublicense), under only those claims of Intel 3118052Sbde * patents that are infringed by the Original Intel Code, to make, use, sell, 3276515Sbde * offer to sell, and import the Covered Code and derivative works thereof 3336494Sbde * solely to the minimum extent necessary to exercise the above copyright 3476515Sbde * license, and in no event shall the patent license extend to any additions 3536494Sbde * to or modifications of the Original Intel Code. No other license or right 3636494Sbde * is granted directly or by implication, estoppel or otherwise; 3736494Sbde * 3847570Sache * The above copyright and patent license is granted only if the following 3957538Sshin * conditions are met: 4036494Sbde * 4167523Sarchie * 3. Conditions 4236575Speter * 4336575Speter * 3.1. Redistribution of Source with Rights to Further Distribute Source. 4476576Smarkm * Redistribution of source code of any substantial portion of the Covered 4536494Sbde * Code or modification with rights to further distribute source must include 4636494Sbde * the above Copyright Notice, the above License, this list of Conditions, 4736494Sbde * and the following Disclaimer and Export Compliance provision. In addition, 4865916Sache * Licensee must cause all Covered Code to which Licensee contributes to 4936494Sbde * contain a file documenting the changes Licensee made to create that Covered 5036494Sbde * Code and the date of any change. Licensee must include in that file the 5176515Sbde * documentation of any changes made by any predecessor Licensee. Licensee 5236494Sbde * must include a prominent statement that the modification is derived, 5365916Sache * directly or indirectly, from Original Intel Code. 5452251Sbp * 5536494Sbde * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 5652419Sjulian * Redistribution of source code of any substantial portion of the Covered 5736494Sbde * Code or modification without rights to further distribute source must 5836494Sbde * include the following Disclaimer and Export Compliance provision in the 5942916Sjdp * documentation and/or other materials provided with distribution. In 6042916Sjdp * addition, Licensee may not authorize further sublicense of source of any 6142916Sjdp * portion of the Covered Code, and must include terms to the effect that the 6259770Sbde * license from Licensee to its licensee is limited to the intellectual 6342916Sjdp * property embodied in the software Licensee provides to its licensee, and 6442916Sjdp * not to intellectual property embodied in modifications its licensee may 6576576Smarkm * make. 6642916Sjdp * 6776576Smarkm * 3.3. Redistribution of Executable. Redistribution in executable form of any 6876576Smarkm * substantial portion of the Covered Code or modification must reproduce the 6942916Sjdp * above Copyright Notice, and the following Disclaimer and Export Compliance 7076576Smarkm * provision in the documentation and/or other materials provided with the 7177866Smarkm * distribution. 7277866Smarkm * 7376576Smarkm * 3.4. Intel retains all right, title, and interest in and to the Original 7477866Smarkm * Intel Code. 7576576Smarkm * 7676576Smarkm * 3.5. Neither the name Intel nor any other trademark owned or controlled by 7755157Sbde * Intel shall be used in advertising or otherwise to promote the sale, use or 7877866Smarkm * other dealings in products derived from or relating to the Covered Code 7977866Smarkm * without prior written authorization from Intel. 8042916Sjdp * 8142916Sjdp * 4. Disclaimer and Export Compliance 8276515Sbde * 8336494Sbde * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 8436494Sbde * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 8539020Smarkm * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 8636494Sbde * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 8741231Sjdp * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 8836494Sbde * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 8936494Sbde * PARTICULAR PURPOSE. 9077866Smarkm * 9136494Sbde * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 9274840Sken * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 9336494Sbde * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 9436494Sbde * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 9566913Sgshapiro * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 9636494Sbde * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 9741231Sjdp * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 9836494Sbde * LIMITED REMEDY. 9918052Sbde * 10076515Sbde * 4.3. Licensee shall not export, either directly or indirectly, any of this 10136494Sbde * software or system incorporating such software without first obtaining any 10276515Sbde * required license or other approval from the U. S. Department of Commerce or 10376515Sbde * any other agency or department of the United States Government. In the 10444757Smarkm * event Licensee exports any such software from the United States or 10536494Sbde * re-exports any such software from a foreign destination, Licensee shall 10636494Sbde * ensure that the distribution and export/re-export of the software is in 10736494Sbde * compliance with all laws, regulations, orders, or other restrictions of the 108 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 109 * any of its subsidiaries will export/re-export any technical data, process, 110 * software, or service, directly or indirectly, to any country for which the 111 * United States government or any agency thereof requires an export license, 112 * other governmental approval, or letter of assurance, without first obtaining 113 * such license, approval or letter. 114 * 115 *****************************************************************************/ 116 117 118#define __AMFLDIO_C__ 119 120#include "acpi.h" 121#include "acinterp.h" 122#include "amlcode.h" 123#include "acnamesp.h" 124#include "achware.h" 125#include "acevents.h" 126 127 128#define _COMPONENT INTERPRETER 129 MODULE_NAME ("amfldio") 130 131 132/******************************************************************************* 133 * 134 * FUNCTION: AcpiAmlReadFieldData 135 * 136 * PARAMETERS: *ObjDesc - Field to be read 137 * *Value - Where to store value 138 * FieldBitWidth - Field Width in bits (8, 16, or 32) 139 * 140 * RETURN: Status 141 * 142 * DESCRIPTION: Retrieve the value of the given field 143 * 144 ******************************************************************************/ 145 146ACPI_STATUS 147AcpiAmlReadFieldData ( 148 ACPI_OPERAND_OBJECT *ObjDesc, 149 UINT32 FieldByteOffset, 150 UINT32 FieldBitWidth, 151 UINT32 *Value) 152{ 153 ACPI_STATUS Status; 154 ACPI_OPERAND_OBJECT *RgnDesc = NULL; 155 ACPI_PHYSICAL_ADDRESS Address; 156 UINT32 LocalValue = 0; 157 UINT32 FieldByteWidth; 158 159 160 FUNCTION_TRACE ("AmlReadFieldData"); 161 162 163 /* ObjDesc is validated by callers */ 164 165 if (ObjDesc) 166 { 167 RgnDesc = ObjDesc->Field.Container; 168 } 169 170 171 FieldByteWidth = DIV_8 (FieldBitWidth); 172 Status = AcpiAmlSetupField (ObjDesc, RgnDesc, FieldBitWidth); 173 if (ACPI_FAILURE (Status)) 174 { 175 return_ACPI_STATUS (Status); 176 } 177 178 /* SetupField validated RgnDesc and FieldBitWidth */ 179 180 if (!Value) 181 { 182 Value = &LocalValue; /* support reads without saving value */ 183 } 184 185 186 /* 187 * Set offset to next multiple of field width, 188 * add region base address and offset within the field 189 */ 190 Address = RgnDesc->Region.Address + 191 (ObjDesc->Field.Offset * FieldByteWidth) + 192 FieldByteOffset; 193 194 DEBUG_PRINT (TRACE_OPREGION, 195 ("AmlReadFieldData: Region %s(%X) at %08lx width %X\n", 196 AcpiCmGetRegionName (RgnDesc->Region.SpaceId), 197 RgnDesc->Region.SpaceId, Address, 198 FieldBitWidth)); 199 200 201 /* Invoke the appropriate AddressSpace/OpRegion handler */ 202 203 Status = AcpiEvAddressSpaceDispatch (RgnDesc, ADDRESS_SPACE_READ, 204 Address, FieldBitWidth, Value); 205 206 if (Status == AE_NOT_IMPLEMENTED) 207 { 208 DEBUG_PRINT (ACPI_ERROR, 209 ("AmlReadFieldData: **** Region %s(%X) not implemented\n", 210 AcpiCmGetRegionName (RgnDesc->Region.SpaceId), 211 RgnDesc->Region.SpaceId)); 212 } 213 214 else if (Status == AE_NOT_EXIST) 215 { 216 DEBUG_PRINT (ACPI_ERROR, 217 ("AmlReadFieldData: **** Region %s(%X) has no handler\n", 218 AcpiCmGetRegionName (RgnDesc->Region.SpaceId), 219 RgnDesc->Region.SpaceId)); 220 } 221 222 DEBUG_PRINT (TRACE_OPREGION, 223 ("AmlReadField: Returned value=%08lx \n", *Value)); 224 225 return_ACPI_STATUS (Status); 226} 227 228 229/******************************************************************************* 230 * 231 * FUNCTION: AcpiAmlReadField 232 * 233 * PARAMETERS: *ObjDesc - Field to be read 234 * *Value - Where to store value 235 * FieldBitWidth - Field Width in bits (8, 16, or 32) 236 * 237 * RETURN: Status 238 * 239 * DESCRIPTION: Retrieve the value of the given field 240 * 241 ******************************************************************************/ 242 243ACPI_STATUS 244AcpiAmlReadField ( 245 ACPI_OPERAND_OBJECT *ObjDesc, 246 void *Buffer, 247 UINT32 BufferLength, 248 UINT32 ByteLength, 249 UINT32 DatumLength, 250 UINT32 BitGranularity, 251 UINT32 ByteGranularity) 252{ 253 ACPI_STATUS Status; 254 UINT32 ThisFieldByteOffset; 255 UINT32 ThisFieldDatumOffset; 256 UINT32 PreviousRawDatum; 257 UINT32 ThisRawDatum = 0; 258 UINT32 ValidFieldBits; 259 UINT32 Mask; 260 UINT32 MergedDatum = 0; 261 262 263 FUNCTION_TRACE ("AmlReadField"); 264 265 /* 266 * Clear the caller's buffer (the whole buffer length as given) 267 * This is very important, especially in the cases where a byte is read, 268 * but the buffer is really a UINT32 (4 bytes). 269 */ 270 271 MEMSET (Buffer, 0, BufferLength); 272 273 /* Read the first raw datum to prime the loop */ 274 275 ThisFieldByteOffset = 0; 276 ThisFieldDatumOffset= 0; 277 278 Status = AcpiAmlReadFieldData (ObjDesc, ThisFieldByteOffset, BitGranularity, 279 &PreviousRawDatum); 280 if (ACPI_FAILURE (Status)) 281 { 282 goto Cleanup; 283 } 284 285 /* We might actually be done if the request fits in one datum */ 286 287 if ((DatumLength == 1) && 288 ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) <= 289 (UINT16) BitGranularity)) 290 { 291 MergedDatum = PreviousRawDatum; 292 293 MergedDatum = (MergedDatum >> ObjDesc->Field.BitOffset); 294 295 ValidFieldBits = ObjDesc->FieldUnit.Length % BitGranularity; 296 if (ValidFieldBits) 297 { 298 Mask = (((UINT32) 1 << ValidFieldBits) - (UINT32) 1); 299 MergedDatum &= Mask; 300 } 301 302 303 /* 304 * Place the MergedDatum into the proper format and return buffer 305 * field 306 */ 307 308 switch (ByteGranularity) 309 { 310 case 1: 311 ((UINT8 *) Buffer) [ThisFieldDatumOffset] = (UINT8) MergedDatum; 312 break; 313 314 case 2: 315 MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer)[ThisFieldDatumOffset]), &MergedDatum); 316 break; 317 318 case 4: 319 MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer)[ThisFieldDatumOffset]), &MergedDatum); 320 break; 321 } 322 323 ThisFieldByteOffset = 1; 324 ThisFieldDatumOffset = 1; 325 } 326 327 else 328 { 329 /* We need to get more raw data to complete one or more field data */ 330 331 while (ThisFieldDatumOffset < DatumLength) 332 { 333 /* 334 * If the field is aligned on a byte boundary, we don't want 335 * to perform a final read, since this would potentially read 336 * past the end of the region. 337 * 338 * TBD: [Investigate] It may make more sense to just split the aligned 339 * and non-aligned cases since the aligned case is so very simple, 340 */ 341 if ((ObjDesc->Field.BitOffset != 0) || 342 ((ObjDesc->Field.BitOffset == 0) && 343 (ThisFieldDatumOffset < (DatumLength -1)))) 344 { 345 /* 346 * Get the next raw datum, it contains some or all bits 347 * of the current field datum 348 */ 349 350 Status = AcpiAmlReadFieldData (ObjDesc, 351 ThisFieldByteOffset + ByteGranularity, 352 BitGranularity, &ThisRawDatum); 353 if (ACPI_FAILURE (Status)) 354 { 355 goto Cleanup; 356 } 357 358 /* Before merging the data, make sure the unused bits are clear */ 359 360 switch (ByteGranularity) 361 { 362 case 1: 363 ThisRawDatum &= 0x000000FF; 364 PreviousRawDatum &= 0x000000FF; 365 break; 366 367 case 2: 368 ThisRawDatum &= 0x0000FFFF; 369 PreviousRawDatum &= 0x0000FFFF; 370 break; 371 } 372 } 373 374 375 /* 376 * Put together bits of the two raw data to make a complete 377 * field datum 378 */ 379 380 381 if (ObjDesc->Field.BitOffset != 0) 382 { 383 MergedDatum = 384 (PreviousRawDatum >> ObjDesc->Field.BitOffset) | 385 (ThisRawDatum << (BitGranularity - ObjDesc->Field.BitOffset)); 386 } 387 388 else 389 { 390 MergedDatum = PreviousRawDatum; 391 } 392 393 /* 394 * Prepare the merged datum for storing into the caller's 395 * buffer. It is possible to have a 32-bit buffer 396 * (ByteGranularity == 4), but a ObjDesc->Field.Length 397 * of 8 or 16, meaning that the upper bytes of merged data 398 * are undesired. This section fixes that. 399 */ 400 switch (ObjDesc->Field.Length) 401 { 402 case 8: 403 MergedDatum &= 0x000000FF; 404 break; 405 406 case 16: 407 MergedDatum &= 0x0000FFFF; 408 break; 409 } 410 411 /* 412 * Now store the datum in the caller's buffer, according to 413 * the data type 414 */ 415 switch (ByteGranularity) 416 { 417 case 1: 418 ((UINT8 *) Buffer) [ThisFieldDatumOffset] = (UINT8) MergedDatum; 419 break; 420 421 case 2: 422 MOVE_UNALIGNED16_TO_16 (&(((UINT16 *) Buffer) [ThisFieldDatumOffset]), &MergedDatum); 423 break; 424 425 case 4: 426 MOVE_UNALIGNED32_TO_32 (&(((UINT32 *) Buffer) [ThisFieldDatumOffset]), &MergedDatum); 427 break; 428 } 429 430 /* 431 * Save the most recent datum since it contains bits of 432 * the *next* field datum 433 */ 434 435 PreviousRawDatum = ThisRawDatum; 436 437 ThisFieldByteOffset += ByteGranularity; 438 ThisFieldDatumOffset++; 439 440 } /* while */ 441 } 442 443Cleanup: 444 445 return_ACPI_STATUS (Status); 446} 447 448 449/******************************************************************************* 450 * 451 * FUNCTION: AcpiAmlWriteFieldData 452 * 453 * PARAMETERS: *ObjDesc - Field to be set 454 * Value - Value to store 455 * FieldBitWidth - Field Width in bits (8, 16, or 32) 456 * 457 * RETURN: Status 458 * 459 * DESCRIPTION: Store the value into the given field 460 * 461 ******************************************************************************/ 462 463static ACPI_STATUS 464AcpiAmlWriteFieldData ( 465 ACPI_OPERAND_OBJECT *ObjDesc, 466 UINT32 FieldByteOffset, 467 UINT32 FieldBitWidth, 468 UINT32 Value) 469{ 470 ACPI_STATUS Status = AE_OK; 471 ACPI_OPERAND_OBJECT *RgnDesc = NULL; 472 ACPI_PHYSICAL_ADDRESS Address; 473 UINT32 FieldByteWidth; 474 475 476 FUNCTION_TRACE ("AmlWriteFieldData"); 477 478 479 /* ObjDesc is validated by callers */ 480 481 if (ObjDesc) 482 { 483 RgnDesc = ObjDesc->Field.Container; 484 } 485 486 FieldByteWidth = DIV_8 (FieldBitWidth); 487 Status = AcpiAmlSetupField (ObjDesc, RgnDesc, FieldBitWidth); 488 if (ACPI_FAILURE (Status)) 489 { 490 return_ACPI_STATUS (Status); 491 } 492 493 494 /* 495 * Set offset to next multiple of field width, 496 * add region base address and offset within the field 497 */ 498 Address = RgnDesc->Region.Address + 499 (ObjDesc->Field.Offset * FieldByteWidth) + 500 FieldByteOffset; 501 502 DEBUG_PRINT (TRACE_OPREGION, 503 ("AmlWriteField: Store %lx in Region %s(%X) at %p width %X\n", 504 Value, AcpiCmGetRegionName (RgnDesc->Region.SpaceId), 505 RgnDesc->Region.SpaceId, Address, 506 FieldBitWidth)); 507 508 /* Invoke the appropriate AddressSpace/OpRegion handler */ 509 510 Status = AcpiEvAddressSpaceDispatch (RgnDesc, ADDRESS_SPACE_WRITE, 511 Address, FieldBitWidth, &Value); 512 513 if (Status == AE_NOT_IMPLEMENTED) 514 { 515 DEBUG_PRINT (ACPI_ERROR, 516 ("AmlWriteField: **** Region type %s(%X) not implemented\n", 517 AcpiCmGetRegionName (RgnDesc->Region.SpaceId), 518 RgnDesc->Region.SpaceId)); 519 } 520 521 else if (Status == AE_NOT_EXIST) 522 { 523 DEBUG_PRINT (ACPI_ERROR, 524 ("AmlWriteField: **** Region type %s(%X) does not have a handler\n", 525 AcpiCmGetRegionName (RgnDesc->Region.SpaceId), 526 RgnDesc->Region.SpaceId)); 527 } 528 529 return_ACPI_STATUS (Status); 530} 531 532 533/***************************************************************************** 534 * 535 * FUNCTION: AcpiAmlWriteFieldDataWithUpdateRule 536 * 537 * PARAMETERS: *ObjDesc - Field to be set 538 * Value - Value to store 539 * FieldBitWidth - Field Width in bits (8, 16, or 32) 540 * 541 * RETURN: Status 542 * 543 * DESCRIPTION: Apply the field update rule to a field write 544 * 545 ****************************************************************************/ 546 547static ACPI_STATUS 548AcpiAmlWriteFieldDataWithUpdateRule ( 549 ACPI_OPERAND_OBJECT *ObjDesc, 550 UINT32 Mask, 551 UINT32 FieldValue, 552 UINT32 ThisFieldByteOffset, 553 UINT32 BitGranularity) 554{ 555 ACPI_STATUS Status = AE_OK; 556 UINT32 MergedValue; 557 UINT32 CurrentValue; 558 559 560 /* Start with the new bits */ 561 562 MergedValue = FieldValue; 563 564 565 566 /* Decode the update rule */ 567 568 switch (ObjDesc->Field.UpdateRule) 569 { 570 571 case UPDATE_PRESERVE: 572 573 /* Check if update rule needs to be applied (not if mask is all ones) */ 574 575 /* The left shift drops the bits we want to ignore. */ 576 if ((~Mask << (sizeof(Mask)*8 - BitGranularity)) != 0) 577 { 578 /* 579 * Read the current contents of the byte/word/dword containing 580 * the field, and merge with the new field value. 581 */ 582 Status = AcpiAmlReadFieldData (ObjDesc, ThisFieldByteOffset, 583 BitGranularity, &CurrentValue); 584 MergedValue |= (CurrentValue & ~Mask); 585 } 586 break; 587 588 589 case UPDATE_WRITE_AS_ONES: 590 591 /* Set positions outside the field to all ones */ 592 593 MergedValue |= ~Mask; 594 break; 595 596 597 case UPDATE_WRITE_AS_ZEROS: 598 599 /* Set positions outside the field to all zeros */ 600 601 MergedValue &= Mask; 602 break; 603 604 605 default: 606 DEBUG_PRINT (ACPI_ERROR, 607 ("WriteFieldDataWithUpdateRule: Unknown UpdateRule setting: %x\n", 608 ObjDesc->Field.UpdateRule)); 609 Status = AE_AML_OPERAND_VALUE; 610 } 611 612 613 /* Write the merged value */ 614 615 if (ACPI_SUCCESS (Status)) 616 { 617 Status = AcpiAmlWriteFieldData (ObjDesc, ThisFieldByteOffset, 618 BitGranularity, MergedValue); 619 } 620 621 return (Status); 622} 623 624 625/***************************************************************************** 626 * 627 * FUNCTION: AcpiAmlWriteField 628 * 629 * PARAMETERS: *ObjDesc - Field to be set 630 * Value - Value to store 631 * FieldBitWidth - Field Width in bits (8, 16, or 32) 632 * 633 * RETURN: Status 634 * 635 * DESCRIPTION: Store the value into the given field 636 * 637 ****************************************************************************/ 638 639ACPI_STATUS 640AcpiAmlWriteField ( 641 ACPI_OPERAND_OBJECT *ObjDesc, 642 void *Buffer, 643 UINT32 BufferLength, 644 UINT32 ByteLength, 645 UINT32 DatumLength, 646 UINT32 BitGranularity, 647 UINT32 ByteGranularity) 648{ 649 ACPI_STATUS Status; 650 UINT32 ThisFieldByteOffset; 651 UINT32 ThisFieldDatumOffset; 652 UINT32 Mask; 653 UINT32 MergedDatum; 654 UINT32 PreviousRawDatum; 655 UINT32 ThisRawDatum; 656 UINT32 FieldValue; 657 UINT32 ValidFieldBits; 658 659 660 FUNCTION_TRACE ("AmlWriteField"); 661 662 663 /* 664 * Break the request into up to three parts: 665 * non-aligned part at start, aligned part in middle, non-aligned part 666 * at end --- Just like an I/O request --- 667 */ 668 669 ThisFieldByteOffset = 0; 670 ThisFieldDatumOffset= 0; 671 672 /* Get a datum */ 673 674 switch (ByteGranularity) 675 { 676 case 1: 677 PreviousRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset]; 678 break; 679 680 case 2: 681 MOVE_UNALIGNED16_TO_32 (&PreviousRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset])); 682 break; 683 684 case 4: 685 MOVE_UNALIGNED32_TO_32 (&PreviousRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset])); 686 break; 687 688 default: 689 DEBUG_PRINT (ACPI_ERROR, ("AmlWriteField: Invalid granularity: %x\n", 690 ByteGranularity)); 691 Status = AE_AML_OPERAND_VALUE; 692 goto Cleanup; 693 } 694 695 696 /* 697 * Write a partial field datum if field does not begin on a datum boundary 698 * 699 * Construct Mask with 1 bits where the field is, 0 bits elsewhere 700 * 701 * 1) Bits above the field 702 */ 703 704 Mask = (((UINT32)(-1)) << (UINT32)ObjDesc->Field.BitOffset); 705 706 /* 2) Only the bottom 5 bits are valid for a shift operation. */ 707 708 if ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) < 32) 709 { 710 /* Bits above the field */ 711 712 Mask &= (~(((UINT32)(-1)) << ((UINT32)ObjDesc->Field.BitOffset + 713 (UINT32)ObjDesc->FieldUnit.Length))); 714 } 715 716 /* 3) Shift and mask the value into the field position */ 717 718 FieldValue = (PreviousRawDatum << ObjDesc->Field.BitOffset) & Mask; 719 720 Status = AcpiAmlWriteFieldDataWithUpdateRule (ObjDesc, Mask, FieldValue, 721 ThisFieldByteOffset, 722 BitGranularity); 723 if (ACPI_FAILURE (Status)) 724 { 725 goto Cleanup; 726 } 727 728 729 /* If the field fits within one datum, we are done. */ 730 731 if ((DatumLength == 1) && 732 ((ObjDesc->Field.BitOffset + ObjDesc->FieldUnit.Length) <= 733 (UINT16) BitGranularity)) 734 { 735 goto Cleanup; 736 } 737 738 /* 739 * We don't need to worry about the update rule for these data, because 740 * all of the bits are part of the field. 741 * 742 * Can't write the last datum, however, because it might contain bits that 743 * are not part of the field -- the update rule must be applied. 744 */ 745 746 while (ThisFieldDatumOffset < (DatumLength - 1)) 747 { 748 ThisFieldDatumOffset++; 749 750 /* Get the next raw datum, it contains bits of the current field datum... */ 751 752 switch (ByteGranularity) 753 { 754 case 1: 755 ThisRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset]; 756 break; 757 758 case 2: 759 MOVE_UNALIGNED16_TO_32 (&ThisRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset])); 760 break; 761 762 case 4: 763 MOVE_UNALIGNED32_TO_32 (&ThisRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset])); 764 break; 765 766 default: 767 DEBUG_PRINT (ACPI_ERROR, ("AmlWriteField: Invalid Byte Granularity: %x\n", 768 ByteGranularity)); 769 Status = AE_AML_OPERAND_VALUE; 770 goto Cleanup; 771 } 772 773 /* 774 * Put together bits of the two raw data to make a complete field 775 * datum 776 */ 777 778 if (ObjDesc->Field.BitOffset != 0) 779 { 780 MergedDatum = 781 (PreviousRawDatum >> (BitGranularity - ObjDesc->Field.BitOffset)) | 782 (ThisRawDatum << ObjDesc->Field.BitOffset); 783 } 784 785 else 786 { 787 MergedDatum = ThisRawDatum; 788 } 789 790 /* Now write the completed datum */ 791 792 793 Status = AcpiAmlWriteFieldData (ObjDesc, 794 ThisFieldByteOffset + ByteGranularity, 795 BitGranularity, MergedDatum); 796 if (ACPI_FAILURE (Status)) 797 { 798 goto Cleanup; 799 } 800 801 802 /* 803 * Save the most recent datum since it contains bits of 804 * the *next* field datum 805 */ 806 807 PreviousRawDatum = ThisRawDatum; 808 809 ThisFieldByteOffset += ByteGranularity; 810 811 } /* while */ 812 813 814 /* Write a partial field datum if field does not end on a datum boundary */ 815 816 if ((ObjDesc->FieldUnit.Length + ObjDesc->FieldUnit.BitOffset) % 817 BitGranularity) 818 { 819 switch (ByteGranularity) 820 { 821 case 1: 822 ThisRawDatum = ((UINT8 *) Buffer) [ThisFieldDatumOffset]; 823 break; 824 825 case 2: 826 MOVE_UNALIGNED16_TO_32 (&ThisRawDatum, &(((UINT16 *) Buffer) [ThisFieldDatumOffset])); 827 break; 828 829 case 4: 830 MOVE_UNALIGNED32_TO_32 (&ThisRawDatum, &(((UINT32 *) Buffer) [ThisFieldDatumOffset])); 831 break; 832 } 833 834 /* Construct Mask with 1 bits where the field is, 0 bits elsewhere */ 835 836 ValidFieldBits = ((ObjDesc->FieldUnit.Length % BitGranularity) + 837 ObjDesc->Field.BitOffset); 838 839 Mask = (((UINT32) 1 << ValidFieldBits) - (UINT32) 1); 840 841 /* Shift and mask the value into the field position */ 842 843 FieldValue = (PreviousRawDatum >> 844 (BitGranularity - ObjDesc->Field.BitOffset)) & Mask; 845 846 Status = AcpiAmlWriteFieldDataWithUpdateRule (ObjDesc, Mask, FieldValue, 847 ThisFieldByteOffset + ByteGranularity, 848 BitGranularity); 849 if (ACPI_FAILURE (Status)) 850 { 851 goto Cleanup; 852 } 853 } 854 855 856Cleanup: 857 858 return_ACPI_STATUS (Status); 859} 860 861 862