xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/asltree.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /******************************************************************************
2  *
3  * Module Name: asltree - Parse tree management
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "acapps.h"
47 
48 #define _COMPONENT          ACPI_COMPILER
49         ACPI_MODULE_NAME    ("asltree")
50 
51 
52 /*******************************************************************************
53  *
54  * FUNCTION:    TrSetOpIntegerValue
55  *
56  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the op
57  *              Op                  - An existing parse op
58  *
59  * RETURN:      The updated op
60  *
61  * DESCRIPTION: Used to set the integer value of a op,
62  *              usually to a specific size (8, 16, 32, or 64 bits)
63  *
64  ******************************************************************************/
65 
66 ACPI_PARSE_OBJECT *
67 TrSetOpIntegerValue (
68     UINT32                  ParseOpcode,
69     ACPI_PARSE_OBJECT       *Op)
70 {
71 
72     if (!Op)
73     {
74         return (NULL);
75     }
76 
77     DbgPrint (ASL_PARSE_OUTPUT,
78         "\nUpdateOp: Old - %s, New - %s\n",
79         UtGetOpName (Op->Asl.ParseOpcode),
80         UtGetOpName (ParseOpcode));
81 
82     /* Assign new opcode and name */
83 
84     if (Op->Asl.ParseOpcode == PARSEOP_ONES)
85     {
86         switch (ParseOpcode)
87         {
88         case PARSEOP_BYTECONST:
89 
90             Op->Asl.Value.Integer = ACPI_UINT8_MAX;
91             break;
92 
93         case PARSEOP_WORDCONST:
94 
95             Op->Asl.Value.Integer = ACPI_UINT16_MAX;
96             break;
97 
98         case PARSEOP_DWORDCONST:
99 
100             Op->Asl.Value.Integer = ACPI_UINT32_MAX;
101             break;
102 
103         /* Don't need to do the QWORD case */
104 
105         default:
106 
107             /* Don't care about others */
108             break;
109         }
110     }
111 
112     Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
113     UtSetParseOpName (Op);
114 
115     /*
116      * For the BYTE, WORD, and DWORD constants, make sure that the integer
117      * that was passed in will actually fit into the data type
118      */
119     switch (ParseOpcode)
120     {
121     case PARSEOP_BYTECONST:
122 
123         UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
124         Op->Asl.Value.Integer &= ACPI_UINT8_MAX;
125         break;
126 
127     case PARSEOP_WORDCONST:
128 
129         UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
130         Op->Asl.Value.Integer &= ACPI_UINT16_MAX;
131         break;
132 
133     case PARSEOP_DWORDCONST:
134 
135         UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
136         Op->Asl.Value.Integer &= ACPI_UINT32_MAX;
137         break;
138 
139     default:
140 
141         /* Don't care about others, don't need to check QWORD */
142 
143         break;
144     }
145 
146     /* Converter: if this is a method invocation, turn off capture comments */
147 
148     if (AcpiGbl_CaptureComments &&
149         (ParseOpcode == PARSEOP_METHODCALL))
150     {
151         Gbl_CommentState.CaptureComments = FALSE;
152     }
153 
154     return (Op);
155 }
156 
157 
158 /*******************************************************************************
159  *
160  * FUNCTION:    TrSetOpFlags
161  *
162  * PARAMETERS:  Op                  - An existing parse op
163  *              Flags               - New flags word
164  *
165  * RETURN:      The updated parser op
166  *
167  * DESCRIPTION: Set bits in the op flags word. Will not clear bits, only set
168  *
169  ******************************************************************************/
170 
171 ACPI_PARSE_OBJECT *
172 TrSetOpFlags (
173     ACPI_PARSE_OBJECT       *Op,
174     UINT32                  Flags)
175 {
176 
177     if (!Op)
178     {
179         return (NULL);
180     }
181 
182     DbgPrint (ASL_PARSE_OUTPUT,
183         "\nSetOpFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags);
184 
185     TrPrintOpFlags (Flags, ASL_PARSE_OUTPUT);
186     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
187 
188     Op->Asl.CompileFlags |= Flags;
189     return (Op);
190 }
191 
192 
193 /*******************************************************************************
194  *
195  * FUNCTION:    TrSetOpAmlLength
196  *
197  * PARAMETERS:  Op                  - An existing parse op
198  *              Length              - AML Length
199  *
200  * RETURN:      The updated parser op
201  *
202  * DESCRIPTION: Set the AML Length in a op. Used by the parser to indicate
203  *              the presence of a op that must be reduced to a fixed length
204  *              constant.
205  *
206  ******************************************************************************/
207 
208 ACPI_PARSE_OBJECT *
209 TrSetOpAmlLength (
210     ACPI_PARSE_OBJECT       *Op,
211     UINT32                  Length)
212 {
213 
214     DbgPrint (ASL_PARSE_OUTPUT,
215         "\nSetOpAmlLength: Op %p, %8.8X\n", Op, Length);
216 
217     if (!Op)
218     {
219         return (NULL);
220     }
221 
222     Op->Asl.AmlLength = Length;
223     return (Op);
224 }
225 
226 
227 /*******************************************************************************
228  *
229  * FUNCTION:    TrSetOpParent
230  *
231  * PARAMETERS:  Op                  - To be set to new parent
232  *              ParentOp            - The parent
233  *
234  * RETURN:      None, sets Op parent directly
235  *
236  * DESCRIPTION: Change the parent of a parse op.
237  *
238  ******************************************************************************/
239 
240 void
241 TrSetOpParent (
242     ACPI_PARSE_OBJECT       *Op,
243     ACPI_PARSE_OBJECT       *ParentOp)
244 {
245 
246     Op->Asl.Parent = ParentOp;
247 }
248 
249 
250 /*******************************************************************************
251  *
252  * FUNCTION:    TrSetOpCurrentFilename
253  *
254  * PARAMETERS:  Op                  - An existing parse op
255  *
256  * RETURN:      None
257  *
258  * DESCRIPTION: Save the include file filename. Used for debug output only.
259  *
260  ******************************************************************************/
261 
262 void
263 TrSetOpCurrentFilename (
264     ACPI_PARSE_OBJECT       *Op)
265 {
266 
267     Op->Asl.Filename = Gbl_PreviousIncludeFilename;
268 }
269 
270 
271 /*******************************************************************************
272  *
273  * FUNCTION:    TrSetOpIntegerWidth
274  *
275  * PARAMETERS:  Op                  - An existing parse op
276  *
277  * RETURN:      None
278  *
279  * DESCRIPTION:
280  *
281  ******************************************************************************/
282 
283 void
284 TrSetOpIntegerWidth (
285     ACPI_PARSE_OBJECT       *TableSignatureOp,
286     ACPI_PARSE_OBJECT       *RevisionOp)
287 {
288 
289     /* TBD: Check table sig? (DSDT vs. SSDT) */
290 
291     /* Handle command-line version override */
292 
293     if (Gbl_RevisionOverride)
294     {
295         AcpiUtSetIntegerWidth (Gbl_RevisionOverride);
296     }
297     else
298     {
299         AcpiUtSetIntegerWidth ((UINT8) RevisionOp->Asl.Value.Integer);
300     }
301 }
302 
303 
304 /*******************************************************************************
305  *
306  * FUNCTION:    TrSetOpEndLineNumber
307  *
308  * PARAMETERS:  Op                - An existing parse op
309  *
310  * RETURN:      None.
311  *
312  * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
313  *              parse op to the current line numbers.
314  *
315  ******************************************************************************/
316 
317 void
318 TrSetOpEndLineNumber (
319     ACPI_PARSE_OBJECT       *Op)
320 {
321 
322     /* If the end line # is already set, just return */
323 
324     if (Op->Asl.EndLine)
325     {
326         return;
327     }
328 
329     Op->Asl.EndLine = Gbl_CurrentLineNumber;
330     Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber;
331 }
332 
333 
334 /*******************************************************************************
335  *
336  * FUNCTION:    TrLinkOpChildren
337  *
338  * PARAMETERS:  Op                - An existing parse op
339  *              NumChildren        - Number of children to follow
340  *              ...                - A list of child ops to link to the new
341  *                                   op. NumChildren long.
342  *
343  * RETURN:      The updated (linked) op
344  *
345  * DESCRIPTION: Link a group of ops to an existing parse op
346  *
347  ******************************************************************************/
348 
349 ACPI_PARSE_OBJECT *
350 TrLinkOpChildren (
351     ACPI_PARSE_OBJECT       *Op,
352     UINT32                  NumChildren,
353     ...)
354 {
355     ACPI_PARSE_OBJECT       *Child;
356     ACPI_PARSE_OBJECT       *PrevChild;
357     va_list                 ap;
358     UINT32                  i;
359     BOOLEAN                 FirstChild;
360 
361 
362     va_start (ap, NumChildren);
363 
364     TrSetOpEndLineNumber (Op);
365 
366     DbgPrint (ASL_PARSE_OUTPUT,
367         "\nLinkChildren  Line [%u to %u] NewParent %p Child %u Op %s  ",
368         Op->Asl.LineNumber, Op->Asl.EndLine,
369         Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
370 
371     switch (Op->Asl.ParseOpcode)
372     {
373     case PARSEOP_ASL_CODE:
374 
375         Gbl_ParseTreeRoot = Op;
376         Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
377         DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
378         break;
379 
380     case PARSEOP_DEFINITION_BLOCK:
381 
382         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
383         break;
384 
385     case PARSEOP_OPERATIONREGION:
386 
387         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
388         break;
389 
390     case PARSEOP_OR:
391 
392         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
393         break;
394 
395     default:
396 
397         /* Nothing to do for other opcodes */
398 
399         break;
400     }
401 
402     /* The following is for capturing comments */
403 
404     if (AcpiGbl_CaptureComments)
405     {
406         /*
407          * If there are "regular comments" detected at this point,
408          * then is an endBlk comment. Categorize it as so and distribute
409          * all regular comments to this parse op.
410          */
411         if (Gbl_CommentListHead)
412         {
413             Op->Asl.EndBlkComment = Gbl_CommentListHead;
414             CvDbgPrint ("EndBlk Comment for %s: %s",
415                 Op->Asl.ParseOpName, Gbl_CommentListHead->Comment);
416             Gbl_CommentListHead = NULL;
417             Gbl_CommentListTail = NULL;
418         }
419     }
420 
421     /* Link the new op to it's children */
422 
423     PrevChild = NULL;
424     FirstChild = TRUE;
425     for (i = 0; i < NumChildren; i++)
426     {
427         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
428 
429         if ((Child == PrevChild) && (Child != NULL))
430         {
431             AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
432                 "Child op list invalid");
433             va_end(ap);
434             return (Op);
435         }
436 
437         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
438 
439         /*
440          * If child is NULL, this means that an optional argument
441          * was omitted. We must create a placeholder with a special
442          * opcode (DEFAULT_ARG) so that the code generator will know
443          * that it must emit the correct default for this argument
444          */
445         if (!Child)
446         {
447             Child = TrAllocateOp (PARSEOP_DEFAULT_ARG);
448         }
449 
450         /* Link first child to parent */
451 
452         if (FirstChild)
453         {
454             FirstChild = FALSE;
455             Op->Asl.Child = Child;
456         }
457 
458         /* Point all children to parent */
459 
460         Child->Asl.Parent = Op;
461 
462         /* Link children in a peer list */
463 
464         if (PrevChild)
465         {
466             PrevChild->Asl.Next = Child;
467         }
468 
469         /*
470          * This child might be a list, point all ops in the list
471          * to the same parent
472          */
473         while (Child->Asl.Next)
474         {
475             Child = Child->Asl.Next;
476             Child->Asl.Parent = Op;
477         }
478 
479         PrevChild = Child;
480     }
481 
482     va_end(ap);
483     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
484 
485     if (AcpiGbl_CaptureComments)
486     {
487         Gbl_CommentState.LatestParseOp = Op;
488         CvDbgPrint ("TrLinkOpChildren=====Set latest parse op to this op.\n");
489     }
490 
491     return (Op);
492 }
493 
494 
495 /*******************************************************************************
496  *
497  * FUNCTION:    TrLinkPeerOp
498  *
499  * PARAMETERS:  Op1           - First peer
500  *              Op2           - Second peer
501  *
502  * RETURN:      Op1 or the non-null op.
503  *
504  * DESCRIPTION: Link two ops as peers. Handles cases where one peer is null.
505  *
506  ******************************************************************************/
507 
508 ACPI_PARSE_OBJECT *
509 TrLinkPeerOp (
510     ACPI_PARSE_OBJECT       *Op1,
511     ACPI_PARSE_OBJECT       *Op2)
512 {
513     ACPI_PARSE_OBJECT       *Next;
514 
515 
516     DbgPrint (ASL_PARSE_OUTPUT,
517         "\nLinkPeerOp: 1=%p (%s), 2=%p (%s)\n",
518         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
519         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
520 
521 
522     if ((!Op1) && (!Op2))
523     {
524         DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null ops!\n");
525         return (Op1);
526     }
527 
528     /* If one of the ops is null, just return the non-null op */
529 
530     if (!Op2)
531     {
532         return (Op1);
533     }
534 
535     if (!Op1)
536     {
537         return (Op2);
538     }
539 
540     if (Op1 == Op2)
541     {
542         DbgPrint (ASL_DEBUG_OUTPUT,
543             "\n************* Internal error, linking op to itself %p\n",
544             Op1);
545         AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
546             "Linking op to itself");
547         return (Op1);
548     }
549 
550     Op1->Asl.Parent = Op2->Asl.Parent;
551 
552     /*
553      * Op 1 may already have a peer list (such as an IF/ELSE pair),
554      * so we must walk to the end of the list and attach the new
555      * peer at the end
556      */
557     Next = Op1;
558     while (Next->Asl.Next)
559     {
560         Next = Next->Asl.Next;
561     }
562 
563     Next->Asl.Next = Op2;
564     return (Op1);
565 }
566 
567 
568 /*******************************************************************************
569  *
570  * FUNCTION:    TrLinkPeerOps
571  *
572  * PARAMETERS:  NumPeers            - The number of ops in the list to follow
573  *              ...                 - A list of ops to link together as peers
574  *
575  * RETURN:      The first op in the list (head of the peer list)
576  *
577  * DESCRIPTION: Link together an arbitrary number of peer ops.
578  *
579  ******************************************************************************/
580 
581 ACPI_PARSE_OBJECT *
582 TrLinkPeerOps (
583     UINT32                  NumPeers,
584     ...)
585 {
586     ACPI_PARSE_OBJECT       *This;
587     ACPI_PARSE_OBJECT       *Next;
588     va_list                 ap;
589     UINT32                  i;
590     ACPI_PARSE_OBJECT       *Start;
591 
592 
593     DbgPrint (ASL_PARSE_OUTPUT,
594         "\nLinkPeerOps: (%u) ", NumPeers);
595 
596     va_start (ap, NumPeers);
597     This = va_arg (ap, ACPI_PARSE_OBJECT *);
598     Start = This;
599 
600     /*
601      * Link all peers
602      */
603     for (i = 0; i < (NumPeers -1); i++)
604     {
605         DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
606 
607         while (This->Asl.Next)
608         {
609             This = This->Asl.Next;
610         }
611 
612         /* Get another peer op */
613 
614         Next = va_arg (ap, ACPI_PARSE_OBJECT *);
615         if (!Next)
616         {
617             Next = TrAllocateOp (PARSEOP_DEFAULT_ARG);
618         }
619 
620         /* link new op to the current op */
621 
622         This->Asl.Next = Next;
623         This = Next;
624     }
625 
626     va_end (ap);
627     DbgPrint (ASL_PARSE_OUTPUT,"\n");
628     return (Start);
629 }
630 
631 
632 /*******************************************************************************
633  *
634  * FUNCTION:    TrLinkChildOp
635  *
636  * PARAMETERS:  Op1           - Parent op
637  *              Op2           - Op to become a child
638  *
639  * RETURN:      The parent op
640  *
641  * DESCRIPTION: Link two ops together as a parent and child
642  *
643  ******************************************************************************/
644 
645 ACPI_PARSE_OBJECT *
646 TrLinkChildOp (
647     ACPI_PARSE_OBJECT       *Op1,
648     ACPI_PARSE_OBJECT       *Op2)
649 {
650     ACPI_PARSE_OBJECT       *Next;
651 
652 
653     DbgPrint (ASL_PARSE_OUTPUT,
654         "\nLinkChildOp: Parent=%p (%s), Child=%p (%s)\n",
655         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
656         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
657 
658     /*
659      * Converter: if TrLinkChildOp is called to link a method call,
660      * turn on capture comments as it signifies that we are done parsing
661      * a method call.
662      */
663     if (AcpiGbl_CaptureComments && Op1)
664     {
665         if (Op1->Asl.ParseOpcode == PARSEOP_METHODCALL)
666         {
667             Gbl_CommentState.CaptureComments = TRUE;
668         }
669         Gbl_CommentState.LatestParseOp = Op1;
670     }
671 
672     if (!Op1 || !Op2)
673     {
674         return (Op1);
675     }
676 
677     Op1->Asl.Child = Op2;
678 
679     /* Set the child and all peers of the child to point to the parent */
680 
681     Next = Op2;
682     while (Next)
683     {
684         Next->Asl.Parent = Op1;
685         Next = Next->Asl.Next;
686     }
687 
688     return (Op1);
689 }
690 
691 
692 /*******************************************************************************
693  *
694  * FUNCTION:    TrWalkParseTree
695  *
696  * PARAMETERS:  Op                      - Walk starting point
697  *              Visitation              - Type of walk
698  *              DescendingCallback      - Called during tree descent
699  *              AscendingCallback       - Called during tree ascent
700  *              Context                 - To be passed to the callbacks
701  *
702  * RETURN:      Status from callback(s)
703  *
704  * DESCRIPTION: Walk the entire parse tree.
705  *
706  ******************************************************************************/
707 
708 ACPI_STATUS
709 TrWalkParseTree (
710     ACPI_PARSE_OBJECT       *Op,
711     UINT32                  Visitation,
712     ASL_WALK_CALLBACK       DescendingCallback,
713     ASL_WALK_CALLBACK       AscendingCallback,
714     void                    *Context)
715 {
716     UINT32                  Level;
717     BOOLEAN                 OpPreviouslyVisited;
718     ACPI_PARSE_OBJECT       *StartOp = Op;
719     ACPI_STATUS             Status;
720 
721 
722     if (!Gbl_ParseTreeRoot)
723     {
724         return (AE_OK);
725     }
726 
727     Level = 0;
728     OpPreviouslyVisited = FALSE;
729 
730     switch (Visitation)
731     {
732     case ASL_WALK_VISIT_DOWNWARD:
733 
734         while (Op)
735         {
736             if (!OpPreviouslyVisited)
737             {
738                 /* Let the callback process the op. */
739 
740                 Status = DescendingCallback (Op, Level, Context);
741                 if (ACPI_SUCCESS (Status))
742                 {
743                     /* Visit children first, once */
744 
745                     if (Op->Asl.Child)
746                     {
747                         Level++;
748                         Op = Op->Asl.Child;
749                         continue;
750                     }
751                 }
752                 else if (Status != AE_CTRL_DEPTH)
753                 {
754                     /* Exit immediately on any error */
755 
756                     return (Status);
757                 }
758             }
759 
760             /* Terminate walk at start op */
761 
762             if (Op == StartOp)
763             {
764                 break;
765             }
766 
767             /* No more children, visit peers */
768 
769             if (Op->Asl.Next)
770             {
771                 Op = Op->Asl.Next;
772                 OpPreviouslyVisited = FALSE;
773             }
774             else
775             {
776                 /* No children or peers, re-visit parent */
777 
778                 if (Level != 0 )
779                 {
780                     Level--;
781                 }
782                 Op = Op->Asl.Parent;
783                 OpPreviouslyVisited = TRUE;
784             }
785         }
786         break;
787 
788     case ASL_WALK_VISIT_UPWARD:
789 
790         while (Op)
791         {
792             /* Visit leaf op (no children) or parent op on return trip */
793 
794             if ((!Op->Asl.Child) ||
795                 (OpPreviouslyVisited))
796             {
797                 /* Let the callback process the op. */
798 
799                 Status = AscendingCallback (Op, Level, Context);
800                 if (ACPI_FAILURE (Status))
801                 {
802                     return (Status);
803                 }
804             }
805             else
806             {
807                 /* Visit children first, once */
808 
809                 Level++;
810                 Op = Op->Asl.Child;
811                 continue;
812             }
813 
814             /* Terminate walk at start op */
815 
816             if (Op == StartOp)
817             {
818                 break;
819             }
820 
821             /* No more children, visit peers */
822 
823             if (Op->Asl.Next)
824             {
825                 Op = Op->Asl.Next;
826                 OpPreviouslyVisited = FALSE;
827             }
828             else
829             {
830                 /* No children or peers, re-visit parent */
831 
832                 if (Level != 0 )
833                 {
834                     Level--;
835                 }
836                 Op = Op->Asl.Parent;
837                 OpPreviouslyVisited = TRUE;
838             }
839         }
840         break;
841 
842      case ASL_WALK_VISIT_TWICE:
843 
844         while (Op)
845         {
846             if (OpPreviouslyVisited)
847             {
848                 Status = AscendingCallback (Op, Level, Context);
849                 if (ACPI_FAILURE (Status))
850                 {
851                     return (Status);
852                 }
853             }
854             else
855             {
856                 /* Let the callback process the op. */
857 
858                 Status = DescendingCallback (Op, Level, Context);
859                 if (ACPI_SUCCESS (Status))
860                 {
861                     /* Visit children first, once */
862 
863                     if (Op->Asl.Child)
864                     {
865                         Level++;
866                         Op = Op->Asl.Child;
867                         continue;
868                     }
869                 }
870                 else if (Status != AE_CTRL_DEPTH)
871                 {
872                     /* Exit immediately on any error */
873 
874                     return (Status);
875                 }
876             }
877 
878             /* Terminate walk at start op */
879 
880             if (Op == StartOp)
881             {
882                 break;
883             }
884 
885             /* No more children, visit peers */
886 
887             if (Op->Asl.Next)
888             {
889                 Op = Op->Asl.Next;
890                 OpPreviouslyVisited = FALSE;
891             }
892             else
893             {
894                 /* No children or peers, re-visit parent */
895 
896                 if (Level != 0 )
897                 {
898                     Level--;
899                 }
900                 Op = Op->Asl.Parent;
901                 OpPreviouslyVisited = TRUE;
902             }
903         }
904         break;
905 
906     default:
907         /* No other types supported */
908         break;
909     }
910 
911     /* If we get here, the walk completed with no errors */
912 
913     return (AE_OK);
914 }
915