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