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 "acpi.h"
  48 #include "accommon.h"
  49 #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 */