diff options
Diffstat (limited to 'drivers/acpi/acpica/psparse.c')
-rw-r--r-- | drivers/acpi/acpica/psparse.c | 701 |
1 files changed, 701 insertions, 0 deletions
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c new file mode 100644 index 000000000000..9da48fdb811a --- /dev/null +++ b/drivers/acpi/acpica/psparse.c | |||
@@ -0,0 +1,701 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * Module Name: psparse - Parser top level AML parse routines | ||
4 | * | ||
5 | *****************************************************************************/ | ||
6 | |||
7 | /* | ||
8 | * Copyright (C) 2000 - 2008, Intel Corp. | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without | ||
12 | * modification, are permitted provided that the following conditions | ||
13 | * are met: | ||
14 | * 1. Redistributions of source code must retain the above copyright | ||
15 | * notice, this list of conditions, and the following disclaimer, | ||
16 | * without modification. | ||
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer | ||
18 | * substantially similar to the "NO WARRANTY" disclaimer below | ||
19 | * ("Disclaimer") and any redistribution must be conditioned upon | ||
20 | * including a substantially similar Disclaimer requirement for further | ||
21 | * binary redistribution. | ||
22 | * 3. Neither the names of the above-listed copyright holders nor the names | ||
23 | * of any contributors may be used to endorse or promote products derived | ||
24 | * from this software without specific prior written permission. | ||
25 | * | ||
26 | * Alternatively, this software may be distributed under the terms of the | ||
27 | * GNU General Public License ("GPL") version 2 as published by the Free | ||
28 | * Software Foundation. | ||
29 | * | ||
30 | * NO WARRANTY | ||
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR | ||
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | ||
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | ||
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
41 | * POSSIBILITY OF SUCH DAMAGES. | ||
42 | */ | ||
43 | |||
44 | /* | ||
45 | * Parse the AML and build an operation tree as most interpreters, | ||
46 | * like Perl, do. Parsing is done by hand rather than with a YACC | ||
47 | * generated parser to tightly constrain stack and dynamic memory | ||
48 | * usage. At the same time, parsing is kept flexible and the code | ||
49 | * fairly compact by parsing based on a list of AML opcode | ||
50 | * templates in aml_op_info[] | ||
51 | */ | ||
52 | |||
53 | #include <acpi/acpi.h> | ||
54 | #include <acpi/accommon.h> | ||
55 | #include <acpi/acparser.h> | ||
56 | #include <acpi/acdispat.h> | ||
57 | #include <acpi/amlcode.h> | ||
58 | #include <acpi/acnamesp.h> | ||
59 | #include <acpi/acinterp.h> | ||
60 | |||
61 | #define _COMPONENT ACPI_PARSER | ||
62 | ACPI_MODULE_NAME("psparse") | ||
63 | |||
64 | /******************************************************************************* | ||
65 | * | ||
66 | * FUNCTION: acpi_ps_get_opcode_size | ||
67 | * | ||
68 | * PARAMETERS: Opcode - An AML opcode | ||
69 | * | ||
70 | * RETURN: Size of the opcode, in bytes (1 or 2) | ||
71 | * | ||
72 | * DESCRIPTION: Get the size of the current opcode. | ||
73 | * | ||
74 | ******************************************************************************/ | ||
75 | u32 acpi_ps_get_opcode_size(u32 opcode) | ||
76 | { | ||
77 | |||
78 | /* Extended (2-byte) opcode if > 255 */ | ||
79 | |||
80 | if (opcode > 0x00FF) { | ||
81 | return (2); | ||
82 | } | ||
83 | |||
84 | /* Otherwise, just a single byte opcode */ | ||
85 | |||
86 | return (1); | ||
87 | } | ||
88 | |||
89 | /******************************************************************************* | ||
90 | * | ||
91 | * FUNCTION: acpi_ps_peek_opcode | ||
92 | * | ||
93 | * PARAMETERS: parser_state - A parser state object | ||
94 | * | ||
95 | * RETURN: Next AML opcode | ||
96 | * | ||
97 | * DESCRIPTION: Get next AML opcode (without incrementing AML pointer) | ||
98 | * | ||
99 | ******************************************************************************/ | ||
100 | |||
101 | u16 acpi_ps_peek_opcode(struct acpi_parse_state * parser_state) | ||
102 | { | ||
103 | u8 *aml; | ||
104 | u16 opcode; | ||
105 | |||
106 | aml = parser_state->aml; | ||
107 | opcode = (u16) ACPI_GET8(aml); | ||
108 | |||
109 | if (opcode == AML_EXTENDED_OP_PREFIX) { | ||
110 | |||
111 | /* Extended opcode, get the second opcode byte */ | ||
112 | |||
113 | aml++; | ||
114 | opcode = (u16) ((opcode << 8) | ACPI_GET8(aml)); | ||
115 | } | ||
116 | |||
117 | return (opcode); | ||
118 | } | ||
119 | |||
120 | /******************************************************************************* | ||
121 | * | ||
122 | * FUNCTION: acpi_ps_complete_this_op | ||
123 | * | ||
124 | * PARAMETERS: walk_state - Current State | ||
125 | * Op - Op to complete | ||
126 | * | ||
127 | * RETURN: Status | ||
128 | * | ||
129 | * DESCRIPTION: Perform any cleanup at the completion of an Op. | ||
130 | * | ||
131 | ******************************************************************************/ | ||
132 | |||
133 | acpi_status | ||
134 | acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, | ||
135 | union acpi_parse_object * op) | ||
136 | { | ||
137 | union acpi_parse_object *prev; | ||
138 | union acpi_parse_object *next; | ||
139 | const struct acpi_opcode_info *parent_info; | ||
140 | union acpi_parse_object *replacement_op = NULL; | ||
141 | acpi_status status = AE_OK; | ||
142 | |||
143 | ACPI_FUNCTION_TRACE_PTR(ps_complete_this_op, op); | ||
144 | |||
145 | /* Check for null Op, can happen if AML code is corrupt */ | ||
146 | |||
147 | if (!op) { | ||
148 | return_ACPI_STATUS(AE_OK); /* OK for now */ | ||
149 | } | ||
150 | |||
151 | /* Delete this op and the subtree below it if asked to */ | ||
152 | |||
153 | if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != | ||
154 | ACPI_PARSE_DELETE_TREE) | ||
155 | || (walk_state->op_info->class == AML_CLASS_ARGUMENT)) { | ||
156 | return_ACPI_STATUS(AE_OK); | ||
157 | } | ||
158 | |||
159 | /* Make sure that we only delete this subtree */ | ||
160 | |||
161 | if (op->common.parent) { | ||
162 | prev = op->common.parent->common.value.arg; | ||
163 | if (!prev) { | ||
164 | |||
165 | /* Nothing more to do */ | ||
166 | |||
167 | goto cleanup; | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Check if we need to replace the operator and its subtree | ||
172 | * with a return value op (placeholder op) | ||
173 | */ | ||
174 | parent_info = | ||
175 | acpi_ps_get_opcode_info(op->common.parent->common. | ||
176 | aml_opcode); | ||
177 | |||
178 | switch (parent_info->class) { | ||
179 | case AML_CLASS_CONTROL: | ||
180 | break; | ||
181 | |||
182 | case AML_CLASS_CREATE: | ||
183 | |||
184 | /* | ||
185 | * These opcodes contain term_arg operands. The current | ||
186 | * op must be replaced by a placeholder return op | ||
187 | */ | ||
188 | replacement_op = | ||
189 | acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); | ||
190 | if (!replacement_op) { | ||
191 | status = AE_NO_MEMORY; | ||
192 | } | ||
193 | break; | ||
194 | |||
195 | case AML_CLASS_NAMED_OBJECT: | ||
196 | |||
197 | /* | ||
198 | * These opcodes contain term_arg operands. The current | ||
199 | * op must be replaced by a placeholder return op | ||
200 | */ | ||
201 | if ((op->common.parent->common.aml_opcode == | ||
202 | AML_REGION_OP) | ||
203 | || (op->common.parent->common.aml_opcode == | ||
204 | AML_DATA_REGION_OP) | ||
205 | || (op->common.parent->common.aml_opcode == | ||
206 | AML_BUFFER_OP) | ||
207 | || (op->common.parent->common.aml_opcode == | ||
208 | AML_PACKAGE_OP) | ||
209 | || (op->common.parent->common.aml_opcode == | ||
210 | AML_BANK_FIELD_OP) | ||
211 | || (op->common.parent->common.aml_opcode == | ||
212 | AML_VAR_PACKAGE_OP)) { | ||
213 | replacement_op = | ||
214 | acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); | ||
215 | if (!replacement_op) { | ||
216 | status = AE_NO_MEMORY; | ||
217 | } | ||
218 | } else | ||
219 | if ((op->common.parent->common.aml_opcode == | ||
220 | AML_NAME_OP) | ||
221 | && (walk_state->pass_number <= | ||
222 | ACPI_IMODE_LOAD_PASS2)) { | ||
223 | if ((op->common.aml_opcode == AML_BUFFER_OP) | ||
224 | || (op->common.aml_opcode == AML_PACKAGE_OP) | ||
225 | || (op->common.aml_opcode == | ||
226 | AML_VAR_PACKAGE_OP)) { | ||
227 | replacement_op = | ||
228 | acpi_ps_alloc_op(op->common. | ||
229 | aml_opcode); | ||
230 | if (!replacement_op) { | ||
231 | status = AE_NO_MEMORY; | ||
232 | } else { | ||
233 | replacement_op->named.data = | ||
234 | op->named.data; | ||
235 | replacement_op->named.length = | ||
236 | op->named.length; | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | break; | ||
241 | |||
242 | default: | ||
243 | |||
244 | replacement_op = | ||
245 | acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); | ||
246 | if (!replacement_op) { | ||
247 | status = AE_NO_MEMORY; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | /* We must unlink this op from the parent tree */ | ||
252 | |||
253 | if (prev == op) { | ||
254 | |||
255 | /* This op is the first in the list */ | ||
256 | |||
257 | if (replacement_op) { | ||
258 | replacement_op->common.parent = | ||
259 | op->common.parent; | ||
260 | replacement_op->common.value.arg = NULL; | ||
261 | replacement_op->common.node = op->common.node; | ||
262 | op->common.parent->common.value.arg = | ||
263 | replacement_op; | ||
264 | replacement_op->common.next = op->common.next; | ||
265 | } else { | ||
266 | op->common.parent->common.value.arg = | ||
267 | op->common.next; | ||
268 | } | ||
269 | } | ||
270 | |||
271 | /* Search the parent list */ | ||
272 | |||
273 | else | ||
274 | while (prev) { | ||
275 | |||
276 | /* Traverse all siblings in the parent's argument list */ | ||
277 | |||
278 | next = prev->common.next; | ||
279 | if (next == op) { | ||
280 | if (replacement_op) { | ||
281 | replacement_op->common.parent = | ||
282 | op->common.parent; | ||
283 | replacement_op->common.value. | ||
284 | arg = NULL; | ||
285 | replacement_op->common.node = | ||
286 | op->common.node; | ||
287 | prev->common.next = | ||
288 | replacement_op; | ||
289 | replacement_op->common.next = | ||
290 | op->common.next; | ||
291 | next = NULL; | ||
292 | } else { | ||
293 | prev->common.next = | ||
294 | op->common.next; | ||
295 | next = NULL; | ||
296 | } | ||
297 | } | ||
298 | prev = next; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | cleanup: | ||
303 | |||
304 | /* Now we can actually delete the subtree rooted at Op */ | ||
305 | |||
306 | acpi_ps_delete_parse_tree(op); | ||
307 | return_ACPI_STATUS(status); | ||
308 | } | ||
309 | |||
310 | /******************************************************************************* | ||
311 | * | ||
312 | * FUNCTION: acpi_ps_next_parse_state | ||
313 | * | ||
314 | * PARAMETERS: walk_state - Current state | ||
315 | * Op - Current parse op | ||
316 | * callback_status - Status from previous operation | ||
317 | * | ||
318 | * RETURN: Status | ||
319 | * | ||
320 | * DESCRIPTION: Update the parser state based upon the return exception from | ||
321 | * the parser callback. | ||
322 | * | ||
323 | ******************************************************************************/ | ||
324 | |||
325 | acpi_status | ||
326 | acpi_ps_next_parse_state(struct acpi_walk_state *walk_state, | ||
327 | union acpi_parse_object *op, | ||
328 | acpi_status callback_status) | ||
329 | { | ||
330 | struct acpi_parse_state *parser_state = &walk_state->parser_state; | ||
331 | acpi_status status = AE_CTRL_PENDING; | ||
332 | |||
333 | ACPI_FUNCTION_TRACE_PTR(ps_next_parse_state, op); | ||
334 | |||
335 | switch (callback_status) { | ||
336 | case AE_CTRL_TERMINATE: | ||
337 | /* | ||
338 | * A control method was terminated via a RETURN statement. | ||
339 | * The walk of this method is complete. | ||
340 | */ | ||
341 | parser_state->aml = parser_state->aml_end; | ||
342 | status = AE_CTRL_TERMINATE; | ||
343 | break; | ||
344 | |||
345 | case AE_CTRL_BREAK: | ||
346 | |||
347 | parser_state->aml = walk_state->aml_last_while; | ||
348 | walk_state->control_state->common.value = FALSE; | ||
349 | status = AE_CTRL_BREAK; | ||
350 | break; | ||
351 | |||
352 | case AE_CTRL_CONTINUE: | ||
353 | |||
354 | parser_state->aml = walk_state->aml_last_while; | ||
355 | status = AE_CTRL_CONTINUE; | ||
356 | break; | ||
357 | |||
358 | case AE_CTRL_PENDING: | ||
359 | |||
360 | parser_state->aml = walk_state->aml_last_while; | ||
361 | break; | ||
362 | |||
363 | #if 0 | ||
364 | case AE_CTRL_SKIP: | ||
365 | |||
366 | parser_state->aml = parser_state->scope->parse_scope.pkg_end; | ||
367 | status = AE_OK; | ||
368 | break; | ||
369 | #endif | ||
370 | |||
371 | case AE_CTRL_TRUE: | ||
372 | /* | ||
373 | * Predicate of an IF was true, and we are at the matching ELSE. | ||
374 | * Just close out this package | ||
375 | */ | ||
376 | parser_state->aml = acpi_ps_get_next_package_end(parser_state); | ||
377 | status = AE_CTRL_PENDING; | ||
378 | break; | ||
379 | |||
380 | case AE_CTRL_FALSE: | ||
381 | /* | ||
382 | * Either an IF/WHILE Predicate was false or we encountered a BREAK | ||
383 | * opcode. In both cases, we do not execute the rest of the | ||
384 | * package; We simply close out the parent (finishing the walk of | ||
385 | * this branch of the tree) and continue execution at the parent | ||
386 | * level. | ||
387 | */ | ||
388 | parser_state->aml = parser_state->scope->parse_scope.pkg_end; | ||
389 | |||
390 | /* In the case of a BREAK, just force a predicate (if any) to FALSE */ | ||
391 | |||
392 | walk_state->control_state->common.value = FALSE; | ||
393 | status = AE_CTRL_END; | ||
394 | break; | ||
395 | |||
396 | case AE_CTRL_TRANSFER: | ||
397 | |||
398 | /* A method call (invocation) -- transfer control */ | ||
399 | |||
400 | status = AE_CTRL_TRANSFER; | ||
401 | walk_state->prev_op = op; | ||
402 | walk_state->method_call_op = op; | ||
403 | walk_state->method_call_node = | ||
404 | (op->common.value.arg)->common.node; | ||
405 | |||
406 | /* Will return value (if any) be used by the caller? */ | ||
407 | |||
408 | walk_state->return_used = | ||
409 | acpi_ds_is_result_used(op, walk_state); | ||
410 | break; | ||
411 | |||
412 | default: | ||
413 | |||
414 | status = callback_status; | ||
415 | if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) { | ||
416 | status = AE_OK; | ||
417 | } | ||
418 | break; | ||
419 | } | ||
420 | |||
421 | return_ACPI_STATUS(status); | ||
422 | } | ||
423 | |||
424 | /******************************************************************************* | ||
425 | * | ||
426 | * FUNCTION: acpi_ps_parse_aml | ||
427 | * | ||
428 | * PARAMETERS: walk_state - Current state | ||
429 | * | ||
430 | * | ||
431 | * RETURN: Status | ||
432 | * | ||
433 | * DESCRIPTION: Parse raw AML and return a tree of ops | ||
434 | * | ||
435 | ******************************************************************************/ | ||
436 | |||
437 | acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state) | ||
438 | { | ||
439 | acpi_status status; | ||
440 | struct acpi_thread_state *thread; | ||
441 | struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list; | ||
442 | struct acpi_walk_state *previous_walk_state; | ||
443 | |||
444 | ACPI_FUNCTION_TRACE(ps_parse_aml); | ||
445 | |||
446 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
447 | "Entered with WalkState=%p Aml=%p size=%X\n", | ||
448 | walk_state, walk_state->parser_state.aml, | ||
449 | walk_state->parser_state.aml_size)); | ||
450 | |||
451 | if (!walk_state->parser_state.aml) { | ||
452 | return_ACPI_STATUS(AE_NULL_OBJECT); | ||
453 | } | ||
454 | |||
455 | /* Create and initialize a new thread state */ | ||
456 | |||
457 | thread = acpi_ut_create_thread_state(); | ||
458 | if (!thread) { | ||
459 | if (walk_state->method_desc) { | ||
460 | |||
461 | /* Executing a control method - additional cleanup */ | ||
462 | |||
463 | acpi_ds_terminate_control_method( | ||
464 | walk_state->method_desc, walk_state); | ||
465 | } | ||
466 | |||
467 | acpi_ds_delete_walk_state(walk_state); | ||
468 | return_ACPI_STATUS(AE_NO_MEMORY); | ||
469 | } | ||
470 | |||
471 | walk_state->thread = thread; | ||
472 | |||
473 | /* | ||
474 | * If executing a method, the starting sync_level is this method's | ||
475 | * sync_level | ||
476 | */ | ||
477 | if (walk_state->method_desc) { | ||
478 | walk_state->thread->current_sync_level = | ||
479 | walk_state->method_desc->method.sync_level; | ||
480 | } | ||
481 | |||
482 | acpi_ds_push_walk_state(walk_state, thread); | ||
483 | |||
484 | /* | ||
485 | * This global allows the AML debugger to get a handle to the currently | ||
486 | * executing control method. | ||
487 | */ | ||
488 | acpi_gbl_current_walk_list = thread; | ||
489 | |||
490 | /* | ||
491 | * Execute the walk loop as long as there is a valid Walk State. This | ||
492 | * handles nested control method invocations without recursion. | ||
493 | */ | ||
494 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "State=%p\n", walk_state)); | ||
495 | |||
496 | status = AE_OK; | ||
497 | while (walk_state) { | ||
498 | if (ACPI_SUCCESS(status)) { | ||
499 | /* | ||
500 | * The parse_loop executes AML until the method terminates | ||
501 | * or calls another method. | ||
502 | */ | ||
503 | status = acpi_ps_parse_loop(walk_state); | ||
504 | } | ||
505 | |||
506 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
507 | "Completed one call to walk loop, %s State=%p\n", | ||
508 | acpi_format_exception(status), walk_state)); | ||
509 | |||
510 | if (status == AE_CTRL_TRANSFER) { | ||
511 | /* | ||
512 | * A method call was detected. | ||
513 | * Transfer control to the called control method | ||
514 | */ | ||
515 | status = | ||
516 | acpi_ds_call_control_method(thread, walk_state, | ||
517 | NULL); | ||
518 | if (ACPI_FAILURE(status)) { | ||
519 | status = | ||
520 | acpi_ds_method_error(status, walk_state); | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * If the transfer to the new method method call worked, a new walk | ||
525 | * state was created -- get it | ||
526 | */ | ||
527 | walk_state = acpi_ds_get_current_walk_state(thread); | ||
528 | continue; | ||
529 | } else if (status == AE_CTRL_TERMINATE) { | ||
530 | status = AE_OK; | ||
531 | } else if ((status != AE_OK) && (walk_state->method_desc)) { | ||
532 | |||
533 | /* Either the method parse or actual execution failed */ | ||
534 | |||
535 | ACPI_ERROR_METHOD("Method parse/execution failed", | ||
536 | walk_state->method_node, NULL, | ||
537 | status); | ||
538 | |||
539 | /* Check for possible multi-thread reentrancy problem */ | ||
540 | |||
541 | if ((status == AE_ALREADY_EXISTS) && | ||
542 | (!walk_state->method_desc->method.mutex)) { | ||
543 | ACPI_INFO((AE_INFO, | ||
544 | "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", | ||
545 | walk_state->method_node->name. | ||
546 | ascii)); | ||
547 | |||
548 | /* | ||
549 | * Method tried to create an object twice. The probable cause is | ||
550 | * that the method cannot handle reentrancy. | ||
551 | * | ||
552 | * The method is marked not_serialized, but it tried to create | ||
553 | * a named object, causing the second thread entrance to fail. | ||
554 | * Workaround this problem by marking the method permanently | ||
555 | * as Serialized. | ||
556 | */ | ||
557 | walk_state->method_desc->method.method_flags |= | ||
558 | AML_METHOD_SERIALIZED; | ||
559 | walk_state->method_desc->method.sync_level = 0; | ||
560 | } | ||
561 | } | ||
562 | |||
563 | /* We are done with this walk, move on to the parent if any */ | ||
564 | |||
565 | walk_state = acpi_ds_pop_walk_state(thread); | ||
566 | |||
567 | /* Reset the current scope to the beginning of scope stack */ | ||
568 | |||
569 | acpi_ds_scope_stack_clear(walk_state); | ||
570 | |||
571 | /* | ||
572 | * If we just returned from the execution of a control method or if we | ||
573 | * encountered an error during the method parse phase, there's lots of | ||
574 | * cleanup to do | ||
575 | */ | ||
576 | if (((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == | ||
577 | ACPI_PARSE_EXECUTE) || (ACPI_FAILURE(status))) { | ||
578 | acpi_ds_terminate_control_method(walk_state-> | ||
579 | method_desc, | ||
580 | walk_state); | ||
581 | } | ||
582 | |||
583 | /* Delete this walk state and all linked control states */ | ||
584 | |||
585 | acpi_ps_cleanup_scope(&walk_state->parser_state); | ||
586 | previous_walk_state = walk_state; | ||
587 | |||
588 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, | ||
589 | "ReturnValue=%p, ImplicitValue=%p State=%p\n", | ||
590 | walk_state->return_desc, | ||
591 | walk_state->implicit_return_obj, walk_state)); | ||
592 | |||
593 | /* Check if we have restarted a preempted walk */ | ||
594 | |||
595 | walk_state = acpi_ds_get_current_walk_state(thread); | ||
596 | if (walk_state) { | ||
597 | if (ACPI_SUCCESS(status)) { | ||
598 | /* | ||
599 | * There is another walk state, restart it. | ||
600 | * If the method return value is not used by the parent, | ||
601 | * The object is deleted | ||
602 | */ | ||
603 | if (!previous_walk_state->return_desc) { | ||
604 | /* | ||
605 | * In slack mode execution, if there is no return value | ||
606 | * we should implicitly return zero (0) as a default value. | ||
607 | */ | ||
608 | if (acpi_gbl_enable_interpreter_slack && | ||
609 | !previous_walk_state-> | ||
610 | implicit_return_obj) { | ||
611 | previous_walk_state-> | ||
612 | implicit_return_obj = | ||
613 | acpi_ut_create_internal_object | ||
614 | (ACPI_TYPE_INTEGER); | ||
615 | if (!previous_walk_state-> | ||
616 | implicit_return_obj) { | ||
617 | return_ACPI_STATUS | ||
618 | (AE_NO_MEMORY); | ||
619 | } | ||
620 | |||
621 | previous_walk_state-> | ||
622 | implicit_return_obj-> | ||
623 | integer.value = 0; | ||
624 | } | ||
625 | |||
626 | /* Restart the calling control method */ | ||
627 | |||
628 | status = | ||
629 | acpi_ds_restart_control_method | ||
630 | (walk_state, | ||
631 | previous_walk_state-> | ||
632 | implicit_return_obj); | ||
633 | } else { | ||
634 | /* | ||
635 | * We have a valid return value, delete any implicit | ||
636 | * return value. | ||
637 | */ | ||
638 | acpi_ds_clear_implicit_return | ||
639 | (previous_walk_state); | ||
640 | |||
641 | status = | ||
642 | acpi_ds_restart_control_method | ||
643 | (walk_state, | ||
644 | previous_walk_state->return_desc); | ||
645 | } | ||
646 | if (ACPI_SUCCESS(status)) { | ||
647 | walk_state->walk_type |= | ||
648 | ACPI_WALK_METHOD_RESTART; | ||
649 | } | ||
650 | } else { | ||
651 | /* On error, delete any return object or implicit return */ | ||
652 | |||
653 | acpi_ut_remove_reference(previous_walk_state-> | ||
654 | return_desc); | ||
655 | acpi_ds_clear_implicit_return | ||
656 | (previous_walk_state); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | /* | ||
661 | * Just completed a 1st-level method, save the final internal return | ||
662 | * value (if any) | ||
663 | */ | ||
664 | else if (previous_walk_state->caller_return_desc) { | ||
665 | if (previous_walk_state->implicit_return_obj) { | ||
666 | *(previous_walk_state->caller_return_desc) = | ||
667 | previous_walk_state->implicit_return_obj; | ||
668 | } else { | ||
669 | /* NULL if no return value */ | ||
670 | |||
671 | *(previous_walk_state->caller_return_desc) = | ||
672 | previous_walk_state->return_desc; | ||
673 | } | ||
674 | } else { | ||
675 | if (previous_walk_state->return_desc) { | ||
676 | |||
677 | /* Caller doesn't want it, must delete it */ | ||
678 | |||
679 | acpi_ut_remove_reference(previous_walk_state-> | ||
680 | return_desc); | ||
681 | } | ||
682 | if (previous_walk_state->implicit_return_obj) { | ||
683 | |||
684 | /* Caller doesn't want it, must delete it */ | ||
685 | |||
686 | acpi_ut_remove_reference(previous_walk_state-> | ||
687 | implicit_return_obj); | ||
688 | } | ||
689 | } | ||
690 | |||
691 | acpi_ds_delete_walk_state(previous_walk_state); | ||
692 | } | ||
693 | |||
694 | /* Normal exit */ | ||
695 | |||
696 | acpi_ex_release_all_mutexes(thread); | ||
697 | acpi_ut_delete_generic_state(ACPI_CAST_PTR | ||
698 | (union acpi_generic_state, thread)); | ||
699 | acpi_gbl_current_walk_list = prev_walk_list; | ||
700 | return_ACPI_STATUS(status); | ||
701 | } | ||