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 #include "acpi.h"
46 #include "accommon.h"
47 #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
AcpiHwValidateRegister(ACPI_GENERIC_ADDRESS * Reg,UINT8 MaxBitWidth,UINT64 * Address)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
AcpiHwRead(UINT32 * Value,ACPI_GENERIC_ADDRESS * Reg)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
AcpiHwWrite(UINT32 Value,ACPI_GENERIC_ADDRESS * Reg)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
AcpiHwClearAcpiStatus(void)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 *
AcpiHwGetBitRegisterInfo(UINT32 RegisterId)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
AcpiHwWritePm1Control(UINT32 Pm1aControl,UINT32 Pm1bControl)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
AcpiHwRegisterRead(UINT32 RegisterId,UINT32 * ReturnValue)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
AcpiHwRegisterWrite(UINT32 RegisterId,UINT32 Value)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
AcpiHwReadMultiple(UINT32 * Value,ACPI_GENERIC_ADDRESS * RegisterA,ACPI_GENERIC_ADDRESS * RegisterB)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
AcpiHwWriteMultiple(UINT32 Value,ACPI_GENERIC_ADDRESS * RegisterA,ACPI_GENERIC_ADDRESS * RegisterB)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 */
729