diff options
Diffstat (limited to 'drivers/acpi/acpica/exoparg1.c')
-rw-r--r-- | drivers/acpi/acpica/exoparg1.c | 1050 |
1 files changed, 1050 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c new file mode 100644 index 000000000000..52d78b8622be --- /dev/null +++ b/drivers/acpi/acpica/exoparg1.c | |||
@@ -0,0 +1,1050 @@ | |||
1 | |||
2 | /****************************************************************************** | ||
3 | * | ||
4 | * Module Name: exoparg1 - AML execution - opcodes with 1 argument | ||
5 | * | ||
6 | *****************************************************************************/ | ||
7 | |||
8 | /* | ||
9 | * Copyright (C) 2000 - 2008, 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/acpi.h> | ||
46 | #include <acpi/accommon.h> | ||
47 | #include <acpi/acparser.h> | ||
48 | #include <acpi/acdispat.h> | ||
49 | #include <acpi/acinterp.h> | ||
50 | #include <acpi/amlcode.h> | ||
51 | #include <acpi/acnamesp.h> | ||
52 | |||
53 | #define _COMPONENT ACPI_EXECUTER | ||
54 | ACPI_MODULE_NAME("exoparg1") | ||
55 | |||
56 | /*! | ||
57 | * Naming convention for AML interpreter execution routines. | ||
58 | * | ||
59 | * The routines that begin execution of AML opcodes are named with a common | ||
60 | * convention based upon the number of arguments, the number of target operands, | ||
61 | * and whether or not a value is returned: | ||
62 | * | ||
63 | * AcpiExOpcode_xA_yT_zR | ||
64 | * | ||
65 | * Where: | ||
66 | * | ||
67 | * xA - ARGUMENTS: The number of arguments (input operands) that are | ||
68 | * required for this opcode type (0 through 6 args). | ||
69 | * yT - TARGETS: The number of targets (output operands) that are required | ||
70 | * for this opcode type (0, 1, or 2 targets). | ||
71 | * zR - RETURN VALUE: Indicates whether this opcode type returns a value | ||
72 | * as the function return (0 or 1). | ||
73 | * | ||
74 | * The AcpiExOpcode* functions are called via the Dispatcher component with | ||
75 | * fully resolved operands. | ||
76 | !*/ | ||
77 | /******************************************************************************* | ||
78 | * | ||
79 | * FUNCTION: acpi_ex_opcode_0A_0T_1R | ||
80 | * | ||
81 | * PARAMETERS: walk_state - Current state (contains AML opcode) | ||
82 | * | ||
83 | * RETURN: Status | ||
84 | * | ||
85 | * DESCRIPTION: Execute operator with no operands, one return value | ||
86 | * | ||
87 | ******************************************************************************/ | ||
88 | acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state) | ||
89 | { | ||
90 | acpi_status status = AE_OK; | ||
91 | union acpi_operand_object *return_desc = NULL; | ||
92 | |||
93 | ACPI_FUNCTION_TRACE_STR(ex_opcode_0A_0T_1R, | ||
94 | acpi_ps_get_opcode_name(walk_state->opcode)); | ||
95 | |||
96 | /* Examine the AML opcode */ | ||
97 | |||
98 | switch (walk_state->opcode) { | ||
99 | case AML_TIMER_OP: /* Timer () */ | ||
100 | |||
101 | /* Create a return object of type Integer */ | ||
102 | |||
103 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); | ||
104 | if (!return_desc) { | ||
105 | status = AE_NO_MEMORY; | ||
106 | goto cleanup; | ||
107 | } | ||
108 | return_desc->integer.value = acpi_os_get_timer(); | ||
109 | break; | ||
110 | |||
111 | default: /* Unknown opcode */ | ||
112 | |||
113 | ACPI_ERROR((AE_INFO, "Unknown AML opcode %X", | ||
114 | walk_state->opcode)); | ||
115 | status = AE_AML_BAD_OPCODE; | ||
116 | break; | ||
117 | } | ||
118 | |||
119 | cleanup: | ||
120 | |||
121 | /* Delete return object on error */ | ||
122 | |||
123 | if ((ACPI_FAILURE(status)) || walk_state->result_obj) { | ||
124 | acpi_ut_remove_reference(return_desc); | ||
125 | walk_state->result_obj = NULL; | ||
126 | } else { | ||
127 | /* Save the return value */ | ||
128 | |||
129 | walk_state->result_obj = return_desc; | ||
130 | } | ||
131 | |||
132 | return_ACPI_STATUS(status); | ||
133 | } | ||
134 | |||
135 | /******************************************************************************* | ||
136 | * | ||
137 | * FUNCTION: acpi_ex_opcode_1A_0T_0R | ||
138 | * | ||
139 | * PARAMETERS: walk_state - Current state (contains AML opcode) | ||
140 | * | ||
141 | * RETURN: Status | ||
142 | * | ||
143 | * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on | ||
144 | * object stack | ||
145 | * | ||
146 | ******************************************************************************/ | ||
147 | |||
148 | acpi_status acpi_ex_opcode_1A_0T_0R(struct acpi_walk_state *walk_state) | ||
149 | { | ||
150 | union acpi_operand_object **operand = &walk_state->operands[0]; | ||
151 | acpi_status status = AE_OK; | ||
152 | |||
153 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_0R, | ||
154 | acpi_ps_get_opcode_name(walk_state->opcode)); | ||
155 | |||
156 | /* Examine the AML opcode */ | ||
157 | |||
158 | switch (walk_state->opcode) { | ||
159 | case AML_RELEASE_OP: /* Release (mutex_object) */ | ||
160 | |||
161 | status = acpi_ex_release_mutex(operand[0], walk_state); | ||
162 | break; | ||
163 | |||
164 | case AML_RESET_OP: /* Reset (event_object) */ | ||
165 | |||
166 | status = acpi_ex_system_reset_event(operand[0]); | ||
167 | break; | ||
168 | |||
169 | case AML_SIGNAL_OP: /* Signal (event_object) */ | ||
170 | |||
171 | status = acpi_ex_system_signal_event(operand[0]); | ||
172 | break; | ||
173 | |||
174 | case AML_SLEEP_OP: /* Sleep (msec_time) */ | ||
175 | |||
176 | status = acpi_ex_system_do_suspend(operand[0]->integer.value); | ||
177 | break; | ||
178 | |||
179 | case AML_STALL_OP: /* Stall (usec_time) */ | ||
180 | |||
181 | status = | ||
182 | acpi_ex_system_do_stall((u32) operand[0]->integer.value); | ||
183 | break; | ||
184 | |||
185 | case AML_UNLOAD_OP: /* Unload (Handle) */ | ||
186 | |||
187 | status = acpi_ex_unload_table(operand[0]); | ||
188 | break; | ||
189 | |||
190 | default: /* Unknown opcode */ | ||
191 | |||
192 | ACPI_ERROR((AE_INFO, "Unknown AML opcode %X", | ||
193 | walk_state->opcode)); | ||
194 | status = AE_AML_BAD_OPCODE; | ||
195 | break; | ||
196 | } | ||
197 | |||
198 | return_ACPI_STATUS(status); | ||
199 | } | ||
200 | |||
201 | /******************************************************************************* | ||
202 | * | ||
203 | * FUNCTION: acpi_ex_opcode_1A_1T_0R | ||
204 | * | ||
205 | * PARAMETERS: walk_state - Current state (contains AML opcode) | ||
206 | * | ||
207 | * RETURN: Status | ||
208 | * | ||
209 | * DESCRIPTION: Execute opcode with one argument, one target, and no | ||
210 | * return value. | ||
211 | * | ||
212 | ******************************************************************************/ | ||
213 | |||
214 | acpi_status acpi_ex_opcode_1A_1T_0R(struct acpi_walk_state *walk_state) | ||
215 | { | ||
216 | acpi_status status = AE_OK; | ||
217 | union acpi_operand_object **operand = &walk_state->operands[0]; | ||
218 | |||
219 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_0R, | ||
220 | acpi_ps_get_opcode_name(walk_state->opcode)); | ||
221 | |||
222 | /* Examine the AML opcode */ | ||
223 | |||
224 | switch (walk_state->opcode) { | ||
225 | case AML_LOAD_OP: | ||
226 | |||
227 | status = acpi_ex_load_op(operand[0], operand[1], walk_state); | ||
228 | break; | ||
229 | |||
230 | default: /* Unknown opcode */ | ||
231 | |||
232 | ACPI_ERROR((AE_INFO, "Unknown AML opcode %X", | ||
233 | walk_state->opcode)); | ||
234 | status = AE_AML_BAD_OPCODE; | ||
235 | goto cleanup; | ||
236 | } | ||
237 | |||
238 | cleanup: | ||
239 | |||
240 | return_ACPI_STATUS(status); | ||
241 | } | ||
242 | |||
243 | /******************************************************************************* | ||
244 | * | ||
245 | * FUNCTION: acpi_ex_opcode_1A_1T_1R | ||
246 | * | ||
247 | * PARAMETERS: walk_state - Current state (contains AML opcode) | ||
248 | * | ||
249 | * RETURN: Status | ||
250 | * | ||
251 | * DESCRIPTION: Execute opcode with one argument, one target, and a | ||
252 | * return value. | ||
253 | * | ||
254 | ******************************************************************************/ | ||
255 | |||
256 | acpi_status acpi_ex_opcode_1A_1T_1R(struct acpi_walk_state *walk_state) | ||
257 | { | ||
258 | acpi_status status = AE_OK; | ||
259 | union acpi_operand_object **operand = &walk_state->operands[0]; | ||
260 | union acpi_operand_object *return_desc = NULL; | ||
261 | union acpi_operand_object *return_desc2 = NULL; | ||
262 | u32 temp32; | ||
263 | u32 i; | ||
264 | acpi_integer power_of_ten; | ||
265 | acpi_integer digit; | ||
266 | |||
267 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_1T_1R, | ||
268 | acpi_ps_get_opcode_name(walk_state->opcode)); | ||
269 | |||
270 | /* Examine the AML opcode */ | ||
271 | |||
272 | switch (walk_state->opcode) { | ||
273 | case AML_BIT_NOT_OP: | ||
274 | case AML_FIND_SET_LEFT_BIT_OP: | ||
275 | case AML_FIND_SET_RIGHT_BIT_OP: | ||
276 | case AML_FROM_BCD_OP: | ||
277 | case AML_TO_BCD_OP: | ||
278 | case AML_COND_REF_OF_OP: | ||
279 | |||
280 | /* Create a return object of type Integer for these opcodes */ | ||
281 | |||
282 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); | ||
283 | if (!return_desc) { | ||
284 | status = AE_NO_MEMORY; | ||
285 | goto cleanup; | ||
286 | } | ||
287 | |||
288 | switch (walk_state->opcode) { | ||
289 | case AML_BIT_NOT_OP: /* Not (Operand, Result) */ | ||
290 | |||
291 | return_desc->integer.value = ~operand[0]->integer.value; | ||
292 | break; | ||
293 | |||
294 | case AML_FIND_SET_LEFT_BIT_OP: /* find_set_left_bit (Operand, Result) */ | ||
295 | |||
296 | return_desc->integer.value = operand[0]->integer.value; | ||
297 | |||
298 | /* | ||
299 | * Acpi specification describes Integer type as a little | ||
300 | * endian unsigned value, so this boundary condition is valid. | ||
301 | */ | ||
302 | for (temp32 = 0; return_desc->integer.value && | ||
303 | temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { | ||
304 | return_desc->integer.value >>= 1; | ||
305 | } | ||
306 | |||
307 | return_desc->integer.value = temp32; | ||
308 | break; | ||
309 | |||
310 | case AML_FIND_SET_RIGHT_BIT_OP: /* find_set_right_bit (Operand, Result) */ | ||
311 | |||
312 | return_desc->integer.value = operand[0]->integer.value; | ||
313 | |||
314 | /* | ||
315 | * The Acpi specification describes Integer type as a little | ||
316 | * endian unsigned value, so this boundary condition is valid. | ||
317 | */ | ||
318 | for (temp32 = 0; return_desc->integer.value && | ||
319 | temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) { | ||
320 | return_desc->integer.value <<= 1; | ||
321 | } | ||
322 | |||
323 | /* Since the bit position is one-based, subtract from 33 (65) */ | ||
324 | |||
325 | return_desc->integer.value = | ||
326 | temp32 == | ||
327 | 0 ? 0 : (ACPI_INTEGER_BIT_SIZE + 1) - temp32; | ||
328 | break; | ||
329 | |||
330 | case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */ | ||
331 | |||
332 | /* | ||
333 | * The 64-bit ACPI integer can hold 16 4-bit BCD characters | ||
334 | * (if table is 32-bit, integer can hold 8 BCD characters) | ||
335 | * Convert each 4-bit BCD value | ||
336 | */ | ||
337 | power_of_ten = 1; | ||
338 | return_desc->integer.value = 0; | ||
339 | digit = operand[0]->integer.value; | ||
340 | |||
341 | /* Convert each BCD digit (each is one nybble wide) */ | ||
342 | |||
343 | for (i = 0; | ||
344 | (i < acpi_gbl_integer_nybble_width) && (digit > 0); | ||
345 | i++) { | ||
346 | |||
347 | /* Get the least significant 4-bit BCD digit */ | ||
348 | |||
349 | temp32 = ((u32) digit) & 0xF; | ||
350 | |||
351 | /* Check the range of the digit */ | ||
352 | |||
353 | if (temp32 > 9) { | ||
354 | ACPI_ERROR((AE_INFO, | ||
355 | "BCD digit too large (not decimal): 0x%X", | ||
356 | temp32)); | ||
357 | |||
358 | status = AE_AML_NUMERIC_OVERFLOW; | ||
359 | goto cleanup; | ||
360 | } | ||
361 | |||
362 | /* Sum the digit into the result with the current power of 10 */ | ||
363 | |||
364 | return_desc->integer.value += | ||
365 | (((acpi_integer) temp32) * power_of_ten); | ||
366 | |||
367 | /* Shift to next BCD digit */ | ||
368 | |||
369 | digit >>= 4; | ||
370 | |||
371 | /* Next power of 10 */ | ||
372 | |||
373 | power_of_ten *= 10; | ||
374 | } | ||
375 | break; | ||
376 | |||
377 | case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */ | ||
378 | |||
379 | return_desc->integer.value = 0; | ||
380 | digit = operand[0]->integer.value; | ||
381 | |||
382 | /* Each BCD digit is one nybble wide */ | ||
383 | |||
384 | for (i = 0; | ||
385 | (i < acpi_gbl_integer_nybble_width) && (digit > 0); | ||
386 | i++) { | ||
387 | (void)acpi_ut_short_divide(digit, 10, &digit, | ||
388 | &temp32); | ||
389 | |||
390 | /* | ||
391 | * Insert the BCD digit that resides in the | ||
392 | * remainder from above | ||
393 | */ | ||
394 | return_desc->integer.value |= | ||
395 | (((acpi_integer) temp32) << ACPI_MUL_4(i)); | ||
396 | } | ||
397 | |||
398 | /* Overflow if there is any data left in Digit */ | ||
399 | |||
400 | if (digit > 0) { | ||
401 | ACPI_ERROR((AE_INFO, | ||
402 | "Integer too large to convert to BCD: %8.8X%8.8X", | ||
403 | ACPI_FORMAT_UINT64(operand[0]-> | ||
404 | integer.value))); | ||
405 | status = AE_AML_NUMERIC_OVERFLOW; | ||
406 | goto cleanup; | ||
407 | } | ||
408 | break; | ||
409 | |||
410 | case AML_COND_REF_OF_OP: /* cond_ref_of (source_object, Result) */ | ||
411 | |||
412 | /* | ||
413 | * This op is a little strange because the internal return value is | ||
414 | * different than the return value stored in the result descriptor | ||
415 | * (There are really two return values) | ||
416 | */ | ||
417 | if ((struct acpi_namespace_node *)operand[0] == | ||
418 | acpi_gbl_root_node) { | ||
419 | /* | ||
420 | * This means that the object does not exist in the namespace, | ||
421 | * return FALSE | ||
422 | */ | ||
423 | return_desc->integer.value = 0; | ||
424 | goto cleanup; | ||
425 | } | ||
426 | |||
427 | /* Get the object reference, store it, and remove our reference */ | ||
428 | |||
429 | status = acpi_ex_get_object_reference(operand[0], | ||
430 | &return_desc2, | ||
431 | walk_state); | ||
432 | if (ACPI_FAILURE(status)) { | ||
433 | goto cleanup; | ||
434 | } | ||
435 | |||
436 | status = | ||
437 | acpi_ex_store(return_desc2, operand[1], walk_state); | ||
438 | acpi_ut_remove_reference(return_desc2); | ||
439 | |||
440 | /* The object exists in the namespace, return TRUE */ | ||
441 | |||
442 | return_desc->integer.value = ACPI_INTEGER_MAX; | ||
443 | goto cleanup; | ||
444 | |||
445 | default: | ||
446 | /* No other opcodes get here */ | ||
447 | break; | ||
448 | } | ||
449 | break; | ||
450 | |||
451 | case AML_STORE_OP: /* Store (Source, Target) */ | ||
452 | |||
453 | /* | ||
454 | * A store operand is typically a number, string, buffer or lvalue | ||
455 | * Be careful about deleting the source object, | ||
456 | * since the object itself may have been stored. | ||
457 | */ | ||
458 | status = acpi_ex_store(operand[0], operand[1], walk_state); | ||
459 | if (ACPI_FAILURE(status)) { | ||
460 | return_ACPI_STATUS(status); | ||
461 | } | ||
462 | |||
463 | /* It is possible that the Store already produced a return object */ | ||
464 | |||
465 | if (!walk_state->result_obj) { | ||
466 | /* | ||
467 | * Normally, we would remove a reference on the Operand[0] | ||
468 | * parameter; But since it is being used as the internal return | ||
469 | * object (meaning we would normally increment it), the two | ||
470 | * cancel out, and we simply don't do anything. | ||
471 | */ | ||
472 | walk_state->result_obj = operand[0]; | ||
473 | walk_state->operands[0] = NULL; /* Prevent deletion */ | ||
474 | } | ||
475 | return_ACPI_STATUS(status); | ||
476 | |||
477 | /* | ||
478 | * ACPI 2.0 Opcodes | ||
479 | */ | ||
480 | case AML_COPY_OP: /* Copy (Source, Target) */ | ||
481 | |||
482 | status = | ||
483 | acpi_ut_copy_iobject_to_iobject(operand[0], &return_desc, | ||
484 | walk_state); | ||
485 | break; | ||
486 | |||
487 | case AML_TO_DECSTRING_OP: /* to_decimal_string (Data, Result) */ | ||
488 | |||
489 | status = acpi_ex_convert_to_string(operand[0], &return_desc, | ||
490 | ACPI_EXPLICIT_CONVERT_DECIMAL); | ||
491 | if (return_desc == operand[0]) { | ||
492 | |||
493 | /* No conversion performed, add ref to handle return value */ | ||
494 | acpi_ut_add_reference(return_desc); | ||
495 | } | ||
496 | break; | ||
497 | |||
498 | case AML_TO_HEXSTRING_OP: /* to_hex_string (Data, Result) */ | ||
499 | |||
500 | status = acpi_ex_convert_to_string(operand[0], &return_desc, | ||
501 | ACPI_EXPLICIT_CONVERT_HEX); | ||
502 | if (return_desc == operand[0]) { | ||
503 | |||
504 | /* No conversion performed, add ref to handle return value */ | ||
505 | acpi_ut_add_reference(return_desc); | ||
506 | } | ||
507 | break; | ||
508 | |||
509 | case AML_TO_BUFFER_OP: /* to_buffer (Data, Result) */ | ||
510 | |||
511 | status = acpi_ex_convert_to_buffer(operand[0], &return_desc); | ||
512 | if (return_desc == operand[0]) { | ||
513 | |||
514 | /* No conversion performed, add ref to handle return value */ | ||
515 | acpi_ut_add_reference(return_desc); | ||
516 | } | ||
517 | break; | ||
518 | |||
519 | case AML_TO_INTEGER_OP: /* to_integer (Data, Result) */ | ||
520 | |||
521 | status = acpi_ex_convert_to_integer(operand[0], &return_desc, | ||
522 | ACPI_ANY_BASE); | ||
523 | if (return_desc == operand[0]) { | ||
524 | |||
525 | /* No conversion performed, add ref to handle return value */ | ||
526 | acpi_ut_add_reference(return_desc); | ||
527 | } | ||
528 | break; | ||
529 | |||
530 | case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */ | ||
531 | case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */ | ||
532 | |||
533 | /* These are two obsolete opcodes */ | ||
534 | |||
535 | ACPI_ERROR((AE_INFO, | ||
536 | "%s is obsolete and not implemented", | ||
537 | acpi_ps_get_opcode_name(walk_state->opcode))); | ||
538 | status = AE_SUPPORT; | ||
539 | goto cleanup; | ||
540 | |||
541 | default: /* Unknown opcode */ | ||
542 | |||
543 | ACPI_ERROR((AE_INFO, "Unknown AML opcode %X", | ||
544 | walk_state->opcode)); | ||
545 | status = AE_AML_BAD_OPCODE; | ||
546 | goto cleanup; | ||
547 | } | ||
548 | |||
549 | if (ACPI_SUCCESS(status)) { | ||
550 | |||
551 | /* Store the return value computed above into the target object */ | ||
552 | |||
553 | status = acpi_ex_store(return_desc, operand[1], walk_state); | ||
554 | } | ||
555 | |||
556 | cleanup: | ||
557 | |||
558 | /* Delete return object on error */ | ||
559 | |||
560 | if (ACPI_FAILURE(status)) { | ||
561 | acpi_ut_remove_reference(return_desc); | ||
562 | } | ||
563 | |||
564 | /* Save return object on success */ | ||
565 | |||
566 | else if (!walk_state->result_obj) { | ||
567 | walk_state->result_obj = return_desc; | ||
568 | } | ||
569 | |||
570 | return_ACPI_STATUS(status); | ||
571 | } | ||
572 | |||
573 | /******************************************************************************* | ||
574 | * | ||
575 | * FUNCTION: acpi_ex_opcode_1A_0T_1R | ||
576 | * | ||
577 | * PARAMETERS: walk_state - Current state (contains AML opcode) | ||
578 | * | ||
579 | * RETURN: Status | ||
580 | * | ||
581 | * DESCRIPTION: Execute opcode with one argument, no target, and a return value | ||
582 | * | ||
583 | ******************************************************************************/ | ||
584 | |||
585 | acpi_status acpi_ex_opcode_1A_0T_1R(struct acpi_walk_state *walk_state) | ||
586 | { | ||
587 | union acpi_operand_object **operand = &walk_state->operands[0]; | ||
588 | union acpi_operand_object *temp_desc; | ||
589 | union acpi_operand_object *return_desc = NULL; | ||
590 | acpi_status status = AE_OK; | ||
591 | u32 type; | ||
592 | acpi_integer value; | ||
593 | |||
594 | ACPI_FUNCTION_TRACE_STR(ex_opcode_1A_0T_1R, | ||
595 | acpi_ps_get_opcode_name(walk_state->opcode)); | ||
596 | |||
597 | /* Examine the AML opcode */ | ||
598 | |||
599 | switch (walk_state->opcode) { | ||
600 | case AML_LNOT_OP: /* LNot (Operand) */ | ||
601 | |||
602 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); | ||
603 | if (!return_desc) { | ||
604 | status = AE_NO_MEMORY; | ||
605 | goto cleanup; | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * Set result to ONES (TRUE) if Value == 0. Note: | ||
610 | * return_desc->Integer.Value is initially == 0 (FALSE) from above. | ||
611 | */ | ||
612 | if (!operand[0]->integer.value) { | ||
613 | return_desc->integer.value = ACPI_INTEGER_MAX; | ||
614 | } | ||
615 | break; | ||
616 | |||
617 | case AML_DECREMENT_OP: /* Decrement (Operand) */ | ||
618 | case AML_INCREMENT_OP: /* Increment (Operand) */ | ||
619 | |||
620 | /* | ||
621 | * Create a new integer. Can't just get the base integer and | ||
622 | * increment it because it may be an Arg or Field. | ||
623 | */ | ||
624 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); | ||
625 | if (!return_desc) { | ||
626 | status = AE_NO_MEMORY; | ||
627 | goto cleanup; | ||
628 | } | ||
629 | |||
630 | /* | ||
631 | * Since we are expecting a Reference operand, it can be either a | ||
632 | * NS Node or an internal object. | ||
633 | */ | ||
634 | temp_desc = operand[0]; | ||
635 | if (ACPI_GET_DESCRIPTOR_TYPE(temp_desc) == | ||
636 | ACPI_DESC_TYPE_OPERAND) { | ||
637 | |||
638 | /* Internal reference object - prevent deletion */ | ||
639 | |||
640 | acpi_ut_add_reference(temp_desc); | ||
641 | } | ||
642 | |||
643 | /* | ||
644 | * Convert the Reference operand to an Integer (This removes a | ||
645 | * reference on the Operand[0] object) | ||
646 | * | ||
647 | * NOTE: We use LNOT_OP here in order to force resolution of the | ||
648 | * reference operand to an actual integer. | ||
649 | */ | ||
650 | status = | ||
651 | acpi_ex_resolve_operands(AML_LNOT_OP, &temp_desc, | ||
652 | walk_state); | ||
653 | if (ACPI_FAILURE(status)) { | ||
654 | ACPI_EXCEPTION((AE_INFO, status, | ||
655 | "While resolving operands for [%s]", | ||
656 | acpi_ps_get_opcode_name(walk_state-> | ||
657 | opcode))); | ||
658 | |||
659 | goto cleanup; | ||
660 | } | ||
661 | |||
662 | /* | ||
663 | * temp_desc is now guaranteed to be an Integer object -- | ||
664 | * Perform the actual increment or decrement | ||
665 | */ | ||
666 | if (walk_state->opcode == AML_INCREMENT_OP) { | ||
667 | return_desc->integer.value = | ||
668 | temp_desc->integer.value + 1; | ||
669 | } else { | ||
670 | return_desc->integer.value = | ||
671 | temp_desc->integer.value - 1; | ||
672 | } | ||
673 | |||
674 | /* Finished with this Integer object */ | ||
675 | |||
676 | acpi_ut_remove_reference(temp_desc); | ||
677 | |||
678 | /* | ||
679 | * Store the result back (indirectly) through the original | ||
680 | * Reference object | ||
681 | */ | ||
682 | status = acpi_ex_store(return_desc, operand[0], walk_state); | ||
683 | break; | ||
684 | |||
685 | case AML_TYPE_OP: /* object_type (source_object) */ | ||
686 | |||
687 | /* | ||
688 | * Note: The operand is not resolved at this point because we want to | ||
689 | * get the associated object, not its value. For example, we don't | ||
690 | * want to resolve a field_unit to its value, we want the actual | ||
691 | * field_unit object. | ||
692 | */ | ||
693 | |||
694 | /* Get the type of the base object */ | ||
695 | |||
696 | status = | ||
697 | acpi_ex_resolve_multiple(walk_state, operand[0], &type, | ||
698 | NULL); | ||
699 | if (ACPI_FAILURE(status)) { | ||
700 | goto cleanup; | ||
701 | } | ||
702 | |||
703 | /* Allocate a descriptor to hold the type. */ | ||
704 | |||
705 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); | ||
706 | if (!return_desc) { | ||
707 | status = AE_NO_MEMORY; | ||
708 | goto cleanup; | ||
709 | } | ||
710 | |||
711 | return_desc->integer.value = type; | ||
712 | break; | ||
713 | |||
714 | case AML_SIZE_OF_OP: /* size_of (source_object) */ | ||
715 | |||
716 | /* | ||
717 | * Note: The operand is not resolved at this point because we want to | ||
718 | * get the associated object, not its value. | ||
719 | */ | ||
720 | |||
721 | /* Get the base object */ | ||
722 | |||
723 | status = acpi_ex_resolve_multiple(walk_state, | ||
724 | operand[0], &type, | ||
725 | &temp_desc); | ||
726 | if (ACPI_FAILURE(status)) { | ||
727 | goto cleanup; | ||
728 | } | ||
729 | |||
730 | /* | ||
731 | * The type of the base object must be integer, buffer, string, or | ||
732 | * package. All others are not supported. | ||
733 | * | ||
734 | * NOTE: Integer is not specifically supported by the ACPI spec, | ||
735 | * but is supported implicitly via implicit operand conversion. | ||
736 | * rather than bother with conversion, we just use the byte width | ||
737 | * global (4 or 8 bytes). | ||
738 | */ | ||
739 | switch (type) { | ||
740 | case ACPI_TYPE_INTEGER: | ||
741 | value = acpi_gbl_integer_byte_width; | ||
742 | break; | ||
743 | |||
744 | case ACPI_TYPE_STRING: | ||
745 | value = temp_desc->string.length; | ||
746 | break; | ||
747 | |||
748 | case ACPI_TYPE_BUFFER: | ||
749 | |||
750 | /* Buffer arguments may not be evaluated at this point */ | ||
751 | |||
752 | status = acpi_ds_get_buffer_arguments(temp_desc); | ||
753 | value = temp_desc->buffer.length; | ||
754 | break; | ||
755 | |||
756 | case ACPI_TYPE_PACKAGE: | ||
757 | |||
758 | /* Package arguments may not be evaluated at this point */ | ||
759 | |||
760 | status = acpi_ds_get_package_arguments(temp_desc); | ||
761 | value = temp_desc->package.count; | ||
762 | break; | ||
763 | |||
764 | default: | ||
765 | ACPI_ERROR((AE_INFO, | ||
766 | "Operand must be Buffer/Integer/String/Package - found type %s", | ||
767 | acpi_ut_get_type_name(type))); | ||
768 | status = AE_AML_OPERAND_TYPE; | ||
769 | goto cleanup; | ||
770 | } | ||
771 | |||
772 | if (ACPI_FAILURE(status)) { | ||
773 | goto cleanup; | ||
774 | } | ||
775 | |||
776 | /* | ||
777 | * Now that we have the size of the object, create a result | ||
778 | * object to hold the value | ||
779 | */ | ||
780 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); | ||
781 | if (!return_desc) { | ||
782 | status = AE_NO_MEMORY; | ||
783 | goto cleanup; | ||
784 | } | ||
785 | |||
786 | return_desc->integer.value = value; | ||
787 | break; | ||
788 | |||
789 | case AML_REF_OF_OP: /* ref_of (source_object) */ | ||
790 | |||
791 | status = | ||
792 | acpi_ex_get_object_reference(operand[0], &return_desc, | ||
793 | walk_state); | ||
794 | if (ACPI_FAILURE(status)) { | ||
795 | goto cleanup; | ||
796 | } | ||
797 | break; | ||
798 | |||
799 | case AML_DEREF_OF_OP: /* deref_of (obj_reference | String) */ | ||
800 | |||
801 | /* Check for a method local or argument, or standalone String */ | ||
802 | |||
803 | if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) == | ||
804 | ACPI_DESC_TYPE_NAMED) { | ||
805 | temp_desc = | ||
806 | acpi_ns_get_attached_object((struct | ||
807 | acpi_namespace_node *) | ||
808 | operand[0]); | ||
809 | if (temp_desc | ||
810 | && | ||
811 | ((ACPI_GET_OBJECT_TYPE(temp_desc) == | ||
812 | ACPI_TYPE_STRING) | ||
813 | || (ACPI_GET_OBJECT_TYPE(temp_desc) == | ||
814 | ACPI_TYPE_LOCAL_REFERENCE))) { | ||
815 | operand[0] = temp_desc; | ||
816 | acpi_ut_add_reference(temp_desc); | ||
817 | } else { | ||
818 | status = AE_AML_OPERAND_TYPE; | ||
819 | goto cleanup; | ||
820 | } | ||
821 | } else { | ||
822 | switch (ACPI_GET_OBJECT_TYPE(operand[0])) { | ||
823 | case ACPI_TYPE_LOCAL_REFERENCE: | ||
824 | /* | ||
825 | * This is a deref_of (local_x | arg_x) | ||
826 | * | ||
827 | * Must resolve/dereference the local/arg reference first | ||
828 | */ | ||
829 | switch (operand[0]->reference.class) { | ||
830 | case ACPI_REFCLASS_LOCAL: | ||
831 | case ACPI_REFCLASS_ARG: | ||
832 | |||
833 | /* Set Operand[0] to the value of the local/arg */ | ||
834 | |||
835 | status = | ||
836 | acpi_ds_method_data_get_value | ||
837 | (operand[0]->reference.class, | ||
838 | operand[0]->reference.value, | ||
839 | walk_state, &temp_desc); | ||
840 | if (ACPI_FAILURE(status)) { | ||
841 | goto cleanup; | ||
842 | } | ||
843 | |||
844 | /* | ||
845 | * Delete our reference to the input object and | ||
846 | * point to the object just retrieved | ||
847 | */ | ||
848 | acpi_ut_remove_reference(operand[0]); | ||
849 | operand[0] = temp_desc; | ||
850 | break; | ||
851 | |||
852 | case ACPI_REFCLASS_REFOF: | ||
853 | |||
854 | /* Get the object to which the reference refers */ | ||
855 | |||
856 | temp_desc = | ||
857 | operand[0]->reference.object; | ||
858 | acpi_ut_remove_reference(operand[0]); | ||
859 | operand[0] = temp_desc; | ||
860 | break; | ||
861 | |||
862 | default: | ||
863 | |||
864 | /* Must be an Index op - handled below */ | ||
865 | break; | ||
866 | } | ||
867 | break; | ||
868 | |||
869 | case ACPI_TYPE_STRING: | ||
870 | break; | ||
871 | |||
872 | default: | ||
873 | status = AE_AML_OPERAND_TYPE; | ||
874 | goto cleanup; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) != | ||
879 | ACPI_DESC_TYPE_NAMED) { | ||
880 | if (ACPI_GET_OBJECT_TYPE(operand[0]) == | ||
881 | ACPI_TYPE_STRING) { | ||
882 | /* | ||
883 | * This is a deref_of (String). The string is a reference | ||
884 | * to a named ACPI object. | ||
885 | * | ||
886 | * 1) Find the owning Node | ||
887 | * 2) Dereference the node to an actual object. Could be a | ||
888 | * Field, so we need to resolve the node to a value. | ||
889 | */ | ||
890 | status = | ||
891 | acpi_ns_get_node(walk_state->scope_info-> | ||
892 | scope.node, | ||
893 | operand[0]->string.pointer, | ||
894 | ACPI_NS_SEARCH_PARENT, | ||
895 | ACPI_CAST_INDIRECT_PTR | ||
896 | (struct | ||
897 | acpi_namespace_node, | ||
898 | &return_desc)); | ||
899 | if (ACPI_FAILURE(status)) { | ||
900 | goto cleanup; | ||
901 | } | ||
902 | |||
903 | status = | ||
904 | acpi_ex_resolve_node_to_value | ||
905 | (ACPI_CAST_INDIRECT_PTR | ||
906 | (struct acpi_namespace_node, &return_desc), | ||
907 | walk_state); | ||
908 | goto cleanup; | ||
909 | } | ||
910 | } | ||
911 | |||
912 | /* Operand[0] may have changed from the code above */ | ||
913 | |||
914 | if (ACPI_GET_DESCRIPTOR_TYPE(operand[0]) == | ||
915 | ACPI_DESC_TYPE_NAMED) { | ||
916 | /* | ||
917 | * This is a deref_of (object_reference) | ||
918 | * Get the actual object from the Node (This is the dereference). | ||
919 | * This case may only happen when a local_x or arg_x is | ||
920 | * dereferenced above. | ||
921 | */ | ||
922 | return_desc = acpi_ns_get_attached_object((struct | ||
923 | acpi_namespace_node | ||
924 | *) | ||
925 | operand[0]); | ||
926 | acpi_ut_add_reference(return_desc); | ||
927 | } else { | ||
928 | /* | ||
929 | * This must be a reference object produced by either the | ||
930 | * Index() or ref_of() operator | ||
931 | */ | ||
932 | switch (operand[0]->reference.class) { | ||
933 | case ACPI_REFCLASS_INDEX: | ||
934 | |||
935 | /* | ||
936 | * The target type for the Index operator must be | ||
937 | * either a Buffer or a Package | ||
938 | */ | ||
939 | switch (operand[0]->reference.target_type) { | ||
940 | case ACPI_TYPE_BUFFER_FIELD: | ||
941 | |||
942 | temp_desc = | ||
943 | operand[0]->reference.object; | ||
944 | |||
945 | /* | ||
946 | * Create a new object that contains one element of the | ||
947 | * buffer -- the element pointed to by the index. | ||
948 | * | ||
949 | * NOTE: index into a buffer is NOT a pointer to a | ||
950 | * sub-buffer of the main buffer, it is only a pointer to a | ||
951 | * single element (byte) of the buffer! | ||
952 | */ | ||
953 | return_desc = | ||
954 | acpi_ut_create_internal_object | ||
955 | (ACPI_TYPE_INTEGER); | ||
956 | if (!return_desc) { | ||
957 | status = AE_NO_MEMORY; | ||
958 | goto cleanup; | ||
959 | } | ||
960 | |||
961 | /* | ||
962 | * Since we are returning the value of the buffer at the | ||
963 | * indexed location, we don't need to add an additional | ||
964 | * reference to the buffer itself. | ||
965 | */ | ||
966 | return_desc->integer.value = | ||
967 | temp_desc->buffer. | ||
968 | pointer[operand[0]->reference. | ||
969 | value]; | ||
970 | break; | ||
971 | |||
972 | case ACPI_TYPE_PACKAGE: | ||
973 | |||
974 | /* | ||
975 | * Return the referenced element of the package. We must | ||
976 | * add another reference to the referenced object, however. | ||
977 | */ | ||
978 | return_desc = | ||
979 | *(operand[0]->reference.where); | ||
980 | if (return_desc) { | ||
981 | acpi_ut_add_reference | ||
982 | (return_desc); | ||
983 | } | ||
984 | break; | ||
985 | |||
986 | default: | ||
987 | |||
988 | ACPI_ERROR((AE_INFO, | ||
989 | "Unknown Index TargetType %X in reference object %p", | ||
990 | operand[0]->reference. | ||
991 | target_type, operand[0])); | ||
992 | status = AE_AML_OPERAND_TYPE; | ||
993 | goto cleanup; | ||
994 | } | ||
995 | break; | ||
996 | |||
997 | case ACPI_REFCLASS_REFOF: | ||
998 | |||
999 | return_desc = operand[0]->reference.object; | ||
1000 | |||
1001 | if (ACPI_GET_DESCRIPTOR_TYPE(return_desc) == | ||
1002 | ACPI_DESC_TYPE_NAMED) { | ||
1003 | return_desc = | ||
1004 | acpi_ns_get_attached_object((struct | ||
1005 | acpi_namespace_node | ||
1006 | *) | ||
1007 | return_desc); | ||
1008 | } | ||
1009 | |||
1010 | /* Add another reference to the object! */ | ||
1011 | |||
1012 | acpi_ut_add_reference(return_desc); | ||
1013 | break; | ||
1014 | |||
1015 | default: | ||
1016 | ACPI_ERROR((AE_INFO, | ||
1017 | "Unknown class in reference(%p) - %2.2X", | ||
1018 | operand[0], | ||
1019 | operand[0]->reference.class)); | ||
1020 | |||
1021 | status = AE_TYPE; | ||
1022 | goto cleanup; | ||
1023 | } | ||
1024 | } | ||
1025 | break; | ||
1026 | |||
1027 | default: | ||
1028 | |||
1029 | ACPI_ERROR((AE_INFO, "Unknown AML opcode %X", | ||
1030 | walk_state->opcode)); | ||
1031 | status = AE_AML_BAD_OPCODE; | ||
1032 | goto cleanup; | ||
1033 | } | ||
1034 | |||
1035 | cleanup: | ||
1036 | |||
1037 | /* Delete return object on error */ | ||
1038 | |||
1039 | if (ACPI_FAILURE(status)) { | ||
1040 | acpi_ut_remove_reference(return_desc); | ||
1041 | } | ||
1042 | |||
1043 | /* Save return object on success */ | ||
1044 | |||
1045 | else { | ||
1046 | walk_state->result_obj = return_desc; | ||
1047 | } | ||
1048 | |||
1049 | return_ACPI_STATUS(status); | ||
1050 | } | ||