c87469493aaea9dde463dcaa84ac15e162dc902b
[reactos.git] / reactos / drivers / bus / acpi / dispatcher / dsutils.c
1 /*******************************************************************************
2 *
3 * Module Name: dsutils - Dispatcher utilities
4 * $Revision: 1.1 $
5 *
6 ******************************************************************************/
7
8 /*
9 * Copyright (C) 2000, 2001 R. Byron Moore
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26
27 #include <acpi.h>
28
29 #define _COMPONENT ACPI_DISPATCHER
30 MODULE_NAME ("dsutils")
31
32
33 /*******************************************************************************
34 *
35 * FUNCTION: Acpi_ds_is_result_used
36 *
37 * PARAMETERS: Op
38 * Result_obj
39 * Walk_state
40 *
41 * RETURN: Status
42 *
43 * DESCRIPTION: Check if a result object will be used by the parent
44 *
45 ******************************************************************************/
46
47 u8
48 acpi_ds_is_result_used (
49 ACPI_PARSE_OBJECT *op,
50 ACPI_WALK_STATE *walk_state)
51 {
52 ACPI_OPCODE_INFO *parent_info;
53
54
55 /* Must have both an Op and a Result Object */
56
57 if (!op) {
58 return (TRUE);
59 }
60
61
62 /*
63 * If there is no parent, the result can't possibly be used!
64 * (An executing method typically has no parent, since each
65 * method is parsed separately) However, a method that is
66 * invoked from another method has a parent.
67 */
68 if (!op->parent) {
69 return (FALSE);
70 }
71
72
73 /*
74 * Get info on the parent. The root Op is AML_SCOPE
75 */
76
77 parent_info = acpi_ps_get_opcode_info (op->parent->opcode);
78 if (ACPI_GET_OP_TYPE (parent_info) != ACPI_OP_TYPE_OPCODE) {
79 return (FALSE);
80 }
81
82
83 /*
84 * Decide what to do with the result based on the parent. If
85 * the parent opcode will not use the result, delete the object.
86 * Otherwise leave it as is, it will be deleted when it is used
87 * as an operand later.
88 */
89
90 switch (ACPI_GET_OP_CLASS (parent_info)) {
91 /*
92 * In these cases, the parent will never use the return object
93 */
94 case OPTYPE_CONTROL: /* IF, ELSE, WHILE only */
95
96 switch (op->parent->opcode) {
97 case AML_RETURN_OP:
98
99 /* Never delete the return value associated with a return opcode */
100
101 return (TRUE);
102 break;
103
104 case AML_IF_OP:
105 case AML_WHILE_OP:
106
107 /*
108 * If we are executing the predicate AND this is the predicate op,
109 * we will use the return value!
110 */
111
112 if ((walk_state->control_state->common.state == CONTROL_PREDICATE_EXECUTING) &&
113 (walk_state->control_state->control.predicate_op == op)) {
114 return (TRUE);
115 }
116
117 break;
118 }
119
120
121 /* Fall through to not used case below */
122
123
124 case OPTYPE_NAMED_OBJECT: /* Scope, method, etc. */
125
126 /*
127 * These opcodes allow Term_arg(s) as operands and therefore
128 * method calls. The result is used.
129 */
130 if ((op->parent->opcode == AML_REGION_OP) ||
131 (op->parent->opcode == AML_CREATE_FIELD_OP) ||
132 (op->parent->opcode == AML_BIT_FIELD_OP) ||
133 (op->parent->opcode == AML_BYTE_FIELD_OP) ||
134 (op->parent->opcode == AML_WORD_FIELD_OP) ||
135 (op->parent->opcode == AML_DWORD_FIELD_OP) ||
136 (op->parent->opcode == AML_QWORD_FIELD_OP)) {
137 return (TRUE);
138 }
139
140 return (FALSE);
141 break;
142
143 /*
144 * In all other cases. the parent will actually use the return
145 * object, so keep it.
146 */
147 default:
148 break;
149 }
150
151 return (TRUE);
152 }
153
154
155 /*******************************************************************************
156 *
157 * FUNCTION: Acpi_ds_delete_result_if_not_used
158 *
159 * PARAMETERS: Op
160 * Result_obj
161 * Walk_state
162 *
163 * RETURN: Status
164 *
165 * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
166 * result descriptor, check if the parent opcode will actually use
167 * this result. If not, delete the result now so that it will
168 * not become orphaned.
169 *
170 ******************************************************************************/
171
172 void
173 acpi_ds_delete_result_if_not_used (
174 ACPI_PARSE_OBJECT *op,
175 ACPI_OPERAND_OBJECT *result_obj,
176 ACPI_WALK_STATE *walk_state)
177 {
178 ACPI_OPERAND_OBJECT *obj_desc;
179 ACPI_STATUS status;
180
181
182 if (!op) {
183 return;
184 }
185
186 if (!result_obj) {
187 return;
188 }
189
190
191 if (!acpi_ds_is_result_used (op, walk_state)) {
192 /*
193 * Must pop the result stack (Obj_desc should be equal
194 * to Result_obj)
195 */
196
197 status = acpi_ds_result_pop (&obj_desc, walk_state);
198 if (ACPI_SUCCESS (status)) {
199 acpi_cm_remove_reference (result_obj);
200 }
201 }
202
203 return;
204 }
205
206
207 /*******************************************************************************
208 *
209 * FUNCTION: Acpi_ds_create_operand
210 *
211 * PARAMETERS: Walk_state
212 * Arg
213 *
214 * RETURN: Status
215 *
216 * DESCRIPTION: Translate a parse tree object that is an argument to an AML
217 * opcode to the equivalent interpreter object. This may include
218 * looking up a name or entering a new name into the internal
219 * namespace.
220 *
221 ******************************************************************************/
222
223 ACPI_STATUS
224 acpi_ds_create_operand (
225 ACPI_WALK_STATE *walk_state,
226 ACPI_PARSE_OBJECT *arg,
227 u32 arg_index)
228 {
229 ACPI_STATUS status = AE_OK;
230 NATIVE_CHAR *name_string;
231 u32 name_length;
232 OBJECT_TYPE_INTERNAL data_type;
233 ACPI_OPERAND_OBJECT *obj_desc;
234 ACPI_PARSE_OBJECT *parent_op;
235 u16 opcode;
236 u32 flags = 0;
237 OPERATING_MODE interpreter_mode;
238
239
240 /* A valid name must be looked up in the namespace */
241
242 if ((arg->opcode == AML_NAMEPATH_OP) &&
243 (arg->value.string)) {
244 /* Get the entire name string from the AML stream */
245
246 status = acpi_aml_get_name_string (ACPI_TYPE_ANY,
247 arg->value.buffer,
248 &name_string,
249 &name_length);
250
251 if (ACPI_FAILURE (status)) {
252 return (status);
253 }
254
255 /*
256 * All prefixes have been handled, and the name is
257 * in Name_string
258 */
259
260 /*
261 * Differentiate between a namespace "create" operation
262 * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
263 * IMODE_EXECUTE) in order to support the creation of
264 * namespace objects during the execution of control methods.
265 */
266
267 parent_op = arg->parent;
268 if ((acpi_ps_is_node_op (parent_op->opcode)) &&
269 (parent_op->opcode != AML_METHODCALL_OP) &&
270 (parent_op->opcode != AML_REGION_OP) &&
271 (parent_op->opcode != AML_NAMEPATH_OP)) {
272 /* Enter name into namespace if not found */
273
274 interpreter_mode = IMODE_LOAD_PASS2;
275 }
276
277 else {
278 /* Return a failure if name not found */
279
280 interpreter_mode = IMODE_EXECUTE;
281 }
282
283 status = acpi_ns_lookup (walk_state->scope_info, name_string,
284 ACPI_TYPE_ANY, interpreter_mode,
285 NS_SEARCH_PARENT | NS_DONT_OPEN_SCOPE,
286 walk_state,
287 (ACPI_NAMESPACE_NODE **) &obj_desc);
288
289 /* Free the namestring created above */
290
291 acpi_cm_free (name_string);
292
293 /*
294 * The only case where we pass through (ignore) a NOT_FOUND
295 * error is for the Cond_ref_of opcode.
296 */
297
298 if (status == AE_NOT_FOUND) {
299 if (parent_op->opcode == AML_COND_REF_OF_OP) {
300 /*
301 * For the Conditional Reference op, it's OK if
302 * the name is not found; We just need a way to
303 * indicate this to the interpreter, set the
304 * object to the root
305 */
306 obj_desc = (ACPI_OPERAND_OBJECT *) acpi_gbl_root_node;
307 status = AE_OK;
308 }
309
310 else {
311 /*
312 * We just plain didn't find it -- which is a
313 * very serious error at this point
314 */
315 status = AE_AML_NAME_NOT_FOUND;
316 }
317 }
318
319 /* Check status from the lookup */
320
321 if (ACPI_FAILURE (status)) {
322 return (status);
323 }
324
325 /* Put the resulting object onto the current object stack */
326
327 status = acpi_ds_obj_stack_push (obj_desc, walk_state);
328 if (ACPI_FAILURE (status)) {
329 return (status);
330 }
331 DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state));
332 }
333
334
335 else {
336 /* Check for null name case */
337
338 if (arg->opcode == AML_NAMEPATH_OP) {
339 /*
340 * If the name is null, this means that this is an
341 * optional result parameter that was not specified
342 * in the original ASL. Create an Reference for a
343 * placeholder
344 */
345 opcode = AML_ZERO_OP; /* Has no arguments! */
346
347 /*
348 * TBD: [Investigate] anything else needed for the
349 * zero op lvalue?
350 */
351 }
352
353 else {
354 opcode = arg->opcode;
355 }
356
357
358 /* Get the data type of the argument */
359
360 data_type = acpi_ds_map_opcode_to_data_type (opcode, &flags);
361 if (data_type == INTERNAL_TYPE_INVALID) {
362 return (AE_NOT_IMPLEMENTED);
363 }
364
365 if (flags & OP_HAS_RETURN_VALUE) {
366 DEBUGGER_EXEC (acpi_db_display_argument_object (walk_state->operands [walk_state->num_operands - 1], walk_state));
367
368 /*
369 * Use value that was already previously returned
370 * by the evaluation of this argument
371 */
372
373 status = acpi_ds_result_pop_from_bottom (&obj_desc, walk_state);
374 if (ACPI_FAILURE (status)) {
375 /*
376 * Only error is underflow, and this indicates
377 * a missing or null operand!
378 */
379 return (status);
380 }
381
382 }
383
384 else {
385 /* Create an ACPI_INTERNAL_OBJECT for the argument */
386
387 obj_desc = acpi_cm_create_internal_object (data_type);
388 if (!obj_desc) {
389 return (AE_NO_MEMORY);
390 }
391
392 /* Initialize the new object */
393
394 status = acpi_ds_init_object_from_op (walk_state, arg,
395 opcode, &obj_desc);
396 if (ACPI_FAILURE (status)) {
397 acpi_cm_delete_object_desc (obj_desc);
398 return (status);
399 }
400 }
401
402 /* Put the operand object on the object stack */
403
404 status = acpi_ds_obj_stack_push (obj_desc, walk_state);
405 if (ACPI_FAILURE (status)) {
406 return (status);
407 }
408
409 DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state));
410 }
411
412 return (AE_OK);
413 }
414
415
416 /*******************************************************************************
417 *
418 * FUNCTION: Acpi_ds_create_operands
419 *
420 * PARAMETERS: First_arg - First argument of a parser argument tree
421 *
422 * RETURN: Status
423 *
424 * DESCRIPTION: Convert an operator's arguments from a parse tree format to
425 * namespace objects and place those argument object on the object
426 * stack in preparation for evaluation by the interpreter.
427 *
428 ******************************************************************************/
429
430 ACPI_STATUS
431 acpi_ds_create_operands (
432 ACPI_WALK_STATE *walk_state,
433 ACPI_PARSE_OBJECT *first_arg)
434 {
435 ACPI_STATUS status = AE_OK;
436 ACPI_PARSE_OBJECT *arg;
437 u32 arg_count = 0;
438
439
440 /* For all arguments in the list... */
441
442 arg = first_arg;
443 while (arg) {
444 status = acpi_ds_create_operand (walk_state, arg, arg_count);
445 if (ACPI_FAILURE (status)) {
446 goto cleanup;
447 }
448
449 /* Move on to next argument, if any */
450
451 arg = arg->next;
452 arg_count++;
453 }
454
455 return (status);
456
457
458 cleanup:
459 /*
460 * We must undo everything done above; meaning that we must
461 * pop everything off of the operand stack and delete those
462 * objects
463 */
464
465 acpi_ds_obj_stack_pop_and_delete (arg_count, walk_state);
466
467 return (status);
468 }
469
470
471 /*******************************************************************************
472 *
473 * FUNCTION: Acpi_ds_resolve_operands
474 *
475 * PARAMETERS: Walk_state - Current walk state with operands on stack
476 *
477 * RETURN: Status
478 *
479 * DESCRIPTION: Resolve all operands to their values. Used to prepare
480 * arguments to a control method invocation (a call from one
481 * method to another.)
482 *
483 ******************************************************************************/
484
485 ACPI_STATUS
486 acpi_ds_resolve_operands (
487 ACPI_WALK_STATE *walk_state)
488 {
489 u32 i;
490 ACPI_STATUS status = AE_OK;
491
492
493 /*
494 * Attempt to resolve each of the valid operands
495 * Method arguments are passed by value, not by reference
496 */
497
498 /*
499 * TBD: [Investigate] Note from previous parser:
500 * Ref_of problem with Acpi_aml_resolve_to_value() conversion.
501 */
502
503 for (i = 0; i < walk_state->num_operands; i++) {
504 status = acpi_aml_resolve_to_value (&walk_state->operands[i], walk_state);
505 if (ACPI_FAILURE (status)) {
506 break;
507 }
508 }
509
510 return (status);
511 }
512
513
514 /*******************************************************************************
515 *
516 * FUNCTION: Acpi_ds_map_opcode_to_data_type
517 *
518 * PARAMETERS: Opcode - AML opcode to map
519 * Out_flags - Additional info about the opcode
520 *
521 * RETURN: The ACPI type associated with the opcode
522 *
523 * DESCRIPTION: Convert a raw AML opcode to the associated ACPI data type,
524 * if any. If the opcode returns a value as part of the
525 * intepreter execution, a flag is returned in Out_flags.
526 *
527 ******************************************************************************/
528
529 OBJECT_TYPE_INTERNAL
530 acpi_ds_map_opcode_to_data_type (
531 u16 opcode,
532 u32 *out_flags)
533 {
534 OBJECT_TYPE_INTERNAL data_type = INTERNAL_TYPE_INVALID;
535 ACPI_OPCODE_INFO *op_info;
536 u32 flags = 0;
537
538
539 op_info = acpi_ps_get_opcode_info (opcode);
540 if (ACPI_GET_OP_TYPE (op_info) != ACPI_OP_TYPE_OPCODE) {
541 /* Unknown opcode */
542
543 return (data_type);
544 }
545
546 switch (ACPI_GET_OP_CLASS (op_info)) {
547
548 case OPTYPE_LITERAL:
549
550 switch (opcode) {
551 case AML_BYTE_OP:
552 case AML_WORD_OP:
553 case AML_DWORD_OP:
554
555 data_type = ACPI_TYPE_INTEGER;
556 break;
557
558
559 case AML_STRING_OP:
560
561 data_type = ACPI_TYPE_STRING;
562 break;
563
564 case AML_NAMEPATH_OP:
565 data_type = INTERNAL_TYPE_REFERENCE;
566 break;
567
568 default:
569 break;
570 }
571 break;
572
573
574 case OPTYPE_DATA_TERM:
575
576 switch (opcode) {
577 case AML_BUFFER_OP:
578
579 data_type = ACPI_TYPE_BUFFER;
580 break;
581
582 case AML_PACKAGE_OP:
583
584 data_type = ACPI_TYPE_PACKAGE;
585 break;
586
587 default:
588 break;
589 }
590 break;
591
592
593 case OPTYPE_CONSTANT:
594 case OPTYPE_METHOD_ARGUMENT:
595 case OPTYPE_LOCAL_VARIABLE:
596
597 data_type = INTERNAL_TYPE_REFERENCE;
598 break;
599
600
601 case OPTYPE_MONADIC2:
602 case OPTYPE_MONADIC2_r:
603 case OPTYPE_DYADIC2:
604 case OPTYPE_DYADIC2_r:
605 case OPTYPE_DYADIC2_s:
606 case OPTYPE_INDEX:
607 case OPTYPE_MATCH:
608 case OPTYPE_RETURN:
609
610 flags = OP_HAS_RETURN_VALUE;
611 data_type = ACPI_TYPE_ANY;
612 break;
613
614 case OPTYPE_METHOD_CALL:
615
616 flags = OP_HAS_RETURN_VALUE;
617 data_type = ACPI_TYPE_METHOD;
618 break;
619
620
621 case OPTYPE_NAMED_OBJECT:
622
623 data_type = acpi_ds_map_named_opcode_to_data_type (opcode);
624 break;
625
626
627 case OPTYPE_DYADIC1:
628 case OPTYPE_CONTROL:
629
630 /* No mapping needed at this time */
631
632 break;
633
634
635 default:
636
637 break;
638 }
639
640 /* Return flags to caller if requested */
641
642 if (out_flags) {
643 *out_flags = flags;
644 }
645
646 return (data_type);
647 }
648
649
650 /*******************************************************************************
651 *
652 * FUNCTION: Acpi_ds_map_named_opcode_to_data_type
653 *
654 * PARAMETERS: Opcode - The Named AML opcode to map
655 *
656 * RETURN: The ACPI type associated with the named opcode
657 *
658 * DESCRIPTION: Convert a raw Named AML opcode to the associated data type.
659 * Named opcodes are a subsystem of the AML opcodes.
660 *
661 ******************************************************************************/
662
663 OBJECT_TYPE_INTERNAL
664 acpi_ds_map_named_opcode_to_data_type (
665 u16 opcode)
666 {
667 OBJECT_TYPE_INTERNAL data_type;
668
669
670 /* Decode Opcode */
671
672 switch (opcode) {
673 case AML_SCOPE_OP:
674 data_type = INTERNAL_TYPE_SCOPE;
675 break;
676
677 case AML_DEVICE_OP:
678 data_type = ACPI_TYPE_DEVICE;
679 break;
680
681 case AML_THERMAL_ZONE_OP:
682 data_type = ACPI_TYPE_THERMAL;
683 break;
684
685 case AML_METHOD_OP:
686 data_type = ACPI_TYPE_METHOD;
687 break;
688
689 case AML_POWER_RES_OP:
690 data_type = ACPI_TYPE_POWER;
691 break;
692
693 case AML_PROCESSOR_OP:
694 data_type = ACPI_TYPE_PROCESSOR;
695 break;
696
697 case AML_DEF_FIELD_OP: /* Def_field_op */
698 data_type = INTERNAL_TYPE_DEF_FIELD_DEFN;
699 break;
700
701 case AML_INDEX_FIELD_OP: /* Index_field_op */
702 data_type = INTERNAL_TYPE_INDEX_FIELD_DEFN;
703 break;
704
705 case AML_BANK_FIELD_OP: /* Bank_field_op */
706 data_type = INTERNAL_TYPE_BANK_FIELD_DEFN;
707 break;
708
709 case AML_NAMEDFIELD_OP: /* NO CASE IN ORIGINAL */
710 data_type = ACPI_TYPE_ANY;
711 break;
712
713 case AML_NAME_OP: /* Name_op - special code in original */
714 case AML_NAMEPATH_OP:
715 data_type = ACPI_TYPE_ANY;
716 break;
717
718 case AML_ALIAS_OP:
719 data_type = INTERNAL_TYPE_ALIAS;
720 break;
721
722 case AML_MUTEX_OP:
723 data_type = ACPI_TYPE_MUTEX;
724 break;
725
726 case AML_EVENT_OP:
727 data_type = ACPI_TYPE_EVENT;
728 break;
729
730 case AML_REGION_OP:
731 data_type = ACPI_TYPE_REGION;
732 break;
733
734
735 default:
736 data_type = ACPI_TYPE_ANY;
737 break;
738
739 }
740
741 return (data_type);
742 }
743
744