]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - sys/contrib/dev/acpica/components/hardware/hwregs.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / sys / contrib / dev / acpica / components / hardware / hwregs.c
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 - 2015, 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  * FUNCTION:    AcpiHwValidateRegister
74  *
75  * PARAMETERS:  Reg                 - GAS register structure
76  *              MaxBitWidth         - Max BitWidth supported (32 or 64)
77  *              Address             - Pointer to where the gas->address
78  *                                    is returned
79  *
80  * RETURN:      Status
81  *
82  * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS
83  *              pointer, Address, SpaceId, BitWidth, and BitOffset.
84  *
85  ******************************************************************************/
86
87 ACPI_STATUS
88 AcpiHwValidateRegister (
89     ACPI_GENERIC_ADDRESS    *Reg,
90     UINT8                   MaxBitWidth,
91     UINT64                  *Address)
92 {
93
94     /* Must have a valid pointer to a GAS structure */
95
96     if (!Reg)
97     {
98         return (AE_BAD_PARAMETER);
99     }
100
101     /*
102      * Copy the target address. This handles possible alignment issues.
103      * Address must not be null. A null address also indicates an optional
104      * ACPI register that is not supported, so no error message.
105      */
106     ACPI_MOVE_64_TO_64 (Address, &Reg->Address);
107     if (!(*Address))
108     {
109         return (AE_BAD_ADDRESS);
110     }
111
112     /* Validate the SpaceID */
113
114     if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
115         (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO))
116     {
117         ACPI_ERROR ((AE_INFO,
118             "Unsupported address space: 0x%X", Reg->SpaceId));
119         return (AE_SUPPORT);
120     }
121
122     /* Validate the BitWidth */
123
124     if ((Reg->BitWidth != 8) &&
125         (Reg->BitWidth != 16) &&
126         (Reg->BitWidth != 32) &&
127         (Reg->BitWidth != MaxBitWidth))
128     {
129         ACPI_ERROR ((AE_INFO,
130             "Unsupported register bit width: 0x%X", Reg->BitWidth));
131         return (AE_SUPPORT);
132     }
133
134     /* Validate the BitOffset. Just a warning for now. */
135
136     if (Reg->BitOffset != 0)
137     {
138         ACPI_WARNING ((AE_INFO,
139             "Unsupported register bit offset: 0x%X", Reg->BitOffset));
140     }
141
142     return (AE_OK);
143 }
144
145
146 /******************************************************************************
147  *
148  * FUNCTION:    AcpiHwRead
149  *
150  * PARAMETERS:  Value               - Where the value is returned
151  *              Reg                 - GAS register structure
152  *
153  * RETURN:      Status
154  *
155  * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max
156  *              version of AcpiRead, used internally since the overhead of
157  *              64-bit values is not needed.
158  *
159  * LIMITATIONS: <These limitations also apply to AcpiHwWrite>
160  *      BitWidth must be exactly 8, 16, or 32.
161  *      SpaceID must be SystemMemory or SystemIO.
162  *      BitOffset and AccessWidth are currently ignored, as there has
163  *          not been a need to implement these.
164  *
165  ******************************************************************************/
166
167 ACPI_STATUS
168 AcpiHwRead (
169     UINT32                  *Value,
170     ACPI_GENERIC_ADDRESS    *Reg)
171 {
172     UINT64                  Address;
173     UINT64                  Value64;
174     ACPI_STATUS             Status;
175
176
177     ACPI_FUNCTION_NAME (HwRead);
178
179
180     /* Validate contents of the GAS register */
181
182     Status = AcpiHwValidateRegister (Reg, 32, &Address);
183     if (ACPI_FAILURE (Status))
184     {
185         return (Status);
186     }
187
188     /* Initialize entire 32-bit return value to zero */
189
190     *Value = 0;
191
192     /*
193      * Two address spaces supported: Memory or IO. PCI_Config is
194      * not supported here because the GAS structure is insufficient
195      */
196     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
197     {
198         Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS)
199                     Address, &Value64, Reg->BitWidth);
200
201         *Value = (UINT32) Value64;
202     }
203     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
204     {
205         Status = AcpiHwReadPort ((ACPI_IO_ADDRESS)
206                     Address, Value, Reg->BitWidth);
207     }
208
209     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
210         "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
211         *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
212         AcpiUtGetRegionName (Reg->SpaceId)));
213
214     return (Status);
215 }
216
217
218 /******************************************************************************
219  *
220  * FUNCTION:    AcpiHwWrite
221  *
222  * PARAMETERS:  Value               - Value to be written
223  *              Reg                 - GAS register structure
224  *
225  * RETURN:      Status
226  *
227  * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max
228  *              version of AcpiWrite, used internally since the overhead of
229  *              64-bit values is not needed.
230  *
231  ******************************************************************************/
232
233 ACPI_STATUS
234 AcpiHwWrite (
235     UINT32                  Value,
236     ACPI_GENERIC_ADDRESS    *Reg)
237 {
238     UINT64                  Address;
239     ACPI_STATUS             Status;
240
241
242     ACPI_FUNCTION_NAME (HwWrite);
243
244
245     /* Validate contents of the GAS register */
246
247     Status = AcpiHwValidateRegister (Reg, 32, &Address);
248     if (ACPI_FAILURE (Status))
249     {
250         return (Status);
251     }
252
253     /*
254      * Two address spaces supported: Memory or IO. PCI_Config is
255      * not supported here because the GAS structure is insufficient
256      */
257     if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY)
258     {
259         Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS)
260                     Address, (UINT64) Value, Reg->BitWidth);
261     }
262     else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
263     {
264         Status = AcpiHwWritePort ((ACPI_IO_ADDRESS)
265                     Address, Value, Reg->BitWidth);
266     }
267
268     ACPI_DEBUG_PRINT ((ACPI_DB_IO,
269         "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
270         Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address),
271         AcpiUtGetRegionName (Reg->SpaceId)));
272
273     return (Status);
274 }
275
276
277 #if (!ACPI_REDUCED_HARDWARE)
278 /*******************************************************************************
279  *
280  * FUNCTION:    AcpiHwClearAcpiStatus
281  *
282  * PARAMETERS:  None
283  *
284  * RETURN:      Status
285  *
286  * DESCRIPTION: Clears all fixed and general purpose status bits
287  *
288  ******************************************************************************/
289
290 ACPI_STATUS
291 AcpiHwClearAcpiStatus (
292     void)
293 {
294     ACPI_STATUS             Status;
295     ACPI_CPU_FLAGS          LockFlags = 0;
296
297
298     ACPI_FUNCTION_TRACE (HwClearAcpiStatus);
299
300
301     ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n",
302         ACPI_BITMASK_ALL_FIXED_STATUS,
303         ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address)));
304
305     LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock);
306
307     /* Clear the fixed events in PM1 A/B */
308
309     Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS,
310                 ACPI_BITMASK_ALL_FIXED_STATUS);
311
312     AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags);
313
314     if (ACPI_FAILURE (Status))
315     {
316         goto Exit;
317     }
318
319     /* Clear the GPE Bits in all GPE registers in all GPE blocks */
320
321     Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL);
322
323 Exit:
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 */