1/****************************************************************************** 2 * 3 * Module Name: exfldio - Aml Field I/O 4 * $Revision: 1.1.1.1 $ 5 * 6 *****************************************************************************/ 7 8/* 9 * Copyright (C) 2000, 2001 R. Byron Moore 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation; either version 2 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program; if not, write to the Free Software 23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 24 */ 25 26 27#include "acpi.h" 28#include "acinterp.h" 29#include "amlcode.h" 30#include "acnamesp.h" 31#include "achware.h" 32#include "acevents.h" 33#include "acdispat.h" 34 35 36#define _COMPONENT ACPI_EXECUTER 37 MODULE_NAME ("exfldio") 38 39 40/******************************************************************************* 41 * 42 * FUNCTION: Acpi_ex_setup_field 43 * 44 * PARAMETERS: *Obj_desc - Field to be read or written 45 * Field_datum_byte_offset - Current offset into the field 46 * 47 * RETURN: Status 48 * 49 * DESCRIPTION: Common processing for Acpi_ex_extract_from_field and 50 * Acpi_ex_insert_into_field 51 * 52 ******************************************************************************/ 53 54acpi_status 55acpi_ex_setup_field ( 56 acpi_operand_object *obj_desc, 57 u32 field_datum_byte_offset) 58{ 59 acpi_status status = AE_OK; 60 acpi_operand_object *rgn_desc; 61 62 63 FUNCTION_TRACE_U32 ("Ex_setup_field", field_datum_byte_offset); 64 65 66 rgn_desc = obj_desc->common_field.region_obj; 67 68 if (ACPI_TYPE_REGION != rgn_desc->common.type) { 69 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %x %s\n", 70 rgn_desc->common.type, acpi_ut_get_type_name (rgn_desc->common.type))); 71 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 72 } 73 74 /* 75 * If the Region Address and Length have not been previously evaluated, 76 * evaluate them now and save the results. 77 */ 78 if (!(rgn_desc->region.flags & AOPOBJ_DATA_VALID)) { 79 80 status = acpi_ds_get_region_arguments (rgn_desc); 81 if (ACPI_FAILURE (status)) { 82 return_ACPI_STATUS (status); 83 } 84 } 85 86 /* 87 * Validate the request. The entire request from the byte offset for a 88 * length of one field datum (access width) must fit within the region. 89 * (Region length is specified in bytes) 90 */ 91 if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset + 92 field_datum_byte_offset + 93 obj_desc->common_field.access_byte_width)) { 94 if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) { 95 /* 96 * This is the case where the Access_type (Acc_word, etc.) is wider 97 * than the region itself. For example, a region of length one 98 * byte, and a field with Dword access specified. 99 */ 100 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 101 "Field access width (%d bytes) too large for region size (%X)\n", 102 obj_desc->common_field.access_byte_width, rgn_desc->region.length)); 103 } 104 105 /* 106 * Offset rounded up to next multiple of field width 107 * exceeds region length, indicate an error 108 */ 109 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 110 "Field base+offset+width %X+%X+%X exceeds region size (%X bytes) field=%p region=%p\n", 111 obj_desc->common_field.base_byte_offset, field_datum_byte_offset, 112 obj_desc->common_field.access_byte_width, 113 rgn_desc->region.length, obj_desc, rgn_desc)); 114 115 return_ACPI_STATUS (AE_AML_REGION_LIMIT); 116 } 117 118 return_ACPI_STATUS (AE_OK); 119} 120 121 122/******************************************************************************* 123 * 124 * FUNCTION: Acpi_ex_read_field_datum 125 * 126 * PARAMETERS: *Obj_desc - Field to be read 127 * *Value - Where to store value (must be 32 bits) 128 * 129 * RETURN: Status 130 * 131 * DESCRIPTION: Retrieve the value of the given field 132 * 133 ******************************************************************************/ 134 135acpi_status 136acpi_ex_read_field_datum ( 137 acpi_operand_object *obj_desc, 138 u32 field_datum_byte_offset, 139 u32 *value) 140{ 141 acpi_status status; 142 acpi_operand_object *rgn_desc; 143 ACPI_PHYSICAL_ADDRESS address; 144 u32 local_value; 145 146 147 FUNCTION_TRACE_U32 ("Ex_read_field_datum", field_datum_byte_offset); 148 149 150 if (!value) { 151 local_value = 0; 152 value = &local_value; /* support reads without saving value */ 153 } 154 155 /* Clear the entire return buffer first, [Very Important!] */ 156 157 *value = 0; 158 159 /* 160 * Buffer_fields - Read from a Buffer 161 * Other Fields - Read from a Operation Region. 162 */ 163 switch (obj_desc->common.type) { 164 case ACPI_TYPE_BUFFER_FIELD: 165 166 /* 167 * For Buffer_fields, we only need to copy the data from the 168 * source buffer. Length is the field width in bytes. 169 */ 170 MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer 171 + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, 172 obj_desc->common_field.access_byte_width); 173 status = AE_OK; 174 break; 175 176 177 case INTERNAL_TYPE_REGION_FIELD: 178 case INTERNAL_TYPE_BANK_FIELD: 179 180 /* 181 * For other fields, we need to go through an Operation Region 182 * (Only types that will get here are Region_fields and Bank_fields) 183 */ 184 status = acpi_ex_setup_field (obj_desc, field_datum_byte_offset); 185 if (ACPI_FAILURE (status)) { 186 return_ACPI_STATUS (status); 187 } 188 189 /* 190 * The physical address of this field datum is: 191 * 192 * 1) The base of the region, plus 193 * 2) The base offset of the field, plus 194 * 3) The current offset into the field 195 */ 196 rgn_desc = obj_desc->common_field.region_obj; 197 address = rgn_desc->region.address + obj_desc->common_field.base_byte_offset + 198 field_datum_byte_offset; 199 200 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Region %s(%X) width %X base:off %X:%X at %8.8X%8.8X\n", 201 acpi_ut_get_region_name (rgn_desc->region.space_id), 202 rgn_desc->region.space_id, obj_desc->common_field.access_bit_width, 203 obj_desc->common_field.base_byte_offset, field_datum_byte_offset, 204 HIDWORD(address), LODWORD(address))); 205 206 /* Invoke the appropriate Address_space/Op_region handler */ 207 208 status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_READ_ADR_SPACE, 209 address, obj_desc->common_field.access_bit_width, value); 210 if (status == AE_NOT_IMPLEMENTED) { 211 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) not implemented\n", 212 acpi_ut_get_region_name (rgn_desc->region.space_id), 213 rgn_desc->region.space_id)); 214 } 215 216 else if (status == AE_NOT_EXIST) { 217 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %s(%X) has no handler\n", 218 acpi_ut_get_region_name (rgn_desc->region.space_id), 219 rgn_desc->region.space_id)); 220 } 221 break; 222 223 224 default: 225 226 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, wrong source type - %s\n", 227 obj_desc, acpi_ut_get_type_name (obj_desc->common.type))); 228 status = AE_AML_INTERNAL; 229 break; 230 } 231 232 233 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Returned value=%08X \n", *value)); 234 235 return_ACPI_STATUS (status); 236} 237 238 239/******************************************************************************* 240 * 241 * FUNCTION: Acpi_ex_get_buffer_datum 242 * 243 * PARAMETERS: Merged_datum - Value to store 244 * Buffer - Receiving buffer 245 * Byte_granularity - 1/2/4 Granularity of the field 246 * (aka Datum Size) 247 * Offset - Datum offset into the buffer 248 * 249 * RETURN: none 250 * 251 * DESCRIPTION: Store the merged datum to the buffer according to the 252 * byte granularity 253 * 254 ******************************************************************************/ 255 256static void 257acpi_ex_get_buffer_datum( 258 u32 *datum, 259 void *buffer, 260 u32 byte_granularity, 261 u32 offset) 262{ 263 264 FUNCTION_ENTRY (); 265 266 267 switch (byte_granularity) { 268 case ACPI_FIELD_BYTE_GRANULARITY: 269 *datum = ((u8 *) buffer) [offset]; 270 break; 271 272 case ACPI_FIELD_WORD_GRANULARITY: 273 MOVE_UNALIGNED16_TO_32 (datum, &(((u16 *) buffer) [offset])); 274 break; 275 276 case ACPI_FIELD_DWORD_GRANULARITY: 277 MOVE_UNALIGNED32_TO_32 (datum, &(((u32 *) buffer) [offset])); 278 break; 279 } 280} 281 282 283/******************************************************************************* 284 * 285 * FUNCTION: Acpi_ex_set_buffer_datum 286 * 287 * PARAMETERS: Merged_datum - Value to store 288 * Buffer - Receiving buffer 289 * Byte_granularity - 1/2/4 Granularity of the field 290 * (aka Datum Size) 291 * Offset - Datum offset into the buffer 292 * 293 * RETURN: none 294 * 295 * DESCRIPTION: Store the merged datum to the buffer according to the 296 * byte granularity 297 * 298 ******************************************************************************/ 299 300static void 301acpi_ex_set_buffer_datum ( 302 u32 merged_datum, 303 void *buffer, 304 u32 byte_granularity, 305 u32 offset) 306{ 307 308 FUNCTION_ENTRY (); 309 310 311 switch (byte_granularity) { 312 case ACPI_FIELD_BYTE_GRANULARITY: 313 ((u8 *) buffer) [offset] = (u8) merged_datum; 314 break; 315 316 case ACPI_FIELD_WORD_GRANULARITY: 317 MOVE_UNALIGNED16_TO_16 (&(((u16 *) buffer)[offset]), &merged_datum); 318 break; 319 320 case ACPI_FIELD_DWORD_GRANULARITY: 321 MOVE_UNALIGNED32_TO_32 (&(((u32 *) buffer)[offset]), &merged_datum); 322 break; 323 } 324} 325 326 327/******************************************************************************* 328 * 329 * FUNCTION: Acpi_ex_extract_from_field 330 * 331 * PARAMETERS: *Obj_desc - Field to be read 332 * *Value - Where to store value 333 * 334 * RETURN: Status 335 * 336 * DESCRIPTION: Retrieve the value of the given field 337 * 338 ******************************************************************************/ 339 340acpi_status 341acpi_ex_extract_from_field ( 342 acpi_operand_object *obj_desc, 343 void *buffer, 344 u32 buffer_length) 345{ 346 acpi_status status; 347 u32 field_datum_byte_offset; 348 u32 datum_offset; 349 u32 previous_raw_datum; 350 u32 this_raw_datum = 0; 351 u32 merged_datum = 0; 352 u32 byte_field_length; 353 u32 datum_count; 354 355 356 FUNCTION_TRACE ("Ex_extract_from_field"); 357 358 359 /* 360 * The field must fit within the caller's buffer 361 */ 362 byte_field_length = ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); 363 if (byte_field_length > buffer_length) { 364 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Field size %X (bytes) too large for buffer (%X)\n", 365 byte_field_length, buffer_length)); 366 367 return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 368 } 369 370 /* Convert field byte count to datum count, round up if necessary */ 371 372 datum_count = ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); 373 374 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, 375 "Byte_len=%x, Datum_len=%x, Bit_gran=%x, Byte_gran=%x\n", 376 byte_field_length, datum_count, obj_desc->common_field.access_bit_width, 377 obj_desc->common_field.access_byte_width)); 378 379 /* 380 * Clear the caller's buffer (the whole buffer length as given) 381 * This is very important, especially in the cases where a byte is read, 382 * but the buffer is really a u32 (4 bytes). 383 */ 384 MEMSET (buffer, 0, buffer_length); 385 386 /* Read the first raw datum to prime the loop */ 387 388 field_datum_byte_offset = 0; 389 datum_offset= 0; 390 391 status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, &previous_raw_datum); 392 if (ACPI_FAILURE (status)) { 393 return_ACPI_STATUS (status); 394 } 395 396 397 /* We might actually be done if the request fits in one datum */ 398 399 if ((datum_count == 1) && 400 (obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM)) { 401 /* 1) Shift the valid data bits down to start at bit 0 */ 402 403 merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); 404 405 /* 2) Mask off any upper unused bits (bits not part of the field) */ 406 407 if (obj_desc->common_field.end_buffer_valid_bits) { 408 merged_datum &= MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); 409 } 410 411 /* Store the datum to the caller buffer */ 412 413 acpi_ex_set_buffer_datum (merged_datum, buffer, obj_desc->common_field.access_byte_width, 414 datum_offset); 415 416 return_ACPI_STATUS (AE_OK); 417 } 418 419 420 /* We need to get more raw data to complete one or more field data */ 421 422 while (datum_offset < datum_count) { 423 field_datum_byte_offset += obj_desc->common_field.access_byte_width; 424 425 /* 426 * If the field is aligned on a byte boundary, we don't want 427 * to perform a final read, since this would potentially read 428 * past the end of the region. 429 * 430 * TBD: [Investigate] It may make more sense to just split the aligned 431 * and non-aligned cases since the aligned case is so very simple, 432 */ 433 if ((obj_desc->common_field.start_field_bit_offset != 0) || 434 ((obj_desc->common_field.start_field_bit_offset == 0) && 435 (datum_offset < (datum_count -1)))) { 436 /* 437 * Get the next raw datum, it contains some or all bits 438 * of the current field datum 439 */ 440 status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, &this_raw_datum); 441 if (ACPI_FAILURE (status)) { 442 return_ACPI_STATUS (status); 443 } 444 } 445 446 /* 447 * Create the (possibly) merged datum to be stored to the caller buffer 448 */ 449 if (obj_desc->common_field.start_field_bit_offset == 0) { 450 /* Field is not skewed and we can just copy the datum */ 451 452 merged_datum = previous_raw_datum; 453 } 454 455 else { 456 /* 457 * Put together the appropriate bits of the two raw data to make a 458 * single complete field datum 459 * 460 * 1) Normalize the first datum down to bit 0 461 */ 462 merged_datum = (previous_raw_datum >> obj_desc->common_field.start_field_bit_offset); 463 464 /* 2) Insert the second datum "above" the first datum */ 465 466 merged_datum |= (this_raw_datum << obj_desc->common_field.datum_valid_bits); 467 468 if ((datum_offset >= (datum_count -1))) { 469 /* 470 * This is the last iteration of the loop. We need to clear 471 * any unused bits (bits that are not part of this field) that 472 * came from the last raw datum before we store the final 473 * merged datum into the caller buffer. 474 */ 475 if (obj_desc->common_field.end_buffer_valid_bits) { 476 merged_datum &= 477 MASK_BITS_ABOVE (obj_desc->common_field.end_buffer_valid_bits); 478 } 479 } 480 } 481 482 /* 483 * Store the merged field datum in the caller's buffer, according to 484 * the granularity of the field (size of each datum). 485 */ 486 acpi_ex_set_buffer_datum (merged_datum, buffer, obj_desc->common_field.access_byte_width, 487 datum_offset); 488 489 /* 490 * Save the raw datum that was just acquired since it may contain bits 491 * of the *next* field datum. Update offsets 492 */ 493 previous_raw_datum = this_raw_datum; 494 datum_offset++; 495 } 496 497 return_ACPI_STATUS (AE_OK); 498} 499 500 501/******************************************************************************* 502 * 503 * FUNCTION: Acpi_ex_write_field_datum 504 * 505 * PARAMETERS: *Obj_desc - Field to be set 506 * Value - Value to store 507 * 508 * RETURN: Status 509 * 510 * DESCRIPTION: Store the value into the given field 511 * 512 ******************************************************************************/ 513 514static acpi_status 515acpi_ex_write_field_datum ( 516 acpi_operand_object *obj_desc, 517 u32 field_datum_byte_offset, 518 u32 value) 519{ 520 acpi_status status = AE_OK; 521 acpi_operand_object *rgn_desc = NULL; 522 ACPI_PHYSICAL_ADDRESS address; 523 524 525 FUNCTION_TRACE_U32 ("Ex_write_field_datum", field_datum_byte_offset); 526 527 528 /* 529 * Buffer_fields - Read from a Buffer 530 * Other Fields - Read from a Operation Region. 531 */ 532 switch (obj_desc->common.type) { 533 case ACPI_TYPE_BUFFER_FIELD: 534 535 /* 536 * For Buffer_fields, we only need to copy the data to the 537 * target buffer. Length is the field width in bytes. 538 */ 539 MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer 540 + obj_desc->buffer_field.base_byte_offset + field_datum_byte_offset, 541 &value, obj_desc->common_field.access_byte_width); 542 status = AE_OK; 543 break; 544 545 546 case INTERNAL_TYPE_REGION_FIELD: 547 case INTERNAL_TYPE_BANK_FIELD: 548 549 /* 550 * For other fields, we need to go through an Operation Region 551 * (Only types that will get here are Region_fields and Bank_fields) 552 */ 553 status = acpi_ex_setup_field (obj_desc, field_datum_byte_offset); 554 if (ACPI_FAILURE (status)) { 555 return_ACPI_STATUS (status); 556 } 557 558 /* 559 * The physical address of this field datum is: 560 * 561 * 1) The base of the region, plus 562 * 2) The base offset of the field, plus 563 * 3) The current offset into the field 564 */ 565 rgn_desc = obj_desc->common_field.region_obj; 566 address = rgn_desc->region.address + 567 obj_desc->common_field.base_byte_offset + 568 field_datum_byte_offset; 569 570 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 571 "Store %X in Region %s(%X) at %8.8X%8.8X width %X\n", 572 value, acpi_ut_get_region_name (rgn_desc->region.space_id), 573 rgn_desc->region.space_id, HIDWORD(address), LODWORD(address), 574 obj_desc->common_field.access_bit_width)); 575 576 /* Invoke the appropriate Address_space/Op_region handler */ 577 578 status = acpi_ev_address_space_dispatch (rgn_desc, ACPI_WRITE_ADR_SPACE, 579 address, obj_desc->common_field.access_bit_width, &value); 580 581 if (status == AE_NOT_IMPLEMENTED) { 582 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 583 "**** Region type %s(%X) not implemented\n", 584 acpi_ut_get_region_name (rgn_desc->region.space_id), 585 rgn_desc->region.space_id)); 586 } 587 588 else if (status == AE_NOT_EXIST) { 589 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 590 "**** Region type %s(%X) does not have a handler\n", 591 acpi_ut_get_region_name (rgn_desc->region.space_id), 592 rgn_desc->region.space_id)); 593 } 594 595 break; 596 597 598 default: 599 600 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p, wrong source type - %s\n", 601 obj_desc, acpi_ut_get_type_name (obj_desc->common.type))); 602 status = AE_AML_INTERNAL; 603 break; 604 } 605 606 607 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value written=%08X \n", value)); 608 return_ACPI_STATUS (status); 609} 610 611 612/******************************************************************************* 613 * 614 * FUNCTION: Acpi_ex_write_field_datum_with_update_rule 615 * 616 * PARAMETERS: *Obj_desc - Field to be set 617 * Value - Value to store 618 * 619 * RETURN: Status 620 * 621 * DESCRIPTION: Apply the field update rule to a field write 622 * 623 ******************************************************************************/ 624 625static acpi_status 626acpi_ex_write_field_datum_with_update_rule ( 627 acpi_operand_object *obj_desc, 628 u32 mask, 629 u32 field_value, 630 u32 field_datum_byte_offset) 631{ 632 acpi_status status = AE_OK; 633 u32 merged_value; 634 u32 current_value; 635 636 637 FUNCTION_TRACE ("Ex_write_field_datum_with_update_rule"); 638 639 640 /* Start with the new bits */ 641 642 merged_value = field_value; 643 644 /* If the mask is all ones, we don't need to worry about the update rule */ 645 646 if (mask != ACPI_UINT32_MAX) { 647 /* Decode the update rule */ 648 649 switch (obj_desc->common_field.update_rule) { 650 case UPDATE_PRESERVE: 651 /* 652 * Check if update rule needs to be applied (not if mask is all 653 * ones) The left shift drops the bits we want to ignore. 654 */ 655 if ((~mask << (sizeof (mask) * 8 - 656 obj_desc->common_field.access_bit_width)) != 0) { 657 /* 658 * Read the current contents of the byte/word/dword containing 659 * the field, and merge with the new field value. 660 */ 661 status = acpi_ex_read_field_datum (obj_desc, field_datum_byte_offset, 662 ¤t_value); 663 merged_value |= (current_value & ~mask); 664 } 665 break; 666 667 668 case UPDATE_WRITE_AS_ONES: 669 670 /* Set positions outside the field to all ones */ 671 672 merged_value |= ~mask; 673 break; 674 675 676 case UPDATE_WRITE_AS_ZEROS: 677 678 /* Set positions outside the field to all zeros */ 679 680 merged_value &= mask; 681 break; 682 683 684 default: 685 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 686 "Write_with_update_rule: Unknown Update_rule setting: %x\n", 687 obj_desc->common_field.update_rule)); 688 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 689 break; 690 } 691 } 692 693 694 /* Write the merged value */ 695 696 status = acpi_ex_write_field_datum (obj_desc, field_datum_byte_offset, 697 merged_value); 698 699 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Mask %X Datum_offset %X Value %X, Merged_value %X\n", 700 mask, field_datum_byte_offset, field_value, merged_value)); 701 702 return_ACPI_STATUS (status); 703} 704 705 706/******************************************************************************* 707 * 708 * FUNCTION: Acpi_ex_insert_into_field 709 * 710 * PARAMETERS: *Obj_desc - Field to be set 711 * Buffer - Value to store 712 * 713 * RETURN: Status 714 * 715 * DESCRIPTION: Store the value into the given field 716 * 717 ******************************************************************************/ 718 719acpi_status 720acpi_ex_insert_into_field ( 721 acpi_operand_object *obj_desc, 722 void *buffer, 723 u32 buffer_length) 724{ 725 acpi_status status; 726 u32 field_datum_byte_offset; 727 u32 datum_offset; 728 u32 mask; 729 u32 merged_datum; 730 u32 previous_raw_datum; 731 u32 this_raw_datum; 732 u32 byte_field_length; 733 u32 datum_count; 734 735 736 FUNCTION_TRACE ("Ex_insert_into_field"); 737 738 739 /* 740 * Incoming buffer must be at least as long as the field, we do not 741 * allow "partial" field writes. We do not care if the buffer is 742 * larger than the field, this typically happens when an integer is 743 * written to a field that is actually smaller than an integer. 744 */ 745 byte_field_length = ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length); 746 if (buffer_length < byte_field_length) { 747 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Buffer length %X too small for field %X\n", 748 buffer_length, byte_field_length)); 749 750 /* TBD: Need a better error code */ 751 752 return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 753 } 754 755 /* Convert byte count to datum count, round up if necessary */ 756 757 datum_count = ROUND_UP_TO (byte_field_length, obj_desc->common_field.access_byte_width); 758 759 ACPI_DEBUG_PRINT ((ACPI_DB_INFO, 760 "Byte_len=%x, Datum_len=%x, Bit_gran=%x, Byte_gran=%x\n", 761 byte_field_length, datum_count, obj_desc->common_field.access_bit_width, 762 obj_desc->common_field.access_byte_width)); 763 764 /* 765 * Break the request into up to three parts (similar to an I/O request): 766 * 1) non-aligned part at start 767 * 2) aligned part in middle 768 * 3) non-aligned part at the end 769 */ 770 field_datum_byte_offset = 0; 771 datum_offset= 0; 772 773 /* Get a single datum from the caller's buffer */ 774 775 acpi_ex_get_buffer_datum (&previous_raw_datum, buffer, 776 obj_desc->common_field.access_byte_width, datum_offset); 777 778 /* 779 * Part1: 780 * Write a partial field datum if field does not begin on a datum boundary 781 * Note: The code in this section also handles the aligned case 782 * 783 * Construct Mask with 1 bits where the field is, 0 bits elsewhere 784 * (Only the bottom 5 bits of Bit_length are valid for a shift operation) 785 * 786 * Mask off bits that are "below" the field (if any) 787 */ 788 mask = MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset); 789 790 /* If the field fits in one datum, may need to mask upper bits */ 791 792 if ((obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM) && 793 obj_desc->common_field.end_field_valid_bits) { 794 /* There are bits above the field, mask them off also */ 795 796 mask &= MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); 797 } 798 799 /* Shift and mask the value into the field position */ 800 801 merged_datum = (previous_raw_datum << obj_desc->common_field.start_field_bit_offset); 802 merged_datum &= mask; 803 804 /* Apply the update rule (if necessary) and write the datum to the field */ 805 806 status = acpi_ex_write_field_datum_with_update_rule (obj_desc, mask, merged_datum, 807 field_datum_byte_offset); 808 if (ACPI_FAILURE (status)) { 809 return_ACPI_STATUS (status); 810 } 811 812 /* If the entire field fits within one datum, we are done. */ 813 814 if ((datum_count == 1) && 815 (obj_desc->common_field.access_flags & AFIELD_SINGLE_DATUM)) { 816 return_ACPI_STATUS (AE_OK); 817 } 818 819 /* 820 * Part2: 821 * Write the aligned data. 822 * 823 * We don't need to worry about the update rule for these data, because 824 * all of the bits in each datum are part of the field. 825 * 826 * The last datum must be special cased because it might contain bits 827 * that are not part of the field -- therefore the "update rule" must be 828 * applied in Part3 below. 829 */ 830 while (datum_offset < datum_count) { 831 datum_offset++; 832 field_datum_byte_offset += obj_desc->common_field.access_byte_width; 833 834 /* 835 * Get the next raw buffer datum. It may contain bits of the previous 836 * field datum 837 */ 838 acpi_ex_get_buffer_datum (&this_raw_datum, buffer, 839 obj_desc->common_field.access_byte_width, datum_offset); 840 841 /* Create the field datum based on the field alignment */ 842 843 if (obj_desc->common_field.start_field_bit_offset != 0) { 844 /* 845 * Put together appropriate bits of the two raw buffer data to make 846 * a single complete field datum 847 */ 848 merged_datum = 849 (previous_raw_datum >> obj_desc->common_field.datum_valid_bits) | 850 (this_raw_datum << obj_desc->common_field.start_field_bit_offset); 851 } 852 853 else { 854 /* Field began aligned on datum boundary */ 855 856 merged_datum = this_raw_datum; 857 } 858 859 /* 860 * Special handling for the last datum if the field does NOT end on 861 * a datum boundary. Update Rule must be applied to the bits outside 862 * the field. 863 */ 864 if (datum_offset == datum_count) { 865 /* 866 * If there are dangling non-aligned bits, perform one more merged write 867 * Else - field is aligned at the end, no need for any more writes 868 */ 869 if (obj_desc->common_field.end_field_valid_bits) { 870 /* 871 * Part3: 872 * This is the last datum and the field does not end on a datum boundary. 873 * Build the partial datum and write with the update rule. 874 * 875 * Mask off the unused bits above (after) the end-of-field 876 */ 877 mask = MASK_BITS_ABOVE (obj_desc->common_field.end_field_valid_bits); 878 merged_datum &= mask; 879 880 /* Write the last datum with the update rule */ 881 882 status = acpi_ex_write_field_datum_with_update_rule (obj_desc, mask, 883 merged_datum, field_datum_byte_offset); 884 if (ACPI_FAILURE (status)) { 885 return_ACPI_STATUS (status); 886 } 887 } 888 } 889 890 else { 891 /* Normal case -- write the completed datum */ 892 893 status = acpi_ex_write_field_datum (obj_desc, 894 field_datum_byte_offset, merged_datum); 895 if (ACPI_FAILURE (status)) { 896 return_ACPI_STATUS (status); 897 } 898 } 899 900 /* 901 * Save the most recent datum since it may contain bits of the *next* 902 * field datum. Update current byte offset. 903 */ 904 previous_raw_datum = this_raw_datum; 905 } 906 907 return_ACPI_STATUS (status); 908} 909 910 911