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 - 2016, 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 | * |
74 | * FUNCTION: AcpiHwValidateRegister |
75 | * |
76 | * PARAMETERS: Reg - GAS register structure |
77 | * MaxBitWidth - Max BitWidth supported (32 or 64) |
78 | * Address - Pointer to where the gas->address |
79 | * is returned |
80 | * |
81 | * RETURN: Status |
82 | * |
83 | * DESCRIPTION: Validate the contents of a GAS register. Checks the GAS |
84 | * pointer, Address, SpaceId, BitWidth, and BitOffset. |
85 | * |
86 | ******************************************************************************/ |
87 | |
88 | ACPI_STATUS |
89 | AcpiHwValidateRegister ( |
90 | ACPI_GENERIC_ADDRESS *Reg, |
91 | UINT8 MaxBitWidth, |
92 | UINT64 *Address) |
93 | { |
94 | |
95 | /* Must have a valid pointer to a GAS structure */ |
96 | |
97 | if (!Reg) |
98 | { |
99 | return (AE_BAD_PARAMETER); |
100 | } |
101 | |
102 | /* |
103 | * Copy the target address. This handles possible alignment issues. |
104 | * Address must not be null. A null address also indicates an optional |
105 | * ACPI register that is not supported, so no error message. |
106 | */ |
107 | ACPI_MOVE_64_TO_64 (Address, &Reg->Address); |
108 | if (!(*Address)) |
109 | { |
110 | return (AE_BAD_ADDRESS); |
111 | } |
112 | |
113 | /* Validate the SpaceID */ |
114 | |
115 | if ((Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) && |
116 | (Reg->SpaceId != ACPI_ADR_SPACE_SYSTEM_IO)) |
117 | { |
118 | ACPI_ERROR ((AE_INFO, |
119 | "Unsupported address space: 0x%X" , Reg->SpaceId)); |
120 | return (AE_SUPPORT); |
121 | } |
122 | |
123 | /* Validate the BitWidth */ |
124 | |
125 | if ((Reg->BitWidth != 8) && |
126 | (Reg->BitWidth != 16) && |
127 | (Reg->BitWidth != 32) && |
128 | (Reg->BitWidth != MaxBitWidth)) |
129 | { |
130 | ACPI_ERROR ((AE_INFO, |
131 | "Unsupported register bit width: 0x%X" , Reg->BitWidth)); |
132 | return (AE_SUPPORT); |
133 | } |
134 | |
135 | /* Validate the BitOffset. Just a warning for now. */ |
136 | |
137 | if (Reg->BitOffset != 0) |
138 | { |
139 | ACPI_WARNING ((AE_INFO, |
140 | "Unsupported register bit offset: 0x%X" , Reg->BitOffset)); |
141 | } |
142 | |
143 | return (AE_OK); |
144 | } |
145 | |
146 | |
147 | /****************************************************************************** |
148 | * |
149 | * FUNCTION: AcpiHwRead |
150 | * |
151 | * PARAMETERS: Value - Where the value is returned |
152 | * Reg - GAS register structure |
153 | * |
154 | * RETURN: Status |
155 | * |
156 | * DESCRIPTION: Read from either memory or IO space. This is a 32-bit max |
157 | * version of AcpiRead, used internally since the overhead of |
158 | * 64-bit values is not needed. |
159 | * |
160 | * LIMITATIONS: <These limitations also apply to AcpiHwWrite> |
161 | * BitWidth must be exactly 8, 16, or 32. |
162 | * SpaceID must be SystemMemory or SystemIO. |
163 | * BitOffset and AccessWidth are currently ignored, as there has |
164 | * not been a need to implement these. |
165 | * |
166 | ******************************************************************************/ |
167 | |
168 | ACPI_STATUS |
169 | AcpiHwRead ( |
170 | UINT32 *Value, |
171 | ACPI_GENERIC_ADDRESS *Reg) |
172 | { |
173 | UINT64 Address; |
174 | UINT64 Value64; |
175 | ACPI_STATUS Status; |
176 | |
177 | |
178 | ACPI_FUNCTION_NAME (HwRead); |
179 | |
180 | |
181 | /* Validate contents of the GAS register */ |
182 | |
183 | Status = AcpiHwValidateRegister (Reg, 32, &Address); |
184 | if (ACPI_FAILURE (Status)) |
185 | { |
186 | return (Status); |
187 | } |
188 | |
189 | /* Initialize entire 32-bit return value to zero */ |
190 | |
191 | *Value = 0; |
192 | |
193 | /* |
194 | * Two address spaces supported: Memory or IO. PCI_Config is |
195 | * not supported here because the GAS structure is insufficient |
196 | */ |
197 | if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) |
198 | { |
199 | Status = AcpiOsReadMemory ((ACPI_PHYSICAL_ADDRESS) |
200 | Address, &Value64, Reg->BitWidth); |
201 | |
202 | *Value = (UINT32) Value64; |
203 | } |
204 | else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ |
205 | { |
206 | Status = AcpiHwReadPort ((ACPI_IO_ADDRESS) |
207 | Address, Value, Reg->BitWidth); |
208 | } |
209 | |
210 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, |
211 | "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n" , |
212 | *Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), |
213 | AcpiUtGetRegionName (Reg->SpaceId))); |
214 | |
215 | return (Status); |
216 | } |
217 | |
218 | |
219 | /****************************************************************************** |
220 | * |
221 | * FUNCTION: AcpiHwWrite |
222 | * |
223 | * PARAMETERS: Value - Value to be written |
224 | * Reg - GAS register structure |
225 | * |
226 | * RETURN: Status |
227 | * |
228 | * DESCRIPTION: Write to either memory or IO space. This is a 32-bit max |
229 | * version of AcpiWrite, used internally since the overhead of |
230 | * 64-bit values is not needed. |
231 | * |
232 | ******************************************************************************/ |
233 | |
234 | ACPI_STATUS |
235 | AcpiHwWrite ( |
236 | UINT32 Value, |
237 | ACPI_GENERIC_ADDRESS *Reg) |
238 | { |
239 | UINT64 Address; |
240 | ACPI_STATUS Status; |
241 | |
242 | |
243 | ACPI_FUNCTION_NAME (HwWrite); |
244 | |
245 | |
246 | /* Validate contents of the GAS register */ |
247 | |
248 | Status = AcpiHwValidateRegister (Reg, 32, &Address); |
249 | if (ACPI_FAILURE (Status)) |
250 | { |
251 | return (Status); |
252 | } |
253 | |
254 | /* |
255 | * Two address spaces supported: Memory or IO. PCI_Config is |
256 | * not supported here because the GAS structure is insufficient |
257 | */ |
258 | if (Reg->SpaceId == ACPI_ADR_SPACE_SYSTEM_MEMORY) |
259 | { |
260 | Status = AcpiOsWriteMemory ((ACPI_PHYSICAL_ADDRESS) |
261 | Address, (UINT64) Value, Reg->BitWidth); |
262 | } |
263 | else /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ |
264 | { |
265 | Status = AcpiHwWritePort ((ACPI_IO_ADDRESS) |
266 | Address, Value, Reg->BitWidth); |
267 | } |
268 | |
269 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, |
270 | "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n" , |
271 | Value, Reg->BitWidth, ACPI_FORMAT_UINT64 (Address), |
272 | AcpiUtGetRegionName (Reg->SpaceId))); |
273 | |
274 | return (Status); |
275 | } |
276 | |
277 | |
278 | #if (!ACPI_REDUCED_HARDWARE) |
279 | /******************************************************************************* |
280 | * |
281 | * FUNCTION: AcpiHwClearAcpiStatus |
282 | * |
283 | * PARAMETERS: None |
284 | * |
285 | * RETURN: Status |
286 | * |
287 | * DESCRIPTION: Clears all fixed and general purpose status bits |
288 | * |
289 | ******************************************************************************/ |
290 | |
291 | ACPI_STATUS |
292 | AcpiHwClearAcpiStatus ( |
293 | void) |
294 | { |
295 | ACPI_STATUS Status; |
296 | ACPI_CPU_FLAGS LockFlags = 0; |
297 | |
298 | |
299 | ACPI_FUNCTION_TRACE (HwClearAcpiStatus); |
300 | |
301 | |
302 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n" , |
303 | ACPI_BITMASK_ALL_FIXED_STATUS, |
304 | ACPI_FORMAT_UINT64 (AcpiGbl_XPm1aStatus.Address))); |
305 | |
306 | LockFlags = AcpiOsAcquireLock (AcpiGbl_HardwareLock); |
307 | |
308 | /* Clear the fixed events in PM1 A/B */ |
309 | |
310 | Status = AcpiHwRegisterWrite (ACPI_REGISTER_PM1_STATUS, |
311 | ACPI_BITMASK_ALL_FIXED_STATUS); |
312 | |
313 | AcpiOsReleaseLock (AcpiGbl_HardwareLock, LockFlags); |
314 | |
315 | if (ACPI_FAILURE (Status)) |
316 | { |
317 | goto Exit; |
318 | } |
319 | |
320 | /* Clear the GPE Bits in all GPE registers in all GPE blocks */ |
321 | |
322 | Status = AcpiEvWalkGpeList (AcpiHwClearGpeBlock, NULL); |
323 | |
324 | Exit: |
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 | case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ |
435 | |
436 | Status = AcpiHwReadMultiple (&Value, |
437 | &AcpiGbl_XPm1aEnable, |
438 | &AcpiGbl_XPm1bEnable); |
439 | break; |
440 | |
441 | case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ |
442 | |
443 | Status = AcpiHwReadMultiple (&Value, |
444 | &AcpiGbl_FADT.XPm1aControlBlock, |
445 | &AcpiGbl_FADT.XPm1bControlBlock); |
446 | |
447 | /* |
448 | * Zero the write-only bits. From the ACPI specification, "Hardware |
449 | * Write-Only Bits": "Upon reads to registers with write-only bits, |
450 | * software masks out all write-only bits." |
451 | */ |
452 | Value &= ~ACPI_PM1_CONTROL_WRITEONLY_BITS; |
453 | break; |
454 | |
455 | case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ |
456 | |
457 | Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPm2ControlBlock); |
458 | break; |
459 | |
460 | case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ |
461 | |
462 | Status = AcpiHwRead (&Value, &AcpiGbl_FADT.XPmTimerBlock); |
463 | break; |
464 | |
465 | case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ |
466 | |
467 | Status = AcpiHwReadPort (AcpiGbl_FADT.SmiCommand, &Value, 8); |
468 | break; |
469 | |
470 | default: |
471 | |
472 | ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X" , |
473 | RegisterId)); |
474 | Status = AE_BAD_PARAMETER; |
475 | break; |
476 | } |
477 | |
478 | if (ACPI_SUCCESS (Status)) |
479 | { |
480 | *ReturnValue = Value; |
481 | } |
482 | |
483 | return_ACPI_STATUS (Status); |
484 | } |
485 | |
486 | |
487 | /****************************************************************************** |
488 | * |
489 | * FUNCTION: AcpiHwRegisterWrite |
490 | * |
491 | * PARAMETERS: RegisterId - ACPI Register ID |
492 | * Value - The value to write |
493 | * |
494 | * RETURN: Status |
495 | * |
496 | * DESCRIPTION: Write to the specified ACPI register |
497 | * |
498 | * NOTE: In accordance with the ACPI specification, this function automatically |
499 | * preserves the value of the following bits, meaning that these bits cannot be |
500 | * changed via this interface: |
501 | * |
502 | * PM1_CONTROL[0] = SCI_EN |
503 | * PM1_CONTROL[9] |
504 | * PM1_STATUS[11] |
505 | * |
506 | * ACPI References: |
507 | * 1) Hardware Ignored Bits: When software writes to a register with ignored |
508 | * bit fields, it preserves the ignored bit fields |
509 | * 2) SCI_EN: OSPM always preserves this bit position |
510 | * |
511 | ******************************************************************************/ |
512 | |
513 | ACPI_STATUS |
514 | AcpiHwRegisterWrite ( |
515 | UINT32 RegisterId, |
516 | UINT32 Value) |
517 | { |
518 | ACPI_STATUS Status; |
519 | UINT32 ReadValue; |
520 | |
521 | |
522 | ACPI_FUNCTION_TRACE (HwRegisterWrite); |
523 | |
524 | |
525 | switch (RegisterId) |
526 | { |
527 | case ACPI_REGISTER_PM1_STATUS: /* PM1 A/B: 16-bit access each */ |
528 | /* |
529 | * Handle the "ignored" bit in PM1 Status. According to the ACPI |
530 | * specification, ignored bits are to be preserved when writing. |
531 | * Normally, this would mean a read/modify/write sequence. However, |
532 | * preserving a bit in the status register is different. Writing a |
533 | * one clears the status, and writing a zero preserves the status. |
534 | * Therefore, we must always write zero to the ignored bit. |
535 | * |
536 | * This behavior is clarified in the ACPI 4.0 specification. |
537 | */ |
538 | Value &= ~ACPI_PM1_STATUS_PRESERVED_BITS; |
539 | |
540 | Status = AcpiHwWriteMultiple (Value, |
541 | &AcpiGbl_XPm1aStatus, |
542 | &AcpiGbl_XPm1bStatus); |
543 | break; |
544 | |
545 | case ACPI_REGISTER_PM1_ENABLE: /* PM1 A/B: 16-bit access each */ |
546 | |
547 | Status = AcpiHwWriteMultiple (Value, |
548 | &AcpiGbl_XPm1aEnable, |
549 | &AcpiGbl_XPm1bEnable); |
550 | break; |
551 | |
552 | case ACPI_REGISTER_PM1_CONTROL: /* PM1 A/B: 16-bit access each */ |
553 | /* |
554 | * Perform a read first to preserve certain bits (per ACPI spec) |
555 | * Note: This includes SCI_EN, we never want to change this bit |
556 | */ |
557 | Status = AcpiHwReadMultiple (&ReadValue, |
558 | &AcpiGbl_FADT.XPm1aControlBlock, |
559 | &AcpiGbl_FADT.XPm1bControlBlock); |
560 | if (ACPI_FAILURE (Status)) |
561 | { |
562 | goto Exit; |
563 | } |
564 | |
565 | /* Insert the bits to be preserved */ |
566 | |
567 | ACPI_INSERT_BITS (Value, ACPI_PM1_CONTROL_PRESERVED_BITS, ReadValue); |
568 | |
569 | /* Now we can write the data */ |
570 | |
571 | Status = AcpiHwWriteMultiple (Value, |
572 | &AcpiGbl_FADT.XPm1aControlBlock, |
573 | &AcpiGbl_FADT.XPm1bControlBlock); |
574 | break; |
575 | |
576 | case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ |
577 | /* |
578 | * For control registers, all reserved bits must be preserved, |
579 | * as per the ACPI spec. |
580 | */ |
581 | Status = AcpiHwRead (&ReadValue, &AcpiGbl_FADT.XPm2ControlBlock); |
582 | if (ACPI_FAILURE (Status)) |
583 | { |
584 | goto Exit; |
585 | } |
586 | |
587 | /* Insert the bits to be preserved */ |
588 | |
589 | ACPI_INSERT_BITS (Value, ACPI_PM2_CONTROL_PRESERVED_BITS, ReadValue); |
590 | |
591 | Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPm2ControlBlock); |
592 | break; |
593 | |
594 | case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ |
595 | |
596 | Status = AcpiHwWrite (Value, &AcpiGbl_FADT.XPmTimerBlock); |
597 | break; |
598 | |
599 | case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ |
600 | |
601 | /* SMI_CMD is currently always in IO space */ |
602 | |
603 | Status = AcpiHwWritePort (AcpiGbl_FADT.SmiCommand, Value, 8); |
604 | break; |
605 | |
606 | default: |
607 | |
608 | ACPI_ERROR ((AE_INFO, "Unknown Register ID: 0x%X" , |
609 | RegisterId)); |
610 | Status = AE_BAD_PARAMETER; |
611 | break; |
612 | } |
613 | |
614 | Exit: |
615 | return_ACPI_STATUS (Status); |
616 | } |
617 | |
618 | |
619 | /****************************************************************************** |
620 | * |
621 | * FUNCTION: AcpiHwReadMultiple |
622 | * |
623 | * PARAMETERS: Value - Where the register value is returned |
624 | * RegisterA - First ACPI register (required) |
625 | * RegisterB - Second ACPI register (optional) |
626 | * |
627 | * RETURN: Status |
628 | * |
629 | * DESCRIPTION: Read from the specified two-part ACPI register (such as PM1 A/B) |
630 | * |
631 | ******************************************************************************/ |
632 | |
633 | static ACPI_STATUS |
634 | AcpiHwReadMultiple ( |
635 | UINT32 *Value, |
636 | ACPI_GENERIC_ADDRESS *RegisterA, |
637 | ACPI_GENERIC_ADDRESS *RegisterB) |
638 | { |
639 | UINT32 ValueA = 0; |
640 | UINT32 ValueB = 0; |
641 | ACPI_STATUS Status; |
642 | |
643 | |
644 | /* The first register is always required */ |
645 | |
646 | Status = AcpiHwRead (&ValueA, RegisterA); |
647 | if (ACPI_FAILURE (Status)) |
648 | { |
649 | return (Status); |
650 | } |
651 | |
652 | /* Second register is optional */ |
653 | |
654 | if (RegisterB->Address) |
655 | { |
656 | Status = AcpiHwRead (&ValueB, RegisterB); |
657 | if (ACPI_FAILURE (Status)) |
658 | { |
659 | return (Status); |
660 | } |
661 | } |
662 | |
663 | /* |
664 | * OR the two return values together. No shifting or masking is necessary, |
665 | * because of how the PM1 registers are defined in the ACPI specification: |
666 | * |
667 | * "Although the bits can be split between the two register blocks (each |
668 | * register block has a unique pointer within the FADT), the bit positions |
669 | * are maintained. The register block with unimplemented bits (that is, |
670 | * those implemented in the other register block) always returns zeros, |
671 | * and writes have no side effects" |
672 | */ |
673 | *Value = (ValueA | ValueB); |
674 | return (AE_OK); |
675 | } |
676 | |
677 | |
678 | /****************************************************************************** |
679 | * |
680 | * FUNCTION: AcpiHwWriteMultiple |
681 | * |
682 | * PARAMETERS: Value - The value to write |
683 | * RegisterA - First ACPI register (required) |
684 | * RegisterB - Second ACPI register (optional) |
685 | * |
686 | * RETURN: Status |
687 | * |
688 | * DESCRIPTION: Write to the specified two-part ACPI register (such as PM1 A/B) |
689 | * |
690 | ******************************************************************************/ |
691 | |
692 | static ACPI_STATUS |
693 | AcpiHwWriteMultiple ( |
694 | UINT32 Value, |
695 | ACPI_GENERIC_ADDRESS *RegisterA, |
696 | ACPI_GENERIC_ADDRESS *RegisterB) |
697 | { |
698 | ACPI_STATUS Status; |
699 | |
700 | |
701 | /* The first register is always required */ |
702 | |
703 | Status = AcpiHwWrite (Value, RegisterA); |
704 | if (ACPI_FAILURE (Status)) |
705 | { |
706 | return (Status); |
707 | } |
708 | |
709 | /* |
710 | * Second register is optional |
711 | * |
712 | * No bit shifting or clearing is necessary, because of how the PM1 |
713 | * registers are defined in the ACPI specification: |
714 | * |
715 | * "Although the bits can be split between the two register blocks (each |
716 | * register block has a unique pointer within the FADT), the bit positions |
717 | * are maintained. The register block with unimplemented bits (that is, |
718 | * those implemented in the other register block) always returns zeros, |
719 | * and writes have no side effects" |
720 | */ |
721 | if (RegisterB->Address) |
722 | { |
723 | Status = AcpiHwWrite (Value, RegisterB); |
724 | } |
725 | |
726 | return (Status); |
727 | } |
728 | |
729 | #endif /* !ACPI_REDUCED_HARDWARE */ |
730 | |