1 /******************************************************************************* 2 * 3 * Module Name: hwregs - Read/write access functions for the various ACPI 4 * control and status registers. 5 * 6 ******************************************************************************/ 7 8 /* 9 * Copyright (C) 2000 - 2014, Intel Corp. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions, and the following disclaimer, 17 * without modification. 18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19 * substantially similar to the "NO WARRANTY" disclaimer below 20 * ("Disclaimer") and any redistribution must be conditioned upon 21 * including a substantially similar Disclaimer requirement for further 22 * binary redistribution. 23 * 3. Neither the names of the above-listed copyright holders nor the names 24 * of any contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * Alternatively, this software may be distributed under the terms of the 28 * GNU General Public License ("GPL") version 2 as published by the Free 29 * Software Foundation. 30 * 31 * NO WARRANTY 32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42 * POSSIBILITY OF SUCH DAMAGES. 43 */ 44 45 #define __HWREGS_C__ 46 47 #include <contrib/dev/acpica/include/acpi.h> 48 #include <contrib/dev/acpica/include/accommon.h> 49 #include <contrib/dev/acpica/include/acevents.h> 50 51 #define _COMPONENT ACPI_HARDWARE 52 ACPI_MODULE_NAME ("hwregs") 53 54 55 #if (!ACPI_REDUCED_HARDWARE) 56 57 /* Local Prototypes */ 58 59 static ACPI_STATUS 60 AcpiHwReadMultiple ( 61 UINT32 *Value, 62 ACPI_GENERIC_ADDRESS *RegisterA, 63 ACPI_GENERIC_ADDRESS *RegisterB); 64 65 static ACPI_STATUS 66 AcpiHwWriteMultiple ( 67 UINT32 Value, 68 ACPI_GENERIC_ADDRESS *RegisterA, 69 ACPI_GENERIC_ADDRESS *RegisterB); 70 71 #endif /* !ACPI_REDUCED_HARDWARE */ 72 73 /****************************************************************************** 74 * 75 * FUNCTION: AcpiHwValidateRegister 76 * 77 * PARAMETERS: Reg - GAS register structure 78 * MaxBitWidth - Max BitWidth supported (32 or 64) 79 * Address - Pointer to where the gas->address 80 * is returned 81 * 82 * RETURN: Status 83 * 84 * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS 85 * pointer, Address, SpaceId, BitWidth, and BitOffset. 86 * 87 ******************************************************************************/ 88 89 ACPI_STATUS 90 AcpiHwValidateRegister ( 91 ACPI_GENERIC_ADDRESS *Reg, 92 UINT8 MaxBitWidth, 93 UINT64 *Address) 94 { 95 96 /* Must have a valid pointer to a GAS structure */ 97 98 if (!Reg) 99 { 100 return (AE_BAD_PARAMETER); 101 } 102 103 /* 104 * Copy the target address. This handles possible alignment issues. 105 * Address must not be null. A null address also indicates an optional 106 * ACPI register that is not supported, so no error message. 107 */ 108 ACPI_MOVE_64_TO_64 (Address, &Reg->Address); 109 if (!(*Address)) 110 { 111 return (AE_BAD_ADDRESS); 112 } 113 114 /* Validate the SpaceID */ 115 116 if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 117 (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) 118 { 119 ACPI_ERROR ((AE_INFO, 120 "Unsupported address space: 0x%X", Reg->SpaceId)); 121 return (AE_SUPPORT); 122 } 123 124 /* Validate the BitWidth */ 125 126 if ((Reg->BitWidth != 8) && 127 (Reg->BitWidth != 16) && 128 (Reg->BitWidth != 32) && 129 (Reg->BitWidth != MaxBitWidth)) 130 { 131 ACPI_ERROR ((AE_INFO, 132 "Unsupported register bit width: 0x%X", Reg->BitWidth)); 133 return (AE_SUPPORT); 134 } 135 136 /* Validate the BitOffset. Just a warning for now. */ 137 138 if (Reg->BitOffset != 0) 139 { 140 ACPI_WARNING ((AE_INFO, 141 "Unsupported register bit offset: 0x%X", Reg->BitOffset)); 142 } 143 144 return (AE_OK); 145 } 146 147 148 /****************************************************************************** 149 * 150 * FUNCTION: AcpiHwRead 151 * 152 * PARAMETERS: Value - Where the value is returned 153 * Reg - GAS register structure 154 * 155 * RETURN: Status 156 * 157 * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max 158 * version of AcpiRead, used internally since the overhead of 159 * 64-bit values is not needed. 160 * 161 * LIMITATIONS: <These limitations also apply to AcpiHwWrite> 162 * BitWidth must be exactly 8, 16, or 32. 163 * SpaceID must be SystemMemory or SystemIO. 164 * BitOffset and AccessWidth are currently ignored, as there has 165 * not been a need to implement these. 166 * 167 ******************************************************************************/ 168 169 ACPI_STATUS 170 AcpiHwRead ( 171 UINT32 *Value, 172 ACPI_GENERIC_ADDRESS *Reg) 173 { 174 UINT64 Address; 175 UINT64 Value64; 176 ACPI_STATUS Status; 177 178 179 ACPI_FUNCTION_NAME (HwRead); 180 181 182 /* Validate contents of the GAS register */ 183 184 Status = AcpiHwValidateRegister (Reg, 32, &Address); 185 if (ACPI_FAILURE (Status)) 186 { 187 return (Status); 188 } 189 190 /* Initialize entire 32-bit return value to zero */ 191 192 *Value = 0; 193 194 /* 195 * Two address spaces supported: Memory or IO. PCI_Config is 196 * not supported here because the GAS structure is insufficient 197 */ 198 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 199 { 200 Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) 201 Address, &Value64, Reg->BitWidth); 202 203 *Value = (UINT32) Value64; 204 } 205 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 206 { 207 Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) 208 Address, Value, Reg->BitWidth); 209 } 210 211 ACPI_DEBUG_PRINT ((ACPI_DB_IO, 212 "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", 213 *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 214 AcpiUtGetRegionName (Reg->SpaceId))); 215 216 return (Status); 217 } 218 219 220 /****************************************************************************** 221 * 222 * FUNCTION: AcpiHwWrite 223 * 224 * PARAMETERS: Value - Value to be written 225 * Reg - GAS register structure 226 * 227 * RETURN: Status 228 * 229 * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max 230 * version of AcpiWrite, used internally since the overhead of 231 * 64-bit values is not needed. 232 * 233 ******************************************************************************/ 234 235 ACPI_STATUS 236 AcpiHwWrite ( 237 UINT32 Value, 238 ACPI_GENERIC_ADDRESS *Reg) 239 { 240 UINT64 Address; 241 ACPI_STATUS Status; 242 243 244 ACPI_FUNCTION_NAME (HwWrite); 245 246 247 /* Validate contents of the GAS register */ 248 249 Status = AcpiHwValidateRegister (Reg, 32, &Address); 250 if (ACPI_FAILURE (Status)) 251 { 252 return (Status); 253 } 254 255 /* 256 * Two address spaces supported: Memory or IO. PCI_Config is 257 * not supported here because the GAS structure is insufficient 258 */ 259 if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) 260 { 261 Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) 262 Address, (UINT64) Value, Reg->BitWidth); 263 } 264 else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ 265 { 266 Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) 267 Address, Value, Reg->BitWidth); 268 } 269 270 ACPI_DEBUG_PRINT ((ACPI_DB_IO, 271 "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 272 Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), 273 AcpiUtGetRegionName (Reg->SpaceId))); 274 275 return (Status); 276 } 277 278 279 #if (!ACPI_REDUCED_HARDWARE) 280 /******************************************************************************* 281 * 282 * FUNCTION: AcpiHwClearAcpiStatus 283 * 284 * PARAMETERS: None 285 * 286 * RETURN: Status 287 * 288 * DESCRIPTION: Clears all fixed and general purpose status bits 289 * 290 ******************************************************************************/ 291 292 ACPI_STATUS 293 AcpiHwClearAcpiStatus ( 294 void) 295 { 296 ACPI_STATUS Status; 297 ACPI_CPU_FLAGS LockFlags = 0; 298 299 300 ACPI_FUNCTION_TRACE (HwClearAcpiStatus); 301 302 303 ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", 304 ACPI_BITMASK_ALL_FIXED_STATUS, 305 ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); 306 307 LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); 308 309 /* Clear the fixed events in PM1 A/B */ 310 311 Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, 312 ACPI_BITMASK_ALL_FIXED_STATUS); 313 314 AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); 315 316 if (ACPI_FAILURE (Status)) 317 { 318 goto Exit; 319 } 320 321 /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 322 323 Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); 324 325 Exit: 326 return_ACPI_STATUS (Status); 327 } 328 329 330 /******************************************************************************* 331 * 332 * FUNCTION: AcpiHwGetBitRegisterInfo 333 * 334 * PARAMETERS: RegisterId - Index of ACPI Register to access 335 * 336 * RETURN: The bitmask to be used when accessing the register 337 * 338 * DESCRIPTION: Map RegisterId into a register bitmask. 339 * 340 ******************************************************************************/ 341 342 ACPI_BIT_REGISTER_INFO * 343 AcpiHwGetBitRegisterInfo ( 344 UINT32 RegisterId) 345 { 346 ACPI_FUNCTION_ENTRY (); 347 348 349 if (RegisterId > ACPI_BITREG_MAX) 350 { 351 ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); 352 return (NULL); 353 } 354 355 return (&AcpiGbl_BitRegisterInfo[RegisterId]); 356 } 357 358 359 /****************************************************************************** 360 * 361 * FUNCTION: AcpiHwWritePm1Control 362 * 363 * PARAMETERS: Pm1aControl - Value to be written to PM1A control 364 * Pm1bControl - Value to be written to PM1B control 365 * 366 * RETURN: Status 367 * 368 * DESCRIPTION: Write the PM1 A/B control registers. These registers are 369 * different than than the PM1 A/B status and enable registers 370 * in that different values can be written to the A/B registers. 371 * Most notably, the SLP_TYP bits can be different, as per the 372 * values returned from the _Sx predefined methods. 373 * 374 ******************************************************************************/ 375 376 ACPI_STATUS 377 AcpiHwWritePm1Control ( 378 UINT32 Pm1aControl, 379 UINT32 Pm1bControl) 380 { 381 ACPI_STATUS Status; 382 383 384 ACPI_FUNCTION_TRACE (HwWritePm1Control); 385 386 387 Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); 388 if (ACPI_FAILURE (Status)) 389 { 390 return_ACPI_STATUS (Status); 391 } 392 393 if (AcpiGbl_FADT.XPm1bControlBlock.Address) 394 { 395 Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); 396 } 397 return_ACPI_STATUS (Status); 398 } 399 400 401 /****************************************************************************** 402 * 403 * FUNCTION: AcpiHwRegisterRead 404 * 405 * PARAMETERS: RegisterId - ACPI Register ID 406 * ReturnValue - Where the register value is returned 407 * 408 * RETURN: Status and the value read. 409 * 410 * DESCRIPTION: Read from the specified ACPI register 411 * 412 ******************************************************************************/ 413 414 ACPI_STATUS 415 AcpiHwRegisterRead ( 416 UINT32 RegisterId, 417 UINT32 *ReturnValue) 418 { 419 UINT32 Value = 0; 420 ACPI_STATUS Status; 421 422 423 ACPI_FUNCTION_TRACE (HwRegisterRead); 424 425 426 switch (RegisterId) 427 { 428 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 429 430 Status = AcpiHwReadMultiple (&Value, 431 &AcpiGbl_XPm1aStatus, 432 &AcpiGbl_XPm1bStatus); 433 break; 434 435 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 436 437 Status = AcpiHwReadMultiple (&Value, 438 &AcpiGbl_XPm1aEnable, 439 &AcpiGbl_XPm1bEnable); 440 break; 441 442 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 443 444 Status = AcpiHwReadMultiple (&Value, 445 &AcpiGbl_FADT.XPm1aControlBlock, 446 &AcpiGbl_FADT.XPm1bControlBlock); 447 448 /* 449 * Zero the write-only bits. From the ACPI specification, "Hardware 450 * Write-Only Bits": "Upon reads to registers with write-only bits, 451 * software masks out all write-only bits." 452 */ 453 Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; 454 break; 455 456 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 457 458 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); 459 break; 460 461 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 462 463 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); 464 break; 465 466 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 467 468 Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); 469 break; 470 471 default: 472 473 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 474 RegisterId)); 475 Status = AE_BAD_PARAMETER; 476 break; 477 } 478 479 if (ACPI_SUCCESS (Status)) 480 { 481 *ReturnValue = Value; 482 } 483 484 return_ACPI_STATUS (Status); 485 } 486 487 488 /****************************************************************************** 489 * 490 * FUNCTION: AcpiHwRegisterWrite 491 * 492 * PARAMETERS: RegisterId - ACPI Register ID 493 * Value - The value to write 494 * 495 * RETURN: Status 496 * 497 * DESCRIPTION: Write to the specified ACPI register 498 * 499 * NOTE: In accordance with the ACPI specification, this function automatically 500 * preserves the value of the following bits, meaning that these bits cannot be 501 * changed via this interface: 502 * 503 * PM1_CONTROL[0] = SCI_EN 504 * PM1_CONTROL[9] 505 * PM1_STATUS[11] 506 * 507 * ACPI References: 508 * 1) Hardware Ignored Bits: When software writes to a register with ignored 509 * bit fields, it preserves the ignored bit fields 510 * 2) SCI_EN: OSPM always preserves this bit position 511 * 512 ******************************************************************************/ 513 514 ACPI_STATUS 515 AcpiHwRegisterWrite ( 516 UINT32 RegisterId, 517 UINT32 Value) 518 { 519 ACPI_STATUS Status; 520 UINT32 ReadValue; 521 522 523 ACPI_FUNCTION_TRACE (HwRegisterWrite); 524 525 526 switch (RegisterId) 527 { 528 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 529 /* 530 * Handle the "ignored" bit in PM1 Status. According to the ACPI 531 * specification, ignored bits are to be preserved when writing. 532 * Normally, this would mean a read/modify/write sequence. However, 533 * preserving a bit in the status register is different. Writing a 534 * one clears the status, and writing a zero preserves the status. 535 * Therefore, we must always write zero to the ignored bit. 536 * 537 * This behavior is clarified in the ACPI 4.0 specification. 538 */ 539 Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 540 541 Status = AcpiHwWriteMultiple (Value, 542 &AcpiGbl_XPm1aStatus, 543 &AcpiGbl_XPm1bStatus); 544 break; 545 546 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 547 548 Status = AcpiHwWriteMultiple (Value, 549 &AcpiGbl_XPm1aEnable, 550 &AcpiGbl_XPm1bEnable); 551 break; 552 553 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 554 /* 555 * Perform a read first to preserve certain bits (per ACPI spec) 556 * Note: This includes SCI_EN, we never want to change this bit 557 */ 558 Status = AcpiHwReadMultiple (&ReadValue, 559 &AcpiGbl_FADT.XPm1aControlBlock, 560 &AcpiGbl_FADT.XPm1bControlBlock); 561 if (ACPI_FAILURE (Status)) 562 { 563 goto Exit; 564 } 565 566 /* Insert the bits to be preserved */ 567 568 ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); 569 570 /* Now we can write the data */ 571 572 Status = AcpiHwWriteMultiple (Value, 573 &AcpiGbl_FADT.XPm1aControlBlock, 574 &AcpiGbl_FADT.XPm1bControlBlock); 575 break; 576 577 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 578 /* 579 * For control registers, all reserved bits must be preserved, 580 * as per the ACPI spec. 581 */ 582 Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); 583 if (ACPI_FAILURE (Status)) 584 { 585 goto Exit; 586 } 587 588 /* Insert the bits to be preserved */ 589 590 ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); 591 592 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); 593 break; 594 595 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 596 597 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); 598 break; 599 600 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 601 602 /* SMI_CMD is currently always in IO space */ 603 604 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); 605 break; 606 607 default: 608 609 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 610 RegisterId)); 611 Status = AE_BAD_PARAMETER; 612 break; 613 } 614 615 Exit: 616 return_ACPI_STATUS (Status); 617 } 618 619 620 /****************************************************************************** 621 * 622 * FUNCTION: AcpiHwReadMultiple 623 * 624 * PARAMETERS: Value - Where the register value is returned 625 * RegisterA - First ACPI register (required) 626 * RegisterB - Second ACPI register (optional) 627 * 628 * RETURN: Status 629 * 630 * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 631 * 632 ******************************************************************************/ 633 634 static ACPI_STATUS 635 AcpiHwReadMultiple ( 636 UINT32 *Value, 637 ACPI_GENERIC_ADDRESS *RegisterA, 638 ACPI_GENERIC_ADDRESS *RegisterB) 639 { 640 UINT32 ValueA = 0; 641 UINT32 ValueB = 0; 642 ACPI_STATUS Status; 643 644 645 /* The first register is always required */ 646 647 Status = AcpiHwRead (&ValueA, RegisterA); 648 if (ACPI_FAILURE (Status)) 649 { 650 return (Status); 651 } 652 653 /* Second register is optional */ 654 655 if (RegisterB->Address) 656 { 657 Status = AcpiHwRead (&ValueB, RegisterB); 658 if (ACPI_FAILURE (Status)) 659 { 660 return (Status); 661 } 662 } 663 664 /* 665 * OR the two return values together. No shifting or masking is necessary, 666 * because of how the PM1 registers are defined in the ACPI specification: 667 * 668 * "Although the bits can be split between the two register blocks (each 669 * register block has a unique pointer within the FADT), the bit positions 670 * are maintained. The register block with unimplemented bits (that is, 671 * those implemented in the other register block) always returns zeros, 672 * and writes have no side effects" 673 */ 674 *Value = (ValueA | ValueB); 675 return (AE_OK); 676 } 677 678 679 /****************************************************************************** 680 * 681 * FUNCTION: AcpiHwWriteMultiple 682 * 683 * PARAMETERS: Value - The value to write 684 * RegisterA - First ACPI register (required) 685 * RegisterB - Second ACPI register (optional) 686 * 687 * RETURN: Status 688 * 689 * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 690 * 691 ******************************************************************************/ 692 693 static ACPI_STATUS 694 AcpiHwWriteMultiple ( 695 UINT32 Value, 696 ACPI_GENERIC_ADDRESS *RegisterA, 697 ACPI_GENERIC_ADDRESS *RegisterB) 698 { 699 ACPI_STATUS Status; 700 701 702 /* The first register is always required */ 703 704 Status = AcpiHwWrite (Value, RegisterA); 705 if (ACPI_FAILURE (Status)) 706 { 707 return (Status); 708 } 709 710 /* 711 * Second register is optional 712 * 713 * No bit shifting or clearing is necessary, because of how the PM1 714 * registers are defined in the ACPI specification: 715 * 716 * "Although the bits can be split between the two register blocks (each 717 * register block has a unique pointer within the FADT), the bit positions 718 * are maintained. The register block with unimplemented bits (that is, 719 * those implemented in the other register block) always returns zeros, 720 * and writes have no side effects" 721 */ 722 if (RegisterB->Address) 723 { 724 Status = AcpiHwWrite (Value, RegisterB); 725 } 726 727 return (Status); 728 } 729 730 #endif /* !ACPI_REDUCED_HARDWARE */ 731