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