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