]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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 - 2005, R. Byron Moore | |
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 | #include <linux/module.h> | |
47 | ||
48 | #include <acpi/acpi.h> | |
49 | #include <acpi/acnamesp.h> | |
50 | #include <acpi/acevents.h> | |
51 | ||
52 | #define _COMPONENT ACPI_HARDWARE | |
53 | ACPI_MODULE_NAME ("hwregs") | |
54 | ||
55 | ||
56 | /******************************************************************************* | |
57 | * | |
58 | * FUNCTION: acpi_hw_clear_acpi_status | |
59 | * | |
60 | * PARAMETERS: Flags - Lock the hardware or not | |
61 | * | |
62 | * RETURN: none | |
63 | * | |
64 | * DESCRIPTION: Clears all fixed and general purpose status bits | |
65 | * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED | |
66 | * | |
67 | ******************************************************************************/ | |
68 | ||
69 | acpi_status | |
70 | acpi_hw_clear_acpi_status ( | |
71 | u32 flags) | |
72 | { | |
73 | acpi_status status; | |
74 | ||
75 | ||
76 | ACPI_FUNCTION_TRACE ("hw_clear_acpi_status"); | |
77 | ||
78 | ||
79 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %04X\n", | |
80 | ACPI_BITMASK_ALL_FIXED_STATUS, | |
81 | (u16) acpi_gbl_FADT->xpm1a_evt_blk.address)); | |
82 | ||
83 | if (flags & ACPI_MTX_LOCK) { | |
84 | status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); | |
85 | if (ACPI_FAILURE (status)) { | |
86 | return_ACPI_STATUS (status); | |
87 | } | |
88 | } | |
89 | ||
90 | status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, | |
91 | ACPI_BITMASK_ALL_FIXED_STATUS); | |
92 | if (ACPI_FAILURE (status)) { | |
93 | goto unlock_and_exit; | |
94 | } | |
95 | ||
96 | /* Clear the fixed events */ | |
97 | ||
98 | if (acpi_gbl_FADT->xpm1b_evt_blk.address) { | |
99 | status = acpi_hw_low_level_write (16, ACPI_BITMASK_ALL_FIXED_STATUS, | |
100 | &acpi_gbl_FADT->xpm1b_evt_blk); | |
101 | if (ACPI_FAILURE (status)) { | |
102 | goto unlock_and_exit; | |
103 | } | |
104 | } | |
105 | ||
106 | /* Clear the GPE Bits in all GPE registers in all GPE blocks */ | |
107 | ||
108 | status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, ACPI_ISR); | |
109 | ||
110 | unlock_and_exit: | |
111 | if (flags & ACPI_MTX_LOCK) { | |
112 | (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); | |
113 | } | |
114 | return_ACPI_STATUS (status); | |
115 | } | |
116 | ||
117 | ||
118 | /******************************************************************************* | |
119 | * | |
120 | * FUNCTION: acpi_get_sleep_type_data | |
121 | * | |
122 | * PARAMETERS: sleep_state - Numeric sleep state | |
123 | * *sleep_type_a - Where SLP_TYPa is returned | |
124 | * *sleep_type_b - Where SLP_TYPb is returned | |
125 | * | |
126 | * RETURN: Status - ACPI status | |
127 | * | |
128 | * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep | |
129 | * state. | |
130 | * | |
131 | ******************************************************************************/ | |
132 | ||
133 | acpi_status | |
134 | acpi_get_sleep_type_data ( | |
135 | u8 sleep_state, | |
136 | u8 *sleep_type_a, | |
137 | u8 *sleep_type_b) | |
138 | { | |
139 | acpi_status status = AE_OK; | |
140 | struct acpi_parameter_info info; | |
141 | ||
142 | ||
143 | ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data"); | |
144 | ||
145 | ||
146 | /* | |
147 | * Validate parameters | |
148 | */ | |
149 | if ((sleep_state > ACPI_S_STATES_MAX) || | |
150 | !sleep_type_a || !sleep_type_b) { | |
151 | return_ACPI_STATUS (AE_BAD_PARAMETER); | |
152 | } | |
153 | ||
154 | /* | |
155 | * Evaluate the namespace object containing the values for this state | |
156 | */ | |
157 | info.parameters = NULL; | |
158 | status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state], | |
159 | &info); | |
160 | if (ACPI_FAILURE (status)) { | |
161 | ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n", | |
162 | acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state])); | |
163 | ||
164 | return_ACPI_STATUS (status); | |
165 | } | |
166 | ||
167 | /* Must have a return object */ | |
168 | ||
169 | if (!info.return_object) { | |
170 | ACPI_REPORT_ERROR (("Missing Sleep State object\n")); | |
171 | status = AE_NOT_EXIST; | |
172 | } | |
173 | ||
174 | /* It must be of type Package */ | |
175 | ||
176 | else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) { | |
177 | ACPI_REPORT_ERROR (("Sleep State object not a Package\n")); | |
178 | status = AE_AML_OPERAND_TYPE; | |
179 | } | |
180 | ||
181 | /* The package must have at least two elements */ | |
182 | ||
183 | else if (info.return_object->package.count < 2) { | |
184 | ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n")); | |
185 | status = AE_AML_NO_OPERAND; | |
186 | } | |
187 | ||
188 | /* The first two elements must both be of type Integer */ | |
189 | ||
190 | else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) != ACPI_TYPE_INTEGER) || | |
191 | (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) { | |
192 | ACPI_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n", | |
193 | acpi_ut_get_object_type_name (info.return_object->package.elements[0]), | |
194 | acpi_ut_get_object_type_name (info.return_object->package.elements[1]))); | |
195 | status = AE_AML_OPERAND_TYPE; | |
196 | } | |
197 | else { | |
198 | /* | |
199 | * Valid _Sx_ package size, type, and value | |
200 | */ | |
201 | *sleep_type_a = (u8) (info.return_object->package.elements[0])->integer.value; | |
202 | *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value; | |
203 | } | |
204 | ||
205 | if (ACPI_FAILURE (status)) { | |
206 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
207 | "While evaluating sleep_state [%s], bad Sleep object %p type %s\n", | |
208 | acpi_gbl_sleep_state_names[sleep_state], info.return_object, | |
209 | acpi_ut_get_object_type_name (info.return_object))); | |
210 | } | |
211 | ||
212 | acpi_ut_remove_reference (info.return_object); | |
213 | return_ACPI_STATUS (status); | |
214 | } | |
215 | EXPORT_SYMBOL(acpi_get_sleep_type_data); | |
216 | ||
217 | ||
218 | /******************************************************************************* | |
219 | * | |
220 | * FUNCTION: acpi_hw_get_register_bit_mask | |
221 | * | |
222 | * PARAMETERS: register_id - Index of ACPI Register to access | |
223 | * | |
224 | * RETURN: The bit mask to be used when accessing the register | |
225 | * | |
226 | * DESCRIPTION: Map register_id into a register bit mask. | |
227 | * | |
228 | ******************************************************************************/ | |
229 | ||
230 | struct acpi_bit_register_info * | |
231 | acpi_hw_get_bit_register_info ( | |
232 | u32 register_id) | |
233 | { | |
234 | ACPI_FUNCTION_NAME ("hw_get_bit_register_info"); | |
235 | ||
236 | ||
237 | if (register_id > ACPI_BITREG_MAX) { | |
238 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid bit_register ID: %X\n", register_id)); | |
239 | return (NULL); | |
240 | } | |
241 | ||
242 | return (&acpi_gbl_bit_register_info[register_id]); | |
243 | } | |
244 | ||
245 | ||
246 | /******************************************************************************* | |
247 | * | |
248 | * FUNCTION: acpi_get_register | |
249 | * | |
250 | * PARAMETERS: register_id - ID of ACPI bit_register to access | |
251 | * return_value - Value that was read from the register | |
252 | * Flags - Lock the hardware or not | |
253 | * | |
254 | * RETURN: Status and the value read from specified Register. Value | |
255 | * returned is normalized to bit0 (is shifted all the way right) | |
256 | * | |
257 | * DESCRIPTION: ACPI bit_register read function. | |
258 | * | |
259 | ******************************************************************************/ | |
260 | ||
261 | acpi_status | |
262 | acpi_get_register ( | |
263 | u32 register_id, | |
264 | u32 *return_value, | |
265 | u32 flags) | |
266 | { | |
267 | u32 register_value = 0; | |
268 | struct acpi_bit_register_info *bit_reg_info; | |
269 | acpi_status status; | |
270 | ||
271 | ||
272 | ACPI_FUNCTION_TRACE ("acpi_get_register"); | |
273 | ||
274 | ||
275 | /* Get the info structure corresponding to the requested ACPI Register */ | |
276 | ||
277 | bit_reg_info = acpi_hw_get_bit_register_info (register_id); | |
278 | if (!bit_reg_info) { | |
279 | return_ACPI_STATUS (AE_BAD_PARAMETER); | |
280 | } | |
281 | ||
282 | if (flags & ACPI_MTX_LOCK) { | |
283 | status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); | |
284 | if (ACPI_FAILURE (status)) { | |
285 | return_ACPI_STATUS (status); | |
286 | } | |
287 | } | |
288 | ||
289 | /* Read from the register */ | |
290 | ||
291 | status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, | |
292 | bit_reg_info->parent_register, ®ister_value); | |
293 | ||
294 | if (flags & ACPI_MTX_LOCK) { | |
295 | (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); | |
296 | } | |
297 | ||
298 | if (ACPI_SUCCESS (status)) { | |
299 | /* Normalize the value that was read */ | |
300 | ||
301 | register_value = ((register_value & bit_reg_info->access_bit_mask) | |
302 | >> bit_reg_info->bit_position); | |
303 | ||
304 | *return_value = register_value; | |
305 | ||
306 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %8.8X register %X\n", | |
307 | register_value, bit_reg_info->parent_register)); | |
308 | } | |
309 | ||
310 | return_ACPI_STATUS (status); | |
311 | } | |
312 | EXPORT_SYMBOL(acpi_get_register); | |
313 | ||
314 | ||
315 | /******************************************************************************* | |
316 | * | |
317 | * FUNCTION: acpi_set_register | |
318 | * | |
319 | * PARAMETERS: register_id - ID of ACPI bit_register to access | |
320 | * Value - (only used on write) value to write to the | |
321 | * Register, NOT pre-normalized to the bit pos | |
322 | * Flags - Lock the hardware or not | |
323 | * | |
324 | * RETURN: Status | |
325 | * | |
326 | * DESCRIPTION: ACPI Bit Register write function. | |
327 | * | |
328 | ******************************************************************************/ | |
329 | ||
330 | acpi_status | |
331 | acpi_set_register ( | |
332 | u32 register_id, | |
333 | u32 value, | |
334 | u32 flags) | |
335 | { | |
336 | u32 register_value = 0; | |
337 | struct acpi_bit_register_info *bit_reg_info; | |
338 | acpi_status status; | |
339 | ||
340 | ||
341 | ACPI_FUNCTION_TRACE_U32 ("acpi_set_register", register_id); | |
342 | ||
343 | ||
344 | /* Get the info structure corresponding to the requested ACPI Register */ | |
345 | ||
346 | bit_reg_info = acpi_hw_get_bit_register_info (register_id); | |
347 | if (!bit_reg_info) { | |
348 | ACPI_REPORT_ERROR (("Bad ACPI HW register_id: %X\n", register_id)); | |
349 | return_ACPI_STATUS (AE_BAD_PARAMETER); | |
350 | } | |
351 | ||
352 | if (flags & ACPI_MTX_LOCK) { | |
353 | status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); | |
354 | if (ACPI_FAILURE (status)) { | |
355 | return_ACPI_STATUS (status); | |
356 | } | |
357 | } | |
358 | ||
359 | /* Always do a register read first so we can insert the new bits */ | |
360 | ||
361 | status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, | |
362 | bit_reg_info->parent_register, ®ister_value); | |
363 | if (ACPI_FAILURE (status)) { | |
364 | goto unlock_and_exit; | |
365 | } | |
366 | ||
367 | /* | |
368 | * Decode the Register ID | |
369 | * Register ID = [Register block ID] | [bit ID] | |
370 | * | |
371 | * Check bit ID to fine locate Register offset. | |
372 | * Check Mask to determine Register offset, and then read-write. | |
373 | */ | |
374 | switch (bit_reg_info->parent_register) { | |
375 | case ACPI_REGISTER_PM1_STATUS: | |
376 | ||
377 | /* | |
378 | * Status Registers are different from the rest. Clear by | |
379 | * writing 1, and writing 0 has no effect. So, the only relevant | |
380 | * information is the single bit we're interested in, all others should | |
381 | * be written as 0 so they will be left unchanged. | |
382 | */ | |
383 | value = ACPI_REGISTER_PREPARE_BITS (value, | |
384 | bit_reg_info->bit_position, bit_reg_info->access_bit_mask); | |
385 | if (value) { | |
386 | status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, | |
387 | ACPI_REGISTER_PM1_STATUS, (u16) value); | |
388 | register_value = 0; | |
389 | } | |
390 | break; | |
391 | ||
392 | ||
393 | case ACPI_REGISTER_PM1_ENABLE: | |
394 | ||
395 | ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, | |
396 | bit_reg_info->access_bit_mask, value); | |
397 | ||
398 | status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, | |
399 | ACPI_REGISTER_PM1_ENABLE, (u16) register_value); | |
400 | break; | |
401 | ||
402 | ||
403 | case ACPI_REGISTER_PM1_CONTROL: | |
404 | ||
405 | /* | |
406 | * Write the PM1 Control register. | |
407 | * Note that at this level, the fact that there are actually TWO | |
408 | * registers (A and B - and B may not exist) is abstracted. | |
409 | */ | |
410 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM1 control: Read %X\n", register_value)); | |
411 | ||
412 | ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, | |
413 | bit_reg_info->access_bit_mask, value); | |
414 | ||
415 | status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, | |
416 | ACPI_REGISTER_PM1_CONTROL, (u16) register_value); | |
417 | break; | |
418 | ||
419 | ||
420 | case ACPI_REGISTER_PM2_CONTROL: | |
421 | ||
422 | status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, | |
423 | ACPI_REGISTER_PM2_CONTROL, ®ister_value); | |
424 | if (ACPI_FAILURE (status)) { | |
425 | goto unlock_and_exit; | |
426 | } | |
427 | ||
428 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n", | |
429 | register_value, | |
430 | ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); | |
431 | ||
432 | ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position, | |
433 | bit_reg_info->access_bit_mask, value); | |
434 | ||
435 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n", | |
436 | register_value, | |
437 | ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address))); | |
438 | ||
439 | status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, | |
440 | ACPI_REGISTER_PM2_CONTROL, (u8) (register_value)); | |
441 | break; | |
442 | ||
443 | ||
444 | default: | |
445 | break; | |
446 | } | |
447 | ||
448 | ||
449 | unlock_and_exit: | |
450 | ||
451 | if (flags & ACPI_MTX_LOCK) { | |
452 | (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); | |
453 | } | |
454 | ||
455 | /* Normalize the value that was read */ | |
456 | ||
457 | ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position)); | |
458 | ||
459 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n", | |
460 | value, register_value, bit_reg_info->parent_register)); | |
461 | return_ACPI_STATUS (status); | |
462 | } | |
463 | EXPORT_SYMBOL(acpi_set_register); | |
464 | ||
465 | ||
466 | /****************************************************************************** | |
467 | * | |
468 | * FUNCTION: acpi_hw_register_read | |
469 | * | |
470 | * PARAMETERS: use_lock - Mutex hw access | |
471 | * register_id - register_iD + Offset | |
472 | * return_value - Value that was read from the register | |
473 | * | |
474 | * RETURN: Status and the value read. | |
475 | * | |
476 | * DESCRIPTION: Acpi register read function. Registers are read at the | |
477 | * given offset. | |
478 | * | |
479 | ******************************************************************************/ | |
480 | ||
481 | acpi_status | |
482 | acpi_hw_register_read ( | |
483 | u8 use_lock, | |
484 | u32 register_id, | |
485 | u32 *return_value) | |
486 | { | |
487 | u32 value1 = 0; | |
488 | u32 value2 = 0; | |
489 | acpi_status status; | |
490 | ||
491 | ||
492 | ACPI_FUNCTION_TRACE ("hw_register_read"); | |
493 | ||
494 | ||
495 | if (ACPI_MTX_LOCK == use_lock) { | |
496 | status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); | |
497 | if (ACPI_FAILURE (status)) { | |
498 | return_ACPI_STATUS (status); | |
499 | } | |
500 | } | |
501 | ||
502 | switch (register_id) { | |
503 | case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ | |
504 | ||
505 | status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->xpm1a_evt_blk); | |
506 | if (ACPI_FAILURE (status)) { | |
507 | goto unlock_and_exit; | |
508 | } | |
509 | ||
510 | /* PM1B is optional */ | |
511 | ||
512 | status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->xpm1b_evt_blk); | |
513 | value1 |= value2; | |
514 | break; | |
515 | ||
516 | ||
517 | case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */ | |
518 | ||
519 | status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_xpm1a_enable); | |
520 | if (ACPI_FAILURE (status)) { | |
521 | goto unlock_and_exit; | |
522 | } | |
523 | ||
524 | /* PM1B is optional */ | |
525 | ||
526 | status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_xpm1b_enable); | |
527 | value1 |= value2; | |
528 | break; | |
529 | ||
530 | ||
531 | case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ | |
532 | ||
533 | status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->xpm1a_cnt_blk); | |
534 | if (ACPI_FAILURE (status)) { | |
535 | goto unlock_and_exit; | |
536 | } | |
537 | ||
538 | status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->xpm1b_cnt_blk); | |
539 | value1 |= value2; | |
540 | break; | |
541 | ||
542 | ||
543 | case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ | |
544 | ||
545 | status = acpi_hw_low_level_read (8, &value1, &acpi_gbl_FADT->xpm2_cnt_blk); | |
546 | break; | |
547 | ||
548 | ||
549 | case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ | |
550 | ||
551 | status = acpi_hw_low_level_read (32, &value1, &acpi_gbl_FADT->xpm_tmr_blk); | |
552 | break; | |
553 | ||
554 | case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ | |
555 | ||
556 | status = acpi_os_read_port (acpi_gbl_FADT->smi_cmd, &value1, 8); | |
557 | break; | |
558 | ||
559 | default: | |
560 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", register_id)); | |
561 | status = AE_BAD_PARAMETER; | |
562 | break; | |
563 | } | |
564 | ||
565 | unlock_and_exit: | |
566 | if (ACPI_MTX_LOCK == use_lock) { | |
567 | (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); | |
568 | } | |
569 | ||
570 | if (ACPI_SUCCESS (status)) { | |
571 | *return_value = value1; | |
572 | } | |
573 | ||
574 | return_ACPI_STATUS (status); | |
575 | } | |
576 | ||
577 | ||
578 | /****************************************************************************** | |
579 | * | |
580 | * FUNCTION: acpi_hw_register_write | |
581 | * | |
582 | * PARAMETERS: use_lock - Mutex hw access | |
583 | * register_id - register_iD + Offset | |
584 | * Value - The value to write | |
585 | * | |
586 | * RETURN: Status | |
587 | * | |
588 | * DESCRIPTION: Acpi register Write function. Registers are written at the | |
589 | * given offset. | |
590 | * | |
591 | ******************************************************************************/ | |
592 | ||
593 | acpi_status | |
594 | acpi_hw_register_write ( | |
595 | u8 use_lock, | |
596 | u32 register_id, | |
597 | u32 value) | |
598 | { | |
599 | acpi_status status; | |
600 | ||
601 | ||
602 | ACPI_FUNCTION_TRACE ("hw_register_write"); | |
603 | ||
604 | ||
605 | if (ACPI_MTX_LOCK == use_lock) { | |
606 | status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE); | |
607 | if (ACPI_FAILURE (status)) { | |
608 | return_ACPI_STATUS (status); | |
609 | } | |
610 | } | |
611 | ||
612 | switch (register_id) { | |
613 | case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */ | |
614 | ||
615 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_evt_blk); | |
616 | if (ACPI_FAILURE (status)) { | |
617 | goto unlock_and_exit; | |
618 | } | |
619 | ||
620 | /* PM1B is optional */ | |
621 | ||
622 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_evt_blk); | |
623 | break; | |
624 | ||
625 | ||
626 | case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access*/ | |
627 | ||
628 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_xpm1a_enable); | |
629 | if (ACPI_FAILURE (status)) { | |
630 | goto unlock_and_exit; | |
631 | } | |
632 | ||
633 | /* PM1B is optional */ | |
634 | ||
635 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_xpm1b_enable); | |
636 | break; | |
637 | ||
638 | ||
639 | case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */ | |
640 | ||
641 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_cnt_blk); | |
642 | if (ACPI_FAILURE (status)) { | |
643 | goto unlock_and_exit; | |
644 | } | |
645 | ||
646 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_cnt_blk); | |
647 | break; | |
648 | ||
649 | ||
650 | case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */ | |
651 | ||
652 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_cnt_blk); | |
653 | break; | |
654 | ||
655 | ||
656 | case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */ | |
657 | ||
658 | status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_cnt_blk); | |
659 | break; | |
660 | ||
661 | ||
662 | case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */ | |
663 | ||
664 | status = acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->xpm2_cnt_blk); | |
665 | break; | |
666 | ||
667 | ||
668 | case ACPI_REGISTER_PM_TIMER: /* 32-bit access */ | |
669 | ||
670 | status = acpi_hw_low_level_write (32, value, &acpi_gbl_FADT->xpm_tmr_blk); | |
671 | break; | |
672 | ||
673 | ||
674 | case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */ | |
675 | ||
676 | /* SMI_CMD is currently always in IO space */ | |
677 | ||
678 | status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, value, 8); | |
679 | break; | |
680 | ||
681 | ||
682 | default: | |
683 | status = AE_BAD_PARAMETER; | |
684 | break; | |
685 | } | |
686 | ||
687 | unlock_and_exit: | |
688 | if (ACPI_MTX_LOCK == use_lock) { | |
689 | (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE); | |
690 | } | |
691 | ||
692 | return_ACPI_STATUS (status); | |
693 | } | |
694 | ||
695 | ||
696 | /****************************************************************************** | |
697 | * | |
698 | * FUNCTION: acpi_hw_low_level_read | |
699 | * | |
700 | * PARAMETERS: Width - 8, 16, or 32 | |
701 | * Value - Where the value is returned | |
702 | * Reg - GAS register structure | |
703 | * | |
704 | * RETURN: Status | |
705 | * | |
706 | * DESCRIPTION: Read from either memory or IO space. | |
707 | * | |
708 | ******************************************************************************/ | |
709 | ||
710 | acpi_status | |
711 | acpi_hw_low_level_read ( | |
712 | u32 width, | |
713 | u32 *value, | |
714 | struct acpi_generic_address *reg) | |
715 | { | |
716 | u64 address; | |
717 | acpi_status status; | |
718 | ||
719 | ||
720 | ACPI_FUNCTION_NAME ("hw_low_level_read"); | |
721 | ||
722 | ||
723 | /* | |
724 | * Must have a valid pointer to a GAS structure, and | |
725 | * a non-zero address within. However, don't return an error | |
726 | * because the PM1A/B code must not fail if B isn't present. | |
727 | */ | |
728 | if (!reg) { | |
729 | return (AE_OK); | |
730 | } | |
731 | ||
732 | /* Get a local copy of the address. Handles possible alignment issues */ | |
733 | ||
734 | ACPI_MOVE_64_TO_64 (&address, ®->address); | |
735 | if (!address) { | |
736 | return (AE_OK); | |
737 | } | |
738 | *value = 0; | |
739 | ||
740 | /* | |
741 | * Two address spaces supported: Memory or IO. | |
742 | * PCI_Config is not supported here because the GAS struct is insufficient | |
743 | */ | |
744 | switch (reg->address_space_id) { | |
745 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | |
746 | ||
747 | status = acpi_os_read_memory ( | |
748 | (acpi_physical_address) address, | |
749 | value, width); | |
750 | break; | |
751 | ||
752 | ||
753 | case ACPI_ADR_SPACE_SYSTEM_IO: | |
754 | ||
755 | status = acpi_os_read_port ((acpi_io_address) address, | |
756 | value, width); | |
757 | break; | |
758 | ||
759 | ||
760 | default: | |
761 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
762 | "Unsupported address space: %X\n", reg->address_space_id)); | |
763 | return (AE_BAD_PARAMETER); | |
764 | } | |
765 | ||
766 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", | |
767 | *value, width, | |
768 | ACPI_FORMAT_UINT64 (address), | |
769 | acpi_ut_get_region_name (reg->address_space_id))); | |
770 | ||
771 | return (status); | |
772 | } | |
773 | ||
774 | ||
775 | /****************************************************************************** | |
776 | * | |
777 | * FUNCTION: acpi_hw_low_level_write | |
778 | * | |
779 | * PARAMETERS: Width - 8, 16, or 32 | |
780 | * Value - To be written | |
781 | * Reg - GAS register structure | |
782 | * | |
783 | * RETURN: Status | |
784 | * | |
785 | * DESCRIPTION: Write to either memory or IO space. | |
786 | * | |
787 | ******************************************************************************/ | |
788 | ||
789 | acpi_status | |
790 | acpi_hw_low_level_write ( | |
791 | u32 width, | |
792 | u32 value, | |
793 | struct acpi_generic_address *reg) | |
794 | { | |
795 | u64 address; | |
796 | acpi_status status; | |
797 | ||
798 | ||
799 | ACPI_FUNCTION_NAME ("hw_low_level_write"); | |
800 | ||
801 | ||
802 | /* | |
803 | * Must have a valid pointer to a GAS structure, and | |
804 | * a non-zero address within. However, don't return an error | |
805 | * because the PM1A/B code must not fail if B isn't present. | |
806 | */ | |
807 | if (!reg) { | |
808 | return (AE_OK); | |
809 | } | |
810 | ||
811 | /* Get a local copy of the address. Handles possible alignment issues */ | |
812 | ||
813 | ACPI_MOVE_64_TO_64 (&address, ®->address); | |
814 | if (!address) { | |
815 | return (AE_OK); | |
816 | } | |
817 | ||
818 | /* | |
819 | * Two address spaces supported: Memory or IO. | |
820 | * PCI_Config is not supported here because the GAS struct is insufficient | |
821 | */ | |
822 | switch (reg->address_space_id) { | |
823 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | |
824 | ||
825 | status = acpi_os_write_memory ( | |
826 | (acpi_physical_address) address, | |
827 | value, width); | |
828 | break; | |
829 | ||
830 | ||
831 | case ACPI_ADR_SPACE_SYSTEM_IO: | |
832 | ||
833 | status = acpi_os_write_port ((acpi_io_address) address, | |
834 | value, width); | |
835 | break; | |
836 | ||
837 | ||
838 | default: | |
839 | ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, | |
840 | "Unsupported address space: %X\n", reg->address_space_id)); | |
841 | return (AE_BAD_PARAMETER); | |
842 | } | |
843 | ||
844 | ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", | |
845 | value, width, | |
846 | ACPI_FORMAT_UINT64 (address), | |
847 | acpi_ut_get_region_name (reg->address_space_id))); | |
848 | ||
849 | return (status); | |
850 | } |