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