Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/acpica/hwregs.c need to be fixed.

0001 
0002 /*******************************************************************************
0003  *
0004  * Module Name: hwregs - Read/write access functions for the various ACPI
0005  *                       control and status registers.
0006  *
0007  ******************************************************************************/
0008 
0009 /******************************************************************************
0010  *
0011  * 1. Copyright Notice
0012  *
0013  * Some or all of this work - Copyright (c) 1999 - 2009, Intel Corp.
0014  * All rights reserved.
0015  *
0016  * 2. License
0017  *
0018  * 2.1. This is your license from Intel Corp. under its intellectual property
0019  * rights.  You may have additional license terms from the party that provided
0020  * you this software, covering your right to use that party's intellectual
0021  * property rights.
0022  *
0023  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
0024  * copy of the source code appearing in this file ("Covered Code") an
0025  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
0026  * base code distributed originally by Intel ("Original Intel Code") to copy,
0027  * make derivatives, distribute, use and display any portion of the Covered
0028  * Code in any form, with the right to sublicense such rights; and
0029  *
0030  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
0031  * license (with the right to sublicense), under only those claims of Intel
0032  * patents that are infringed by the Original Intel Code, to make, use, sell,
0033  * offer to sell, and import the Covered Code and derivative works thereof
0034  * solely to the minimum extent necessary to exercise the above copyright
0035  * license, and in no event shall the patent license extend to any additions
0036  * to or modifications of the Original Intel Code.  No other license or right
0037  * is granted directly or by implication, estoppel or otherwise;
0038  *
0039  * The above copyright and patent license is granted only if the following
0040  * conditions are met:
0041  *
0042  * 3. Conditions
0043  *
0044  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
0045  * Redistribution of source code of any substantial portion of the Covered
0046  * Code or modification with rights to further distribute source must include
0047  * the above Copyright Notice, the above License, this list of Conditions,
0048  * and the following Disclaimer and Export Compliance provision.  In addition,
0049  * Licensee must cause all Covered Code to which Licensee contributes to
0050  * contain a file documenting the changes Licensee made to create that Covered
0051  * Code and the date of any change.  Licensee must include in that file the
0052  * documentation of any changes made by any predecessor Licensee.  Licensee
0053  * must include a prominent statement that the modification is derived,
0054  * directly or indirectly, from Original Intel Code.
0055  *
0056  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
0057  * Redistribution of source code of any substantial portion of the Covered
0058  * Code or modification without rights to further distribute source must
0059  * include the following Disclaimer and Export Compliance provision in the
0060  * documentation and/or other materials provided with distribution.  In
0061  * addition, Licensee may not authorize further sublicense of source of any
0062  * portion of the Covered Code, and must include terms to the effect that the
0063  * license from Licensee to its licensee is limited to the intellectual
0064  * property embodied in the software Licensee provides to its licensee, and
0065  * not to intellectual property embodied in modifications its licensee may
0066  * make.
0067  *
0068  * 3.3. Redistribution of Executable. Redistribution in executable form of any
0069  * substantial portion of the Covered Code or modification must reproduce the
0070  * above Copyright Notice, and the following Disclaimer and Export Compliance
0071  * provision in the documentation and/or other materials provided with the
0072  * distribution.
0073  *
0074  * 3.4. Intel retains all right, title, and interest in and to the Original
0075  * Intel Code.
0076  *
0077  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
0078  * Intel shall be used in advertising or otherwise to promote the sale, use or
0079  * other dealings in products derived from or relating to the Covered Code
0080  * without prior written authorization from Intel.
0081  *
0082  * 4. Disclaimer and Export Compliance
0083  *
0084  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
0085  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
0086  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
0087  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
0088  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
0089  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
0090  * PARTICULAR PURPOSE.
0091  *
0092  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
0093  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
0094  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
0095  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
0096  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
0097  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
0098  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
0099  * LIMITED REMEDY.
0100  *
0101  * 4.3. Licensee shall not export, either directly or indirectly, any of this
0102  * software or system incorporating such software without first obtaining any
0103  * required license or other approval from the U. S. Department of Commerce or
0104  * any other agency or department of the United States Government.  In the
0105  * event Licensee exports any such software from the United States or
0106  * re-exports any such software from a foreign destination, Licensee shall
0107  * ensure that the distribution and export/re-export of the software is in
0108  * compliance with all laws, regulations, orders, or other restrictions of the
0109  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
0110  * any of its subsidiaries will export/re-export any technical data, process,
0111  * software, or service, directly or indirectly, to any country for which the
0112  * United States government or any agency thereof requires an export license,
0113  * other governmental approval, or letter of assurance, without first obtaining
0114  * such license, approval or letter.
0115  *
0116  *****************************************************************************/
0117 
0118 #define __HWREGS_C__
0119 
0120 #include "acpi.h"
0121 #include "accommon.h"
0122 #include "acevents.h"
0123 
0124 #define _COMPONENT          ACPI_HARDWARE
0125         ACPI_MODULE_NAME    ("hwregs")
0126 
0127 
0128 /* Local Prototypes */
0129 
0130 static ACPI_STATUS
0131 AcpiHwReadMultiple (
0132     UINT32                  *Value,
0133     ACPI_GENERIC_ADDRESS    *RegisterA,
0134     ACPI_GENERIC_ADDRESS    *RegisterB);
0135 
0136 static ACPI_STATUS
0137 AcpiHwWriteMultiple (
0138     UINT32                  Value,
0139     ACPI_GENERIC_ADDRESS    *RegisterA,
0140     ACPI_GENERIC_ADDRESS    *RegisterB);
0141 
0142 
0143 /******************************************************************************
0144  *
0145  * FUNCTION:    AcpiHwValidateRegister
0146  *
0147  * PARAMETERS:  Reg                 - GAS register structure
0148  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
0149  *              Address             - Pointer to where the gas->address
0150  *                                    is returned
0151  *
0152  * RETURN:      Status
0153  *
0154  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
0155  *              pointer, Address, SpaceId, BitWidth, and BitOffset.
0156  *
0157  ******************************************************************************/
0158 
0159 ACPI_STATUS
0160 AcpiHwValidateRegister (
0161     ACPI_GENERIC_ADDRESS    *Reg,
0162     UINT8                   MaxBitWidth,
0163     UINT64                  *Address)
0164 {
0165 
0166     /* Must have a valid pointer to a GAS structure */
0167 
0168     if (!Reg)
0169     {
0170         return (AE_BAD_PARAMETER);
0171     }
0172 
0173     /*
0174      * Copy the target address. This handles possible alignment issues.
0175      * Address must not be null. A null address also indicates an optional
0176      * ACPI register that is not supported, so no error message.
0177      */
0178     ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
0179     if (!(*Address))
0180     {
0181         return (AE_BAD_ADDRESS);
0182     }
0183 
0184     /* Validate the SpaceID */
0185 
0186     if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
0187         (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
0188     {
0189         ACPI_ERROR ((AE_INFO,
0190             "Unsupported address space: 0x%X", Reg->SpaceId));
0191         return (AE_SUPPORT);
0192     }
0193 
0194     /* Validate the BitWidth */
0195 
0196     if ((Reg->BitWidth != 8) &&
0197         (Reg->BitWidth != 16) &&
0198         (Reg->BitWidth != 32) &&
0199         (Reg->BitWidth != MaxBitWidth))
0200     {
0201         ACPI_ERROR ((AE_INFO,
0202             "Unsupported register bit width: 0x%X", Reg->BitWidth));
0203         return (AE_SUPPORT);
0204     }
0205 
0206     /* Validate the BitOffset. Just a warning for now. */
0207 
0208     if (Reg->BitOffset != 0)
0209     {
0210         ACPI_WARNING ((AE_INFO,
0211             "Unsupported register bit offset: 0x%X", Reg->BitOffset));
0212     }
0213 
0214     return (AE_OK);
0215 }
0216 
0217 
0218 /******************************************************************************
0219  *
0220  * FUNCTION:    AcpiHwRead
0221  *
0222  * PARAMETERS:  Value               - Where the value is returned
0223  *              Reg                 - GAS register structure
0224  *
0225  * RETURN:      Status
0226  *
0227  * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
0228  *              version of AcpiRead, used internally since the overhead of
0229  *              64-bit values is not needed.
0230  *
0231  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
0232  *      BitWidth must be exactly 8, 16, or 32.
0233  *      SpaceID must be SystemMemory or SystemIO.
0234  *      BitOffset and AccessWidth are currently ignored, as there has
0235  *          not been a need to implement these.
0236  *
0237  ******************************************************************************/
0238 
0239 ACPI_STATUS
0240 AcpiHwRead (
0241     UINT32                  *Value,
0242     ACPI_GENERIC_ADDRESS    *Reg)
0243 {
0244     UINT64                  Address;
0245     ACPI_STATUS             Status;
0246 
0247 
0248     ACPI_FUNCTION_NAME (HwRead);
0249 
0250 
0251     /* Validate contents of the GAS register */
0252 
0253     Status = AcpiHwValidateRegister (Reg, 32, &Address);
0254     if (ACPI_FAILURE (Status))
0255     {
0256         return (Status);
0257     }
0258 
0259     /* Initialize entire 32-bit return value to zero */
0260 
0261     *Value = 0;
0262 
0263     /*
0264      * Two address spaces supported: Memory or IO. PCI_Config is
0265      * not supported here because the GAS structure is insufficient
0266      */
0267     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
0268     {
0269         Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
0270                     Address, Value, Reg->BitWidth);
0271     }
0272     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
0273     {
0274         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
0275                     Address, Value, Reg->BitWidth);
0276     }
0277 
0278     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
0279         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
0280         *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
0281         AcpiUtGetRegionName (Reg->SpaceId)));
0282 
0283     return (Status);
0284 }
0285 
0286 
0287 /******************************************************************************
0288  *
0289  * FUNCTION:    AcpiHwWrite
0290  *
0291  * PARAMETERS:  Value               - Value to be written
0292  *              Reg                 - GAS register structure
0293  *
0294  * RETURN:      Status
0295  *
0296  * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
0297  *              version of AcpiWrite, used internally since the overhead of
0298  *              64-bit values is not needed.
0299  *
0300  ******************************************************************************/
0301 
0302 ACPI_STATUS
0303 AcpiHwWrite (
0304     UINT32                  Value,
0305     ACPI_GENERIC_ADDRESS    *Reg)
0306 {
0307     UINT64                  Address;
0308     ACPI_STATUS             Status;
0309 
0310 
0311     ACPI_FUNCTION_NAME (HwWrite);
0312 
0313 
0314     /* Validate contents of the GAS register */
0315 
0316     Status = AcpiHwValidateRegister (Reg, 32, &Address);
0317     if (ACPI_FAILURE (Status))
0318     {
0319         return (Status);
0320     }
0321 
0322     /*
0323      * Two address spaces supported: Memory or IO. PCI_Config is
0324      * not supported here because the GAS structure is insufficient
0325      */
0326     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
0327     {
0328         Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
0329                     Address, Value, Reg->BitWidth);
0330     }
0331     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
0332     {
0333         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
0334                     Address, Value, Reg->BitWidth);
0335     }
0336 
0337     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
0338         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
0339         Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
0340         AcpiUtGetRegionName (Reg->SpaceId)));
0341 
0342     return (Status);
0343 }
0344 
0345 
0346 /*******************************************************************************
0347  *
0348  * FUNCTION:    AcpiHwClearAcpiStatus
0349  *
0350  * PARAMETERS:  None
0351  *
0352  * RETURN:      Status
0353  *
0354  * DESCRIPTION: Clears all fixed and general purpose status bits
0355  *
0356  ******************************************************************************/
0357 
0358 ACPI_STATUS
0359 AcpiHwClearAcpiStatus (
0360     void)
0361 {
0362     ACPI_STATUS             Status;
0363     ACPI_CPU_FLAGS          LockFlags = 0;
0364 
0365 
0366     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
0367 
0368 
0369     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
0370         ACPI_BITMASK_ALL_FIXED_STATUS,
0371         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
0372 
0373     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
0374 
0375     /* Clear the fixed events in PM1 A/B */
0376 
0377     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
0378                 ACPI_BITMASK_ALL_FIXED_STATUS);
0379     if (ACPI_FAILURE (Status))
0380     {
0381         goto UnlockAndExit;
0382     }
0383 
0384     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
0385 
0386     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
0387 
0388 UnlockAndExit:
0389     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
0390     return_ACPI_STATUS (Status);
0391 }
0392 
0393 
0394 /*******************************************************************************
0395  *
0396  * FUNCTION:    AcpiHwGetRegisterBitMask
0397  *
0398  * PARAMETERS:  RegisterId          - Index of ACPI Register to access
0399  *
0400  * RETURN:      The bitmask to be used when accessing the register
0401  *
0402  * DESCRIPTION: Map RegisterId into a register bitmask.
0403  *
0404  ******************************************************************************/
0405 
0406 ACPI_BIT_REGISTER_INFO *
0407 AcpiHwGetBitRegisterInfo (
0408     UINT32                  RegisterId)
0409 {
0410     ACPI_FUNCTION_ENTRY ();
0411 
0412 
0413     if (RegisterId > ACPI_BITREG_MAX)
0414     {
0415         ACPI_ERROR ((AE_INFO, "Invalid BitRegister ID: %X", RegisterId));
0416         return (NULL);
0417     }
0418 
0419     return (&AcpiGbl_BitRegisterInfo[RegisterId]);
0420 }
0421 
0422 
0423 /******************************************************************************
0424  *
0425  * FUNCTION:    AcpiHwWritePm1Control
0426  *
0427  * PARAMETERS:  Pm1aControl         - Value to be written to PM1A control
0428  *              Pm1bControl         - Value to be written to PM1B control
0429  *
0430  * RETURN:      Status
0431  *
0432  * DESCRIPTION: Write the PM1 A/B control registers. These registers are
0433  *              different than than the PM1 A/B status and enable registers
0434  *              in that different values can be written to the A/B registers.
0435  *              Most notably, the SLP_TYP bits can be different, as per the
0436  *              values returned from the _Sx predefined methods.
0437  *
0438  ******************************************************************************/
0439 
0440 ACPI_STATUS
0441 AcpiHwWritePm1Control (
0442     UINT32                  Pm1aControl,
0443     UINT32                  Pm1bControl)
0444 {
0445     ACPI_STATUS             Status;
0446 
0447 
0448     ACPI_FUNCTION_TRACE (HwWritePm1Control);
0449 
0450 
0451     Status = AcpiHwWrite (Pm1aControl, &AcpiGbl_FADT.XPm1aControlBlock);
0452     if (ACPI_FAILURE (Status))
0453     {
0454         return_ACPI_STATUS (Status);
0455     }
0456 
0457     if (AcpiGbl_FADT.XPm1bControlBlock.Address)
0458     {
0459         Status = AcpiHwWrite (Pm1bControl, &AcpiGbl_FADT.XPm1bControlBlock);
0460     }
0461     return_ACPI_STATUS (Status);
0462 }
0463 
0464 
0465 /******************************************************************************
0466  *
0467  * FUNCTION:    AcpiHwRegisterRead
0468  *
0469  * PARAMETERS:  RegisterId          - ACPI Register ID
0470  *              ReturnValue         - Where the register value is returned
0471  *
0472  * RETURN:      Status and the value read.
0473  *
0474  * DESCRIPTION: Read from the specified ACPI register
0475  *
0476  ******************************************************************************/
0477 
0478 ACPI_STATUS
0479 AcpiHwRegisterRead (
0480     UINT32                  RegisterId,
0481     UINT32                  *ReturnValue)
0482 {
0483     UINT32                  Value = 0;
0484     ACPI_STATUS             Status;
0485 
0486 
0487     ACPI_FUNCTION_TRACE (HwRegisterRead);
0488 
0489 
0490     switch (RegisterId)
0491     {
0492     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
0493 
0494         Status = AcpiHwReadMultiple (&Value,
0495                     &AcpiGbl_XPm1aStatus,
0496                     &AcpiGbl_XPm1bStatus);
0497         break;
0498 
0499 
0500     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
0501 
0502         Status = AcpiHwReadMultiple (&Value,
0503                     &AcpiGbl_XPm1aEnable,
0504                     &AcpiGbl_XPm1bEnable);
0505         break;
0506 
0507 
0508     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
0509 
0510         Status = AcpiHwReadMultiple (&Value,
0511                     &AcpiGbl_FADT.XPm1aControlBlock,
0512                     &AcpiGbl_FADT.XPm1bControlBlock);
0513 
0514         /*
0515          * Zero the write-only bits. From the ACPI specification, "Hardware
0516          * Write-Only Bits": "Upon reads to registers with write-only bits,
0517          * software masks out all write-only bits."
0518          */
0519         Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS;
0520         break;
0521 
0522 
0523     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
0524 
0525         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock);
0526         break;
0527 
0528 
0529     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
0530 
0531         Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock);
0532         break;
0533 
0534 
0535     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
0536 
0537         Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8);
0538         break;
0539 
0540 
0541     default:
0542         ACPI_ERROR ((AE_INFO, "Unknown Register ID: %X",
0543             RegisterId));
0544         Status = AE_BAD_PARAMETER;
0545         break;
0546     }
0547 
0548     if (ACPI_SUCCESS (Status))
0549     {
0550         *ReturnValue = Value;
0551     }
0552 
0553     return_ACPI_STATUS (Status);
0554 }
0555 
0556 
0557 /******************************************************************************
0558  *
0559  * FUNCTION:    AcpiHwRegisterWrite
0560  *
0561  * PARAMETERS:  RegisterId          - ACPI Register ID
0562  *              Value               - The value to write
0563  *
0564  * RETURN:      Status
0565  *
0566  * DESCRIPTION: Write to the specified ACPI register
0567  *
0568  * NOTE: In accordance with the ACPI specification, this function automatically
0569  * preserves the value of the following bits, meaning that these bits cannot be
0570  * changed via this interface:
0571  *
0572  * PM1_CONTROL[0] = SCI_EN
0573  * PM1_CONTROL[9]
0574  * PM1_STATUS[11]
0575  *
0576  * ACPI References:
0577  * 1) Hardware Ignored Bits: When software writes to a register with ignored
0578  *      bit fields, it preserves the ignored bit fields
0579  * 2) SCI_EN: OSPM always preserves this bit position
0580  *
0581  ******************************************************************************/
0582 
0583 ACPI_STATUS
0584 AcpiHwRegisterWrite (
0585     UINT32                  RegisterId,
0586     UINT32                  Value)
0587 {
0588     ACPI_STATUS             Status;
0589     UINT32                  ReadValue;
0590 
0591 
0592     ACPI_FUNCTION_TRACE (HwRegisterWrite);
0593 
0594 
0595     switch (RegisterId)
0596     {
0597     case ACPI_REGISTER_PM1_STATUS:           /* PM1 A/B: 16-bit access each */
0598         /*
0599          * Handle the "ignored" bit in PM1 Status. According to the ACPI
0600          * specification, ignored bits are to be preserved when writing.
0601          * Normally, this would mean a read/modify/write sequence. However,
0602          * preserving a bit in the status register is different. Writing a
0603          * one clears the status, and writing a zero preserves the status.
0604          * Therefore, we must always write zero to the ignored bit.
0605          *
0606          * This behavior is clarified in the ACPI 4.0 specification.
0607          */
0608         Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS;
0609 
0610         Status = AcpiHwWriteMultiple (Value,
0611                     &AcpiGbl_XPm1aStatus,
0612                     &AcpiGbl_XPm1bStatus);
0613         break;
0614 
0615 
0616     case ACPI_REGISTER_PM1_ENABLE:           /* PM1 A/B: 16-bit access each */
0617 
0618         Status = AcpiHwWriteMultiple (Value,
0619                     &AcpiGbl_XPm1aEnable,
0620                     &AcpiGbl_XPm1bEnable);
0621         break;
0622 
0623 
0624     case ACPI_REGISTER_PM1_CONTROL:          /* PM1 A/B: 16-bit access each */
0625 
0626         /*
0627          * Perform a read first to preserve certain bits (per ACPI spec)
0628          * Note: This includes SCI_EN, we never want to change this bit
0629          */
0630         Status = AcpiHwReadMultiple (&ReadValue,
0631                     &AcpiGbl_FADT.XPm1aControlBlock,
0632                     &AcpiGbl_FADT.XPm1bControlBlock);
0633         if (ACPI_FAILURE (Status))
0634         {
0635             goto Exit;
0636         }
0637 
0638         /* Insert the bits to be preserved */
0639 
0640         ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue);
0641 
0642         /* Now we can write the data */
0643 
0644         Status = AcpiHwWriteMultiple (Value,
0645                     &AcpiGbl_FADT.XPm1aControlBlock,
0646                     &AcpiGbl_FADT.XPm1bControlBlock);
0647         break;
0648 
0649 
0650     case ACPI_REGISTER_PM2_CONTROL:          /* 8-bit access */
0651 
0652         /*
0653          * For control registers, all reserved bits must be preserved,
0654          * as per the ACPI spec.
0655          */
0656         Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock);
0657         if (ACPI_FAILURE (Status))
0658         {
0659             goto Exit;
0660         }
0661 
0662         /* Insert the bits to be preserved */
0663 
0664         ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue);
0665 
0666         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock);
0667         break;
0668 
0669 
0670     case ACPI_REGISTER_PM_TIMER:             /* 32-bit access */
0671 
0672         Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock);
0673         break;
0674 
0675 
0676     case ACPI_REGISTER_SMI_COMMAND_BLOCK:    /* 8-bit access */
0677 
0678         /* SMI_CMD is currently always in IO space */
0679 
0680         Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8);
0681         break;
0682 
0683 
0684     default:
0685         ACPI_ERROR ((AE_INFO, "Unknown Register ID: %X",
0686             RegisterId));
0687         Status = AE_BAD_PARAMETER;
0688         break;
0689     }
0690 
0691 Exit:
0692     return_ACPI_STATUS (Status);
0693 }
0694 
0695 
0696 /******************************************************************************
0697  *
0698  * FUNCTION:    AcpiHwReadMultiple
0699  *
0700  * PARAMETERS:  Value               - Where the register value is returned
0701  *              RegisterA           - First ACPI register (required)
0702  *              RegisterB           - Second ACPI register (optional)
0703  *
0704  * RETURN:      Status
0705  *
0706  * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B)
0707  *
0708  ******************************************************************************/
0709 
0710 static ACPI_STATUS
0711 AcpiHwReadMultiple (
0712     UINT32                  *Value,
0713     ACPI_GENERIC_ADDRESS    *RegisterA,
0714     ACPI_GENERIC_ADDRESS    *RegisterB)
0715 {
0716     UINT32                  ValueA = 0;
0717     UINT32                  ValueB = 0;
0718     ACPI_STATUS             Status;
0719 
0720 
0721     /* The first register is always required */
0722 
0723     Status = AcpiHwRead (&ValueA, RegisterA);
0724     if (ACPI_FAILURE (Status))
0725     {
0726         return (Status);
0727     }
0728 
0729     /* Second register is optional */
0730 
0731     if (RegisterB->Address)
0732     {
0733         Status = AcpiHwRead (&ValueB, RegisterB);
0734         if (ACPI_FAILURE (Status))
0735         {
0736             return (Status);
0737         }
0738     }
0739 
0740     /*
0741      * OR the two return values together. No shifting or masking is necessary,
0742      * because of how the PM1 registers are defined in the ACPI specification:
0743      *
0744      * "Although the bits can be split between the two register blocks (each
0745      * register block has a unique pointer within the FADT), the bit positions
0746      * are maintained. The register block with unimplemented bits (that is,
0747      * those implemented in the other register block) always returns zeros,
0748      * and writes have no side effects"
0749      */
0750     *Value = (ValueA | ValueB);
0751     return (AE_OK);
0752 }
0753 
0754 
0755 /******************************************************************************
0756  *
0757  * FUNCTION:    AcpiHwWriteMultiple
0758  *
0759  * PARAMETERS:  Value               - The value to write
0760  *              RegisterA           - First ACPI register (required)
0761  *              RegisterB           - Second ACPI register (optional)
0762  *
0763  * RETURN:      Status
0764  *
0765  * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B)
0766  *
0767  ******************************************************************************/
0768 
0769 static ACPI_STATUS
0770 AcpiHwWriteMultiple (
0771     UINT32                  Value,
0772     ACPI_GENERIC_ADDRESS    *RegisterA,
0773     ACPI_GENERIC_ADDRESS    *RegisterB)
0774 {
0775     ACPI_STATUS             Status;
0776 
0777 
0778     /* The first register is always required */
0779 
0780     Status = AcpiHwWrite (Value, RegisterA);
0781     if (ACPI_FAILURE (Status))
0782     {
0783         return (Status);
0784     }
0785 
0786     /*
0787      * Second register is optional
0788      *
0789      * No bit shifting or clearing is necessary, because of how the PM1
0790      * registers are defined in the ACPI specification:
0791      *
0792      * "Although the bits can be split between the two register blocks (each
0793      * register block has a unique pointer within the FADT), the bit positions
0794      * are maintained. The register block with unimplemented bits (that is,
0795      * those implemented in the other register block) always returns zeros,
0796      * and writes have no side effects"
0797      */
0798     if (RegisterB->Address)
0799     {
0800         Status = AcpiHwWrite (Value, RegisterB);
0801     }
0802 
0803     return (Status);
0804 }
0805