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 - 2013, 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 if (ACPI_FAILURE (Status)) 314 { 315 goto UnlockAndExit; 316 } 317 318 /* Clear the GPE Bits in all GPE registers in all GPE blocks */ 319 320 Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); 321 322 UnlockAndExit: 323 AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); 324 return_ACPI_STATUS (Status); 325 } 326 327 328 /******************************************************************************* 329 * 330 * FUNCTION: AcpiHwGetBitRegisterInfo 331 * 332 * PARAMETERS: RegisterId - Index of ACPI Register to access 333 * 334 * RETURN: The bitmask to be used when accessing the register 335 * 336 * DESCRIPTION: Map RegisterId into a register bitmask. 337 * 338 ******************************************************************************/ 339 340 ACPI_BIT_REGISTER_INFO * 341 AcpiHwGetBitRegisterInfo ( 342 UINT32 RegisterId) 343 { 344 ACPI_FUNCTION_ENTRY (); 345 346 347 if (RegisterId > ACPI_BITREG_MAX) 348 { 349 ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: 0x%X", RegisterId)); 350 return (NULL); 351 } 352 353 return (&AcpiGbl_BitRegisterInfo[RegisterId]); 354 } 355 356 357 /****************************************************************************** 358 * 359 * FUNCTION: AcpiHwWritePm1Control 360 * 361 * PARAMETERS: Pm1aControl - Value to be written to PM1A control 362 * Pm1bControl - Value to be written to PM1B control 363 * 364 * RETURN: Status 365 * 366 * DESCRIPTION: Write the PM1 A/B control registers. These registers are 367 * different than than the PM1 A/B status and enable registers 368 * in that different values can be written to the A/B registers. 369 * Most notably, the SLP_TYP bits can be different, as per the 370 * values returned from the _Sx predefined methods. 371 * 372 ******************************************************************************/ 373 374 ACPI_STATUS 375 AcpiHwWritePm1Control ( 376 UINT32 Pm1aControl, 377 UINT32 Pm1bControl) 378 { 379 ACPI_STATUS Status; 380 381 382 ACPI_FUNCTION_TRACE (HwWritePm1Control); 383 384 385 Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock); 386 if (ACPI_FAILURE (Status)) 387 { 388 return_ACPI_STATUS (Status); 389 } 390 391 if (AcpiGbl_FADT.XPm1bControlBlock.Address) 392 { 393 Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock); 394 } 395 return_ACPI_STATUS (Status); 396 } 397 398 399 /****************************************************************************** 400 * 401 * FUNCTION: AcpiHwRegisterRead 402 * 403 * PARAMETERS: RegisterId - ACPI Register ID 404 * ReturnValue - Where the register value is returned 405 * 406 * RETURN: Status and the value read. 407 * 408 * DESCRIPTION: Read from the specified ACPI register 409 * 410 ******************************************************************************/ 411 412 ACPI_STATUS 413 AcpiHwRegisterRead ( 414 UINT32 RegisterId, 415 UINT32 *ReturnValue) 416 { 417 UINT32 Value = 0; 418 ACPI_STATUS Status; 419 420 421 ACPI_FUNCTION_TRACE (HwRegisterRead); 422 423 424 switch (RegisterId) 425 { 426 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 427 428 Status = AcpiHwReadMultiple (&Value, 429 &AcpiGbl_XPm1aStatus, 430 &AcpiGbl_XPm1bStatus); 431 break; 432 433 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 434 435 Status = AcpiHwReadMultiple (&Value, 436 &AcpiGbl_XPm1aEnable, 437 &AcpiGbl_XPm1bEnable); 438 break; 439 440 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 441 442 Status = AcpiHwReadMultiple (&Value, 443 &AcpiGbl_FADT.XPm1aControlBlock, 444 &AcpiGbl_FADT.XPm1bControlBlock); 445 446 /* 447 * Zero the write-only bits. From the ACPI specification, "Hardware 448 * Write-Only Bits": "Upon reads to registers with write-only bits, 449 * software masks out all write-only bits." 450 */ 451 Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; 452 break; 453 454 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 455 456 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); 457 break; 458 459 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 460 461 Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); 462 break; 463 464 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 465 466 Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); 467 break; 468 469 default: 470 471 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 472 RegisterId)); 473 Status = AE_BAD_PARAMETER; 474 break; 475 } 476 477 if (ACPI_SUCCESS (Status)) 478 { 479 *ReturnValue = Value; 480 } 481 482 return_ACPI_STATUS (Status); 483 } 484 485 486 /****************************************************************************** 487 * 488 * FUNCTION: AcpiHwRegisterWrite 489 * 490 * PARAMETERS: RegisterId - ACPI Register ID 491 * Value - The value to write 492 * 493 * RETURN: Status 494 * 495 * DESCRIPTION: Write to the specified ACPI register 496 * 497 * NOTE: In accordance with the ACPI specification, this function automatically 498 * preserves the value of the following bits, meaning that these bits cannot be 499 * changed via this interface: 500 * 501 * PM1_CONTROL[0] = SCI_EN 502 * PM1_CONTROL[9] 503 * PM1_STATUS[11] 504 * 505 * ACPI References: 506 * 1) Hardware Ignored Bits: When software writes to a register with ignored 507 * bit fields, it preserves the ignored bit fields 508 * 2) SCI_EN: OSPM always preserves this bit position 509 * 510 ******************************************************************************/ 511 512 ACPI_STATUS 513 AcpiHwRegisterWrite ( 514 UINT32 RegisterId, 515 UINT32 Value) 516 { 517 ACPI_STATUS Status; 518 UINT32 ReadValue; 519 520 521 ACPI_FUNCTION_TRACE (HwRegisterWrite); 522 523 524 switch (RegisterId) 525 { 526 case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ 527 /* 528 * Handle the "ignored" bit in PM1 Status. According to the ACPI 529 * specification, ignored bits are to be preserved when writing. 530 * Normally, this would mean a read/modify/write sequence. However, 531 * preserving a bit in the status register is different. Writing a 532 * one clears the status, and writing a zero preserves the status. 533 * Therefore, we must always write zero to the ignored bit. 534 * 535 * This behavior is clarified in the ACPI 4.0 specification. 536 */ 537 Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; 538 539 Status = AcpiHwWriteMultiple (Value, 540 &AcpiGbl_XPm1aStatus, 541 &AcpiGbl_XPm1bStatus); 542 break; 543 544 case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ 545 546 Status = AcpiHwWriteMultiple (Value, 547 &AcpiGbl_XPm1aEnable, 548 &AcpiGbl_XPm1bEnable); 549 break; 550 551 case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ 552 /* 553 * Perform a read first to preserve certain bits (per ACPI spec) 554 * Note: This includes SCI_EN, we never want to change this bit 555 */ 556 Status = AcpiHwReadMultiple (&ReadValue, 557 &AcpiGbl_FADT.XPm1aControlBlock, 558 &AcpiGbl_FADT.XPm1bControlBlock); 559 if (ACPI_FAILURE (Status)) 560 { 561 goto Exit; 562 } 563 564 /* Insert the bits to be preserved */ 565 566 ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); 567 568 /* Now we can write the data */ 569 570 Status = AcpiHwWriteMultiple (Value, 571 &AcpiGbl_FADT.XPm1aControlBlock, 572 &AcpiGbl_FADT.XPm1bControlBlock); 573 break; 574 575 case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ 576 /* 577 * For control registers, all reserved bits must be preserved, 578 * as per the ACPI spec. 579 */ 580 Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); 581 if (ACPI_FAILURE (Status)) 582 { 583 goto Exit; 584 } 585 586 /* Insert the bits to be preserved */ 587 588 ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); 589 590 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); 591 break; 592 593 case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ 594 595 Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); 596 break; 597 598 case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ 599 600 /* SMI_CMD is currently always in IO space */ 601 602 Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); 603 break; 604 605 default: 606 607 ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X", 608 RegisterId)); 609 Status = AE_BAD_PARAMETER; 610 break; 611 } 612 613 Exit: 614 return_ACPI_STATUS (Status); 615 } 616 617 618 /****************************************************************************** 619 * 620 * FUNCTION: AcpiHwReadMultiple 621 * 622 * PARAMETERS: Value - Where the register value is returned 623 * RegisterA - First ACPI register (required) 624 * RegisterB - Second ACPI register (optional) 625 * 626 * RETURN: Status 627 * 628 * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) 629 * 630 ******************************************************************************/ 631 632 static ACPI_STATUS 633 AcpiHwReadMultiple ( 634 UINT32 *Value, 635 ACPI_GENERIC_ADDRESS *RegisterA, 636 ACPI_GENERIC_ADDRESS *RegisterB) 637 { 638 UINT32 ValueA = 0; 639 UINT32 ValueB = 0; 640 ACPI_STATUS Status; 641 642 643 /* The first register is always required */ 644 645 Status = AcpiHwRead (&ValueA, RegisterA); 646 if (ACPI_FAILURE (Status)) 647 { 648 return (Status); 649 } 650 651 /* Second register is optional */ 652 653 if (RegisterB->Address) 654 { 655 Status = AcpiHwRead (&ValueB, RegisterB); 656 if (ACPI_FAILURE (Status)) 657 { 658 return (Status); 659 } 660 } 661 662 /* 663 * OR the two return values together. No shifting or masking is necessary, 664 * because of how the PM1 registers are defined in the ACPI specification: 665 * 666 * "Although the bits can be split between the two register blocks (each 667 * register block has a unique pointer within the FADT), the bit positions 668 * are maintained. The register block with unimplemented bits (that is, 669 * those implemented in the other register block) always returns zeros, 670 * and writes have no side effects" 671 */ 672 *Value = (ValueA | ValueB); 673 return (AE_OK); 674 } 675 676 677 /****************************************************************************** 678 * 679 * FUNCTION: AcpiHwWriteMultiple 680 * 681 * PARAMETERS: Value - The value to write 682 * RegisterA - First ACPI register (required) 683 * RegisterB - Second ACPI register (optional) 684 * 685 * RETURN: Status 686 * 687 * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) 688 * 689 ******************************************************************************/ 690 691 static ACPI_STATUS 692 AcpiHwWriteMultiple ( 693 UINT32 Value, 694 ACPI_GENERIC_ADDRESS *RegisterA, 695 ACPI_GENERIC_ADDRESS *RegisterB) 696 { 697 ACPI_STATUS Status; 698 699 700 /* The first register is always required */ 701 702 Status = AcpiHwWrite (Value, RegisterA); 703 if (ACPI_FAILURE (Status)) 704 { 705 return (Status); 706 } 707 708 /* 709 * Second register is optional 710 * 711 * No bit shifting or clearing is necessary, because of how the PM1 712 * registers are defined in the ACPI specification: 713 * 714 * "Although the bits can be split between the two register blocks (each 715 * register block has a unique pointer within the FADT), the bit positions 716 * are maintained. The register block with unimplemented bits (that is, 717 * those implemented in the other register block) always returns zeros, 718 * and writes have no side effects" 719 */ 720 if (RegisterB->Address) 721 { 722 Status = AcpiHwWrite (Value, RegisterB); 723 } 724 725 return (Status); 726 } 727 728 #endif /* !ACPI_REDUCED_HARDWARE */ 729