Merge trunk HEAD (46152)
[reactos.git] / drivers / bus / acpi / dispatcher / dsopcode.c
1 /******************************************************************************
2 *
3 * Module Name: dsopcode - Dispatcher Op Region support and handling of
4 * "control" opcodes
5 * $Revision: 1.1 $
6 *
7 *****************************************************************************/
8
9 /*
10 * Copyright (C) 2000, 2001 R. Byron Moore
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27
28 #include <acpi.h>
29
30 #define _COMPONENT ACPI_DISPATCHER
31 MODULE_NAME ("dsopcode")
32
33
34 /*****************************************************************************
35 *
36 * FUNCTION: Acpi_ds_get_field_unit_arguments
37 *
38 * PARAMETERS: Obj_desc - A valid Field_unit object
39 *
40 * RETURN: Status.
41 *
42 * DESCRIPTION: Get Field_unit Buffer and Index. This implements the late
43 * evaluation of these field attributes.
44 *
45 ****************************************************************************/
46
47 ACPI_STATUS
48 acpi_ds_get_field_unit_arguments (
49 ACPI_OPERAND_OBJECT *obj_desc)
50 {
51 ACPI_OPERAND_OBJECT *extra_desc;
52 ACPI_NAMESPACE_NODE *node;
53 ACPI_PARSE_OBJECT *op;
54 ACPI_PARSE_OBJECT *field_op;
55 ACPI_STATUS status;
56 ACPI_TABLE_DESC *table_desc;
57
58
59 if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
60 return (AE_OK);
61 }
62
63
64 /* Get the AML pointer (method object) and Field_unit node */
65
66 extra_desc = obj_desc->field_unit.extra;
67 node = obj_desc->field_unit.node;
68
69 /*
70 * Allocate a new parser op to be the root of the parsed
71 * Op_region tree
72 */
73
74 op = acpi_ps_alloc_op (AML_SCOPE_OP);
75 if (!op) {
76 return (AE_NO_MEMORY);
77 }
78
79 /* Save the Node for use in Acpi_ps_parse_aml */
80
81 op->node = acpi_ns_get_parent_object (node);
82
83 /* Get a handle to the parent ACPI table */
84
85 status = acpi_tb_handle_to_object (node->owner_id, &table_desc);
86 if (ACPI_FAILURE (status)) {
87 return (status);
88 }
89
90 /* Pass1: Parse the entire Field_unit declaration */
91
92 status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
93 extra_desc->extra.pcode_length, 0,
94 NULL, NULL, NULL, acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
95 if (ACPI_FAILURE (status)) {
96 acpi_ps_delete_parse_tree (op);
97 return (status);
98 }
99
100
101 /* Get and init the actual Fiel_unit_op created above */
102
103 field_op = op->value.arg;
104 op->node = node;
105
106
107 field_op = op->value.arg;
108 field_op->node = node;
109 acpi_ps_delete_parse_tree (op);
110
111 /* Acpi_evaluate the address and length arguments for the Op_region */
112
113 op = acpi_ps_alloc_op (AML_SCOPE_OP);
114 if (!op) {
115 return (AE_NO_MEMORY);
116 }
117
118 op->node = acpi_ns_get_parent_object (node);
119
120 status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
121 extra_desc->extra.pcode_length,
122 ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE,
123 NULL /*Method_desc*/, NULL, NULL,
124 acpi_ds_exec_begin_op, acpi_ds_exec_end_op);
125 /* All done with the parse tree, delete it */
126
127 acpi_ps_delete_parse_tree (op);
128
129
130 /*
131 * The pseudo-method object is no longer needed since the region is
132 * now initialized
133 */
134 acpi_cm_remove_reference (obj_desc->field_unit.extra);
135 obj_desc->field_unit.extra = NULL;
136
137 return (status);
138 }
139
140
141 /*****************************************************************************
142 *
143 * FUNCTION: Acpi_ds_get_region_arguments
144 *
145 * PARAMETERS: Obj_desc - A valid region object
146 *
147 * RETURN: Status.
148 *
149 * DESCRIPTION: Get region address and length. This implements the late
150 * evaluation of these region attributes.
151 *
152 ****************************************************************************/
153
154 ACPI_STATUS
155 acpi_ds_get_region_arguments (
156 ACPI_OPERAND_OBJECT *obj_desc)
157 {
158 ACPI_OPERAND_OBJECT *extra_desc = NULL;
159 ACPI_NAMESPACE_NODE *node;
160 ACPI_PARSE_OBJECT *op;
161 ACPI_PARSE_OBJECT *region_op;
162 ACPI_STATUS status;
163 ACPI_TABLE_DESC *table_desc;
164
165
166 if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
167 return (AE_OK);
168 }
169
170
171 /* Get the AML pointer (method object) and region node */
172
173 extra_desc = obj_desc->region.extra;
174 node = obj_desc->region.node;
175
176 /*
177 * Allocate a new parser op to be the root of the parsed
178 * Op_region tree
179 */
180
181 op = acpi_ps_alloc_op (AML_SCOPE_OP);
182 if (!op) {
183 return (AE_NO_MEMORY);
184 }
185
186 /* Save the Node for use in Acpi_ps_parse_aml */
187
188 op->node = acpi_ns_get_parent_object (node);
189
190 /* Get a handle to the parent ACPI table */
191
192 status = acpi_tb_handle_to_object (node->owner_id, &table_desc);
193 if (ACPI_FAILURE (status)) {
194 return (status);
195 }
196
197 /* Parse the entire Op_region declaration, creating a parse tree */
198
199 status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
200 extra_desc->extra.pcode_length, 0,
201 NULL, NULL, NULL, acpi_ds_load1_begin_op, acpi_ds_load1_end_op);
202
203 if (ACPI_FAILURE (status)) {
204 acpi_ps_delete_parse_tree (op);
205 return (status);
206 }
207
208
209 /* Get and init the actual Region_op created above */
210
211 region_op = op->value.arg;
212 op->node = node;
213
214
215 region_op = op->value.arg;
216 region_op->node = node;
217 acpi_ps_delete_parse_tree (op);
218
219 /* Acpi_evaluate the address and length arguments for the Op_region */
220
221 op = acpi_ps_alloc_op (AML_SCOPE_OP);
222 if (!op) {
223 return (AE_NO_MEMORY);
224 }
225
226 op->node = acpi_ns_get_parent_object (node);
227
228 status = acpi_ps_parse_aml (op, extra_desc->extra.pcode,
229 extra_desc->extra.pcode_length,
230 ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE,
231 NULL /*Method_desc*/, NULL, NULL,
232 acpi_ds_exec_begin_op, acpi_ds_exec_end_op);
233
234 /* All done with the parse tree, delete it */
235
236 acpi_ps_delete_parse_tree (op);
237
238 return (status);
239 }
240
241
242 /*****************************************************************************
243 *
244 * FUNCTION: Acpi_ds_initialize_region
245 *
246 * PARAMETERS: Op - A valid region Op object
247 *
248 * RETURN: Status
249 *
250 * DESCRIPTION:
251 *
252 ****************************************************************************/
253
254 ACPI_STATUS
255 acpi_ds_initialize_region (
256 ACPI_HANDLE obj_handle)
257 {
258 ACPI_OPERAND_OBJECT *obj_desc;
259 ACPI_STATUS status;
260
261
262 obj_desc = acpi_ns_get_attached_object (obj_handle);
263
264 /* Namespace is NOT locked */
265
266 status = acpi_ev_initialize_region (obj_desc, FALSE);
267
268 return (status);
269 }
270
271
272 /*****************************************************************************
273 *
274 * FUNCTION: Acpi_ds_eval_field_unit_operands
275 *
276 * PARAMETERS: Op - A valid Field_unit Op object
277 *
278 * RETURN: Status
279 *
280 * DESCRIPTION: Get Field_unit Buffer and Index
281 * Called from Acpi_ds_exec_end_op during Field_unit parse tree walk
282 *
283 ****************************************************************************/
284
285 ACPI_STATUS
286 acpi_ds_eval_field_unit_operands (
287 ACPI_WALK_STATE *walk_state,
288 ACPI_PARSE_OBJECT *op)
289 {
290 ACPI_STATUS status;
291 ACPI_OPERAND_OBJECT *field_desc;
292 ACPI_NAMESPACE_NODE *node;
293 ACPI_PARSE_OBJECT *next_op;
294 u32 offset;
295 u32 bit_offset;
296 u16 bit_count;
297
298
299 ACPI_OPERAND_OBJECT *res_desc = NULL;
300 ACPI_OPERAND_OBJECT *cnt_desc = NULL;
301 ACPI_OPERAND_OBJECT *off_desc = NULL;
302 ACPI_OPERAND_OBJECT *src_desc = NULL;
303 u32 num_operands = 3;
304
305
306 /*
307 * This is where we evaluate the address and length fields of the Op_field_unit declaration
308 */
309
310 node = op->node;
311
312 /* Next_op points to the op that holds the Buffer */
313 next_op = op->value.arg;
314
315 /* Acpi_evaluate/create the address and length operands */
316
317 status = acpi_ds_create_operands (walk_state, next_op);
318 if (ACPI_FAILURE (status)) {
319 return (status);
320 }
321
322 field_desc = acpi_ns_get_attached_object (node);
323 if (!field_desc) {
324 return (AE_NOT_EXIST);
325 }
326
327
328 /* Resolve the operands */
329
330 status = acpi_aml_resolve_operands (op->opcode, WALK_OPERANDS, walk_state);
331
332 /* Get the operands */
333
334 status |= acpi_ds_obj_stack_pop_object (&res_desc, walk_state);
335 if (AML_CREATE_FIELD_OP == op->opcode) {
336 num_operands = 4;
337 status |= acpi_ds_obj_stack_pop_object (&cnt_desc, walk_state);
338 }
339
340 status |= acpi_ds_obj_stack_pop_object (&off_desc, walk_state);
341 status |= acpi_ds_obj_stack_pop_object (&src_desc, walk_state);
342
343 if (ACPI_FAILURE (status)) {
344 /* Invalid parameters on object stack */
345
346 goto cleanup;
347 }
348
349
350 offset = (u32) off_desc->integer.value;
351
352
353 /*
354 * If Res_desc is a Name, it will be a direct name pointer after
355 * Acpi_aml_resolve_operands()
356 */
357
358 if (!VALID_DESCRIPTOR_TYPE (res_desc, ACPI_DESC_TYPE_NAMED)) {
359 status = AE_AML_OPERAND_TYPE;
360 goto cleanup;
361 }
362
363
364 /*
365 * Setup the Bit offsets and counts, according to the opcode
366 */
367
368 switch (op->opcode) {
369
370 /* Def_create_bit_field */
371
372 case AML_BIT_FIELD_OP:
373
374 /* Offset is in bits, Field is a bit */
375
376 bit_offset = offset;
377 bit_count = 1;
378 break;
379
380
381 /* Def_create_byte_field */
382
383 case AML_BYTE_FIELD_OP:
384
385 /* Offset is in bytes, field is a byte */
386
387 bit_offset = 8 * offset;
388 bit_count = 8;
389 break;
390
391
392 /* Def_create_word_field */
393
394 case AML_WORD_FIELD_OP:
395
396 /* Offset is in bytes, field is a word */
397
398 bit_offset = 8 * offset;
399 bit_count = 16;
400 break;
401
402
403 /* Def_create_dWord_field */
404
405 case AML_DWORD_FIELD_OP:
406
407 /* Offset is in bytes, field is a dword */
408
409 bit_offset = 8 * offset;
410 bit_count = 32;
411 break;
412
413
414 /* Def_create_field */
415
416 case AML_CREATE_FIELD_OP:
417
418 /* Offset is in bits, count is in bits */
419
420 bit_offset = offset;
421 bit_count = (u16) cnt_desc->integer.value;
422 break;
423
424
425 default:
426
427 status = AE_AML_BAD_OPCODE;
428 goto cleanup;
429 }
430
431
432 /*
433 * Setup field according to the object type
434 */
435
436 switch (src_desc->common.type) {
437
438 /* Source_buff := Term_arg=>Buffer */
439
440 case ACPI_TYPE_BUFFER:
441
442 if (bit_offset + (u32) bit_count >
443 (8 * (u32) src_desc->buffer.length)) {
444 status = AE_AML_BUFFER_LIMIT;
445 goto cleanup;
446 }
447
448
449 /* Construct the remainder of the field object */
450
451 field_desc->field_unit.access = (u8) ACCESS_ANY_ACC;
452 field_desc->field_unit.lock_rule = (u8) GLOCK_NEVER_LOCK;
453 field_desc->field_unit.update_rule = (u8) UPDATE_PRESERVE;
454 field_desc->field_unit.length = bit_count;
455 field_desc->field_unit.bit_offset = (u8) (bit_offset % 8);
456 field_desc->field_unit.offset = DIV_8 (bit_offset);
457 field_desc->field_unit.container = src_desc;
458
459 /* Reference count for Src_desc inherits Field_desc count */
460
461 src_desc->common.reference_count = (u16) (src_desc->common.reference_count +
462 field_desc->common.reference_count);
463
464 break;
465
466
467 /* Improper object type */
468
469 default:
470
471
472
473 status = AE_AML_OPERAND_TYPE;
474 goto cleanup;
475 }
476
477
478 if (AML_CREATE_FIELD_OP == op->opcode) {
479 /* Delete object descriptor unique to Create_field */
480
481 acpi_cm_remove_reference (cnt_desc);
482 cnt_desc = NULL;
483 }
484
485
486 cleanup:
487
488 /* Always delete the operands */
489
490 acpi_cm_remove_reference (off_desc);
491 acpi_cm_remove_reference (src_desc);
492
493 if (AML_CREATE_FIELD_OP == op->opcode) {
494 acpi_cm_remove_reference (cnt_desc);
495 }
496
497 /* On failure, delete the result descriptor */
498
499 if (ACPI_FAILURE (status)) {
500 acpi_cm_remove_reference (res_desc); /* Result descriptor */
501 }
502
503 else {
504 /* Now the address and length are valid for this op_field_unit */
505
506 field_desc->field_unit.flags |= AOPOBJ_DATA_VALID;
507 }
508
509 return (status);
510 }
511
512
513 /*****************************************************************************
514 *
515 * FUNCTION: Acpi_ds_eval_region_operands
516 *
517 * PARAMETERS: Op - A valid region Op object
518 *
519 * RETURN: Status
520 *
521 * DESCRIPTION: Get region address and length
522 * Called from Acpi_ds_exec_end_op during Op_region parse tree walk
523 *
524 ****************************************************************************/
525
526 ACPI_STATUS
527 acpi_ds_eval_region_operands (
528 ACPI_WALK_STATE *walk_state,
529 ACPI_PARSE_OBJECT *op)
530 {
531 ACPI_STATUS status;
532 ACPI_OPERAND_OBJECT *obj_desc;
533 ACPI_OPERAND_OBJECT *operand_desc;
534 ACPI_NAMESPACE_NODE *node;
535 ACPI_PARSE_OBJECT *next_op;
536
537
538 /*
539 * This is where we evaluate the address and length fields of the Op_region declaration
540 */
541
542 node = op->node;
543
544 /* Next_op points to the op that holds the Space_iD */
545 next_op = op->value.arg;
546
547 /* Next_op points to address op */
548 next_op = next_op->next;
549
550 /* Acpi_evaluate/create the address and length operands */
551
552 status = acpi_ds_create_operands (walk_state, next_op);
553 if (ACPI_FAILURE (status)) {
554 return (status);
555 }
556
557 /* Resolve the length and address operands to numbers */
558
559 status = acpi_aml_resolve_operands (op->opcode, WALK_OPERANDS, walk_state);
560 if (ACPI_FAILURE (status)) {
561 return (status);
562 }
563
564
565 obj_desc = acpi_ns_get_attached_object (node);
566 if (!obj_desc) {
567 return (AE_NOT_EXIST);
568 }
569
570 /*
571 * Get the length operand and save it
572 * (at Top of stack)
573 */
574 operand_desc = walk_state->operands[walk_state->num_operands - 1];
575
576 obj_desc->region.length = (u32) operand_desc->integer.value;
577 acpi_cm_remove_reference (operand_desc);
578
579 /*
580 * Get the address and save it
581 * (at top of stack - 1)
582 */
583 operand_desc = walk_state->operands[walk_state->num_operands - 2];
584
585 obj_desc->region.address = (ACPI_PHYSICAL_ADDRESS) operand_desc->integer.value;
586 acpi_cm_remove_reference (operand_desc);
587
588
589 /* Now the address and length are valid for this opregion */
590
591 obj_desc->region.flags |= AOPOBJ_DATA_VALID;
592
593 return (status);
594 }
595
596
597 /*******************************************************************************
598 *
599 * FUNCTION: Acpi_ds_exec_begin_control_op
600 *
601 * PARAMETERS: Walk_list - The list that owns the walk stack
602 * Op - The control Op
603 *
604 * RETURN: Status
605 *
606 * DESCRIPTION: Handles all control ops encountered during control method
607 * execution.
608 *
609 ******************************************************************************/
610
611 ACPI_STATUS
612 acpi_ds_exec_begin_control_op (
613 ACPI_WALK_STATE *walk_state,
614 ACPI_PARSE_OBJECT *op)
615 {
616 ACPI_STATUS status = AE_OK;
617 ACPI_GENERIC_STATE *control_state;
618
619
620 switch (op->opcode) {
621 case AML_IF_OP:
622 case AML_WHILE_OP:
623
624 /*
625 * IF/WHILE: Create a new control state to manage these
626 * constructs. We need to manage these as a stack, in order
627 * to handle nesting.
628 */
629
630 control_state = acpi_cm_create_control_state ();
631 if (!control_state) {
632 status = AE_NO_MEMORY;
633 break;
634 }
635
636 acpi_cm_push_generic_state (&walk_state->control_state, control_state);
637
638 /*
639 * Save a pointer to the predicate for multiple executions
640 * of a loop
641 */
642 walk_state->control_state->control.aml_predicate_start =
643 walk_state->parser_state->aml - 1;
644 /* TBD: can this be removed? */
645 /*Acpi_ps_pkg_length_encoding_size (GET8 (Walk_state->Parser_state->Aml));*/
646 break;
647
648
649 case AML_ELSE_OP:
650
651 /* Predicate is in the state object */
652 /* If predicate is true, the IF was executed, ignore ELSE part */
653
654 if (walk_state->last_predicate) {
655 status = AE_CTRL_TRUE;
656 }
657
658 break;
659
660
661 case AML_RETURN_OP:
662
663 break;
664
665
666 default:
667 break;
668 }
669
670 return (status);
671 }
672
673
674 /*******************************************************************************
675 *
676 * FUNCTION: Acpi_ds_exec_end_control_op
677 *
678 * PARAMETERS: Walk_list - The list that owns the walk stack
679 * Op - The control Op
680 *
681 * RETURN: Status
682 *
683 * DESCRIPTION: Handles all control ops encountered during control method
684 * execution.
685 *
686 *
687 ******************************************************************************/
688
689 ACPI_STATUS
690 acpi_ds_exec_end_control_op (
691 ACPI_WALK_STATE *walk_state,
692 ACPI_PARSE_OBJECT *op)
693 {
694 ACPI_STATUS status = AE_OK;
695 ACPI_GENERIC_STATE *control_state;
696
697
698 switch (op->opcode) {
699 case AML_IF_OP:
700
701 /*
702 * Save the result of the predicate in case there is an
703 * ELSE to come
704 */
705
706 walk_state->last_predicate =
707 (u8) walk_state->control_state->common.value;
708
709 /*
710 * Pop the control state that was created at the start
711 * of the IF and free it
712 */
713
714 control_state =
715 acpi_cm_pop_generic_state (&walk_state->control_state);
716
717 acpi_cm_delete_generic_state (control_state);
718
719 break;
720
721
722 case AML_ELSE_OP:
723
724 break;
725
726
727 case AML_WHILE_OP:
728
729 if (walk_state->control_state->common.value) {
730 /* Predicate was true, go back and evaluate it again! */
731
732 status = AE_CTRL_PENDING;
733 }
734
735
736 /* Pop this control state and free it */
737
738 control_state =
739 acpi_cm_pop_generic_state (&walk_state->control_state);
740
741 walk_state->aml_last_while = control_state->control.aml_predicate_start;
742 acpi_cm_delete_generic_state (control_state);
743
744 break;
745
746
747 case AML_RETURN_OP:
748
749
750 /*
751 * One optional operand -- the return value
752 * It can be either an immediate operand or a result that
753 * has been bubbled up the tree
754 */
755 if (op->value.arg) {
756 /* Return statement has an immediate operand */
757
758 status = acpi_ds_create_operands (walk_state, op->value.arg);
759 if (ACPI_FAILURE (status)) {
760 return (status);
761 }
762
763 /*
764 * If value being returned is a Reference (such as
765 * an arg or local), resolve it now because it may
766 * cease to exist at the end of the method.
767 */
768 status = acpi_aml_resolve_to_value (&walk_state->operands [0], walk_state);
769 if (ACPI_FAILURE (status)) {
770 return (status);
771 }
772
773 /*
774 * Get the return value and save as the last result
775 * value. This is the only place where Walk_state->Return_desc
776 * is set to anything other than zero!
777 */
778
779 walk_state->return_desc = walk_state->operands[0];
780 }
781
782 else if ((walk_state->results) &&
783 (walk_state->results->results.num_results > 0)) {
784 /*
785 * The return value has come from a previous calculation.
786 *
787 * If value being returned is a Reference (such as
788 * an arg or local), resolve it now because it may
789 * cease to exist at the end of the method.
790 *
791 * Allow references created by the Index operator to return unchanged.
792 */
793
794 if (VALID_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc [0], ACPI_DESC_TYPE_INTERNAL) &&
795 ((walk_state->results->results.obj_desc [0])->common.type == INTERNAL_TYPE_REFERENCE) &&
796 ((walk_state->results->results.obj_desc [0])->reference.opcode != AML_INDEX_OP)) {
797 status = acpi_aml_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state);
798 if (ACPI_FAILURE (status)) {
799 return (status);
800 }
801 }
802
803 walk_state->return_desc = walk_state->results->results.obj_desc [0];
804 }
805
806 else {
807 /* No return operand */
808
809 if (walk_state->num_operands) {
810 acpi_cm_remove_reference (walk_state->operands [0]);
811 }
812
813 walk_state->operands [0] = NULL;
814 walk_state->num_operands = 0;
815 walk_state->return_desc = NULL;
816 }
817
818
819 /* End the control method execution right now */
820 status = AE_CTRL_TERMINATE;
821 break;
822
823
824 case AML_NOOP_OP:
825
826 /* Just do nothing! */
827 break;
828
829
830 case AML_BREAK_POINT_OP:
831
832 /* Call up to the OS dependent layer to handle this */
833
834 acpi_os_breakpoint (NULL);
835
836 /* If it returns, we are done! */
837
838 break;
839
840
841 case AML_BREAK_OP:
842
843 /*
844 * As per the ACPI specification:
845 * "The break operation causes the current package
846 * execution to complete"
847 * "Break -- Stop executing the current code package
848 * at this point"
849 *
850 * Returning AE_FALSE here will cause termination of
851 * the current package, and execution will continue one
852 * level up, starting with the completion of the parent Op.
853 */
854
855 status = AE_CTRL_FALSE;
856 break;
857
858
859 default:
860
861 status = AE_AML_BAD_OPCODE;
862 break;
863 }
864
865
866 return (status);
867 }
868