Home | History | Annotate | Line # | Download | only in compiler
asltree.c revision 1.4.2.2
      1 /******************************************************************************
      2  *
      3  * Module Name: asltree - parse tree management
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2016, 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 #include <time.h>
     48 
     49 #define _COMPONENT          ACPI_COMPILER
     50         ACPI_MODULE_NAME    ("asltree")
     51 
     52 /* Local prototypes */
     53 
     54 static ACPI_PARSE_OBJECT *
     55 TrGetNextNode (
     56     void);
     57 
     58 
     59 /*******************************************************************************
     60  *
     61  * FUNCTION:    TrGetNextNode
     62  *
     63  * PARAMETERS:  None
     64  *
     65  * RETURN:      New parse node. Aborts on allocation failure
     66  *
     67  * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local
     68  *              dynamic memory manager for performance reasons (This has a
     69  *              major impact on the speed of the compiler.)
     70  *
     71  ******************************************************************************/
     72 
     73 static ACPI_PARSE_OBJECT *
     74 TrGetNextNode (
     75     void)
     76 {
     77     ASL_CACHE_INFO          *Cache;
     78 
     79 
     80     if (Gbl_ParseOpCacheNext >= Gbl_ParseOpCacheLast)
     81     {
     82         /* Allocate a new buffer */
     83 
     84         Cache = UtLocalCalloc (sizeof (Cache->Next) +
     85             (sizeof (ACPI_PARSE_OBJECT) * ASL_PARSEOP_CACHE_SIZE));
     86 
     87         /* Link new cache buffer to head of list */
     88 
     89         Cache->Next = Gbl_ParseOpCacheList;
     90         Gbl_ParseOpCacheList = Cache;
     91 
     92         /* Setup cache management pointers */
     93 
     94         Gbl_ParseOpCacheNext = ACPI_CAST_PTR (ACPI_PARSE_OBJECT, Cache->Buffer);
     95         Gbl_ParseOpCacheLast = Gbl_ParseOpCacheNext + ASL_PARSEOP_CACHE_SIZE;
     96     }
     97 
     98     Gbl_ParseOpCount++;
     99     return (Gbl_ParseOpCacheNext++);
    100 }
    101 
    102 
    103 /*******************************************************************************
    104  *
    105  * FUNCTION:    TrAllocateNode
    106  *
    107  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
    108  *
    109  * RETURN:      New parse node. Aborts on allocation failure
    110  *
    111  * DESCRIPTION: Allocate and initialize a new parse node for the parse tree
    112  *
    113  ******************************************************************************/
    114 
    115 ACPI_PARSE_OBJECT *
    116 TrAllocateNode (
    117     UINT32                  ParseOpcode)
    118 {
    119     ACPI_PARSE_OBJECT       *Op;
    120 
    121 
    122     Op = TrGetNextNode ();
    123 
    124     Op->Asl.ParseOpcode       = (UINT16) ParseOpcode;
    125     Op->Asl.Filename          = Gbl_Files[ASL_FILE_INPUT].Filename;
    126     Op->Asl.LineNumber        = Gbl_CurrentLineNumber;
    127     Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber;
    128     Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset;
    129     Op->Asl.Column            = Gbl_CurrentColumn;
    130 
    131     UtSetParseOpName (Op);
    132     return (Op);
    133 }
    134 
    135 
    136 /*******************************************************************************
    137  *
    138  * FUNCTION:    TrReleaseNode
    139  *
    140  * PARAMETERS:  Op            - Op to be released
    141  *
    142  * RETURN:      None
    143  *
    144  * DESCRIPTION: "release" a node. In truth, nothing is done since the node
    145  *              is part of a larger buffer
    146  *
    147  ******************************************************************************/
    148 
    149 void
    150 TrReleaseNode (
    151     ACPI_PARSE_OBJECT       *Op)
    152 {
    153 
    154     return;
    155 }
    156 
    157 
    158 /*******************************************************************************
    159  *
    160  * FUNCTION:    TrSetCurrentFilename
    161  *
    162  * PARAMETERS:  Op                  - An existing parse node
    163  *
    164  * RETURN:      None
    165  *
    166  * DESCRIPTION: Save the include file filename. Used for debug output only.
    167  *
    168  ******************************************************************************/
    169 
    170 void
    171 TrSetCurrentFilename (
    172     ACPI_PARSE_OBJECT       *Op)
    173 {
    174     Op->Asl.Filename = Gbl_PreviousIncludeFilename;
    175 }
    176 
    177 
    178 /*******************************************************************************
    179  *
    180  * FUNCTION:    TrUpdateNode
    181  *
    182  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
    183  *              Op                  - An existing parse node
    184  *
    185  * RETURN:      The updated node
    186  *
    187  * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to
    188  *              change an opcode to DEFAULT_ARG so that the node is ignored
    189  *              during the code generation. Also used to set generic integers
    190  *              to a specific size (8, 16, 32, or 64 bits)
    191  *
    192  ******************************************************************************/
    193 
    194 ACPI_PARSE_OBJECT *
    195 TrUpdateNode (
    196     UINT32                  ParseOpcode,
    197     ACPI_PARSE_OBJECT       *Op)
    198 {
    199 
    200     if (!Op)
    201     {
    202         return (NULL);
    203     }
    204 
    205     DbgPrint (ASL_PARSE_OUTPUT,
    206         "\nUpdateNode: Old - %s, New - %s\n",
    207         UtGetOpName (Op->Asl.ParseOpcode),
    208         UtGetOpName (ParseOpcode));
    209 
    210     /* Assign new opcode and name */
    211 
    212     if (Op->Asl.ParseOpcode == PARSEOP_ONES)
    213     {
    214         switch (ParseOpcode)
    215         {
    216         case PARSEOP_BYTECONST:
    217 
    218             Op->Asl.Value.Integer = ACPI_UINT8_MAX;
    219             break;
    220 
    221         case PARSEOP_WORDCONST:
    222 
    223             Op->Asl.Value.Integer = ACPI_UINT16_MAX;
    224             break;
    225 
    226         case PARSEOP_DWORDCONST:
    227 
    228             Op->Asl.Value.Integer = ACPI_UINT32_MAX;
    229             break;
    230 
    231         /* Don't need to do the QWORD case */
    232 
    233         default:
    234 
    235             /* Don't care about others */
    236             break;
    237         }
    238     }
    239 
    240     Op->Asl.ParseOpcode = (UINT16) ParseOpcode;
    241     UtSetParseOpName (Op);
    242 
    243     /*
    244      * For the BYTE, WORD, and DWORD constants, make sure that the integer
    245      * that was passed in will actually fit into the data type
    246      */
    247     switch (ParseOpcode)
    248     {
    249     case PARSEOP_BYTECONST:
    250 
    251         UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX);
    252         Op->Asl.Value.Integer &= ACPI_UINT8_MAX;
    253         break;
    254 
    255     case PARSEOP_WORDCONST:
    256 
    257         UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX);
    258         Op->Asl.Value.Integer &= ACPI_UINT16_MAX;
    259         break;
    260 
    261     case PARSEOP_DWORDCONST:
    262 
    263         UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX);
    264         Op->Asl.Value.Integer &= ACPI_UINT32_MAX;
    265         break;
    266 
    267     default:
    268 
    269         /* Don't care about others, don't need to check QWORD */
    270 
    271         break;
    272     }
    273 
    274     return (Op);
    275 }
    276 
    277 
    278 /*******************************************************************************
    279  *
    280  * FUNCTION:    TrPrintNodeCompileFlags
    281  *
    282  * PARAMETERS:  Flags               - Flags word to be decoded
    283  *
    284  * RETURN:      None
    285  *
    286  * DESCRIPTION: Decode a flags word to text. Displays all flags that are set.
    287  *
    288  ******************************************************************************/
    289 
    290 void
    291 TrPrintNodeCompileFlags (
    292     UINT32                  Flags)
    293 {
    294     UINT32                  i;
    295     UINT32                  FlagBit = 1;
    296     char                    *FlagName = NULL;
    297 
    298 
    299     for (i = 0; i < 32; i++)
    300     {
    301         switch (Flags & FlagBit)
    302         {
    303         case NODE_VISITED:
    304 
    305             FlagName = "NODE_VISITED";
    306             break;
    307 
    308         case NODE_AML_PACKAGE:
    309 
    310             FlagName = "NODE_AML_PACKAGE";
    311             break;
    312 
    313         case NODE_IS_TARGET:
    314 
    315             FlagName = "NODE_IS_TARGET";
    316             break;
    317 
    318         case NODE_IS_RESOURCE_DESC:
    319 
    320             FlagName = "NODE_IS_RESOURCE_DESC";
    321             break;
    322 
    323         case NODE_IS_RESOURCE_FIELD:
    324 
    325             FlagName = "NODE_IS_RESOURCE_FIELD";
    326             break;
    327 
    328         case NODE_HAS_NO_EXIT:
    329 
    330             FlagName = "NODE_HAS_NO_EXIT";
    331             break;
    332 
    333         case NODE_IF_HAS_NO_EXIT:
    334 
    335             FlagName = "NODE_IF_HAS_NO_EXIT";
    336             break;
    337 
    338         case NODE_NAME_INTERNALIZED:
    339 
    340             FlagName = "NODE_NAME_INTERNALIZED";
    341             break;
    342 
    343         case NODE_METHOD_NO_RETVAL:
    344 
    345             FlagName = "NODE_METHOD_NO_RETVAL";
    346             break;
    347 
    348         case NODE_METHOD_SOME_NO_RETVAL:
    349 
    350             FlagName = "NODE_METHOD_SOME_NO_RETVAL";
    351             break;
    352 
    353         case NODE_RESULT_NOT_USED:
    354 
    355             FlagName = "NODE_RESULT_NOT_USED";
    356             break;
    357 
    358         case NODE_METHOD_TYPED:
    359 
    360             FlagName = "NODE_METHOD_TYPED";
    361             break;
    362 
    363         case NODE_COULD_NOT_REDUCE:
    364 
    365             FlagName = "NODE_COULD_NOT_REDUCE";
    366             break;
    367 
    368         case NODE_COMPILE_TIME_CONST:
    369 
    370             FlagName = "NODE_COMPILE_TIME_CONST";
    371             break;
    372 
    373         case NODE_IS_TERM_ARG:
    374 
    375             FlagName = "NODE_IS_TERM_ARG";
    376             break;
    377 
    378         case NODE_WAS_ONES_OP:
    379 
    380             FlagName = "NODE_WAS_ONES_OP";
    381             break;
    382 
    383         case NODE_IS_NAME_DECLARATION:
    384 
    385             FlagName = "NODE_IS_NAME_DECLARATION";
    386             break;
    387 
    388         case NODE_COMPILER_EMITTED:
    389 
    390             FlagName = "NODE_COMPILER_EMITTED";
    391             break;
    392 
    393         case NODE_IS_DUPLICATE:
    394 
    395             FlagName = "NODE_IS_DUPLICATE";
    396             break;
    397 
    398         case NODE_IS_RESOURCE_DATA:
    399 
    400             FlagName = "NODE_IS_RESOURCE_DATA";
    401             break;
    402 
    403         case NODE_IS_NULL_RETURN:
    404 
    405             FlagName = "NODE_IS_NULL_RETURN";
    406             break;
    407 
    408         default:
    409             break;
    410         }
    411 
    412         if (FlagName)
    413         {
    414             DbgPrint (ASL_PARSE_OUTPUT, " %s", FlagName);
    415             FlagName = NULL;
    416         }
    417 
    418         FlagBit <<= 1;
    419     }
    420 }
    421 
    422 
    423 /*******************************************************************************
    424  *
    425  * FUNCTION:    TrSetNodeFlags
    426  *
    427  * PARAMETERS:  Op                  - An existing parse node
    428  *              Flags               - New flags word
    429  *
    430  * RETURN:      The updated parser op
    431  *
    432  * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set
    433  *
    434  ******************************************************************************/
    435 
    436 ACPI_PARSE_OBJECT *
    437 TrSetNodeFlags (
    438     ACPI_PARSE_OBJECT       *Op,
    439     UINT32                  Flags)
    440 {
    441 
    442     if (!Op)
    443     {
    444         return (NULL);
    445     }
    446 
    447     DbgPrint (ASL_PARSE_OUTPUT,
    448         "\nSetNodeFlags: %s Op %p, %8.8X", Op->Asl.ParseOpName, Op, Flags);
    449 
    450     TrPrintNodeCompileFlags (Flags);
    451     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
    452 
    453     Op->Asl.CompileFlags |= Flags;
    454     return (Op);
    455 }
    456 
    457 
    458 /*******************************************************************************
    459  *
    460  * FUNCTION:    TrSetNodeAmlLength
    461  *
    462  * PARAMETERS:  Op                  - An existing parse node
    463  *              Length              - AML Length
    464  *
    465  * RETURN:      The updated parser op
    466  *
    467  * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate
    468  *              the presence of a node that must be reduced to a fixed length
    469  *              constant.
    470  *
    471  ******************************************************************************/
    472 
    473 ACPI_PARSE_OBJECT *
    474 TrSetNodeAmlLength (
    475     ACPI_PARSE_OBJECT       *Op,
    476     UINT32                  Length)
    477 {
    478 
    479     DbgPrint (ASL_PARSE_OUTPUT,
    480         "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length);
    481 
    482     if (!Op)
    483     {
    484         return (NULL);
    485     }
    486 
    487     Op->Asl.AmlLength = Length;
    488     return (Op);
    489 }
    490 
    491 
    492 /*******************************************************************************
    493  *
    494  * FUNCTION:    TrSetEndLineNumber
    495  *
    496  * PARAMETERS:  Op                - An existing parse node
    497  *
    498  * RETURN:      None.
    499  *
    500  * DESCRIPTION: Set the ending line numbers (file line and logical line) of a
    501  *              parse node to the current line numbers.
    502  *
    503  ******************************************************************************/
    504 
    505 void
    506 TrSetEndLineNumber (
    507     ACPI_PARSE_OBJECT       *Op)
    508 {
    509 
    510     /* If the end line # is already set, just return */
    511 
    512     if (Op->Asl.EndLine)
    513     {
    514         return;
    515     }
    516 
    517     Op->Asl.EndLine = Gbl_CurrentLineNumber;
    518     Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber;
    519 }
    520 
    521 
    522 /*******************************************************************************
    523  *
    524  * FUNCTION:    TrCreateAssignmentNode
    525  *
    526  * PARAMETERS:  Target              - Assignment target
    527  *              Source              - Assignment source
    528  *
    529  * RETURN:      Pointer to the new node. Aborts on allocation failure
    530  *
    531  * DESCRIPTION: Implements the C-style '=' operator. It changes the parse
    532  *              tree if possible to utilize the last argument of the math
    533  *              operators which is a target operand -- thus saving invocation
    534  *              of and additional Store() operator. An optimization.
    535  *
    536  ******************************************************************************/
    537 
    538 ACPI_PARSE_OBJECT *
    539 TrCreateAssignmentNode (
    540     ACPI_PARSE_OBJECT       *Target,
    541     ACPI_PARSE_OBJECT       *Source)
    542 {
    543     ACPI_PARSE_OBJECT       *TargetOp;
    544     ACPI_PARSE_OBJECT       *SourceOp1;
    545     ACPI_PARSE_OBJECT       *SourceOp2;
    546     ACPI_PARSE_OBJECT       *Operator;
    547 
    548 
    549     DbgPrint (ASL_PARSE_OUTPUT,
    550         "\nTrCreateAssignmentNode  Line [%u to %u] Source %s Target %s\n",
    551         Source->Asl.LineNumber, Source->Asl.EndLine,
    552         UtGetOpName (Source->Asl.ParseOpcode),
    553         UtGetOpName (Target->Asl.ParseOpcode));
    554 
    555     TrSetNodeFlags (Target, NODE_IS_TARGET);
    556 
    557     switch (Source->Asl.ParseOpcode)
    558     {
    559     /*
    560      * Only these operators can be optimized because they have
    561      * a target operand
    562      */
    563     case PARSEOP_ADD:
    564     case PARSEOP_AND:
    565     case PARSEOP_DIVIDE:
    566     case PARSEOP_INDEX:
    567     case PARSEOP_MOD:
    568     case PARSEOP_MULTIPLY:
    569     case PARSEOP_NOT:
    570     case PARSEOP_OR:
    571     case PARSEOP_SHIFTLEFT:
    572     case PARSEOP_SHIFTRIGHT:
    573     case PARSEOP_SUBTRACT:
    574     case PARSEOP_XOR:
    575 
    576         break;
    577 
    578     /* Otherwise, just create a normal Store operator */
    579 
    580     default:
    581 
    582         goto CannotOptimize;
    583     }
    584 
    585     /*
    586      * Transform the parse tree such that the target is moved to the
    587      * last operand of the operator
    588      */
    589     SourceOp1 = Source->Asl.Child;
    590     SourceOp2 = SourceOp1->Asl.Next;
    591 
    592     /* NOT only has one operand, but has a target */
    593 
    594     if (Source->Asl.ParseOpcode == PARSEOP_NOT)
    595     {
    596         SourceOp2 = SourceOp1;
    597     }
    598 
    599     /* DIVIDE has an extra target operand (remainder) */
    600 
    601     if (Source->Asl.ParseOpcode == PARSEOP_DIVIDE)
    602     {
    603         SourceOp2 = SourceOp2->Asl.Next;
    604     }
    605 
    606     TargetOp = SourceOp2->Asl.Next;
    607 
    608     /*
    609      * Can't perform this optimization if there already is a target
    610      * for the operator (ZERO is a "no target" placeholder).
    611      */
    612     if (TargetOp->Asl.ParseOpcode != PARSEOP_ZERO)
    613     {
    614         goto CannotOptimize;
    615     }
    616 
    617     /* Link in the target as the final operand */
    618 
    619     SourceOp2->Asl.Next = Target;
    620     Target->Asl.Parent = Source;
    621 
    622     return (Source);
    623 
    624 
    625 CannotOptimize:
    626 
    627     Operator = TrAllocateNode (PARSEOP_STORE);
    628     TrLinkChildren (Operator, 2, Source, Target);
    629 
    630     /* Set the appropriate line numbers for the new node */
    631 
    632     Operator->Asl.LineNumber        = Target->Asl.LineNumber;
    633     Operator->Asl.LogicalLineNumber = Target->Asl.LogicalLineNumber;
    634     Operator->Asl.LogicalByteOffset = Target->Asl.LogicalByteOffset;
    635     Operator->Asl.Column            = Target->Asl.Column;
    636 
    637     return (Operator);
    638 }
    639 
    640 
    641 /*******************************************************************************
    642  *
    643  * FUNCTION:    TrCreateLeafNode
    644  *
    645  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
    646  *
    647  * RETURN:      Pointer to the new node. Aborts on allocation failure
    648  *
    649  * DESCRIPTION: Create a simple leaf node (no children or peers, and no value
    650  *              assigned to the node)
    651  *
    652  ******************************************************************************/
    653 
    654 ACPI_PARSE_OBJECT *
    655 TrCreateLeafNode (
    656     UINT32                  ParseOpcode)
    657 {
    658     ACPI_PARSE_OBJECT       *Op;
    659 
    660 
    661     Op = TrAllocateNode (ParseOpcode);
    662 
    663     DbgPrint (ASL_PARSE_OUTPUT,
    664         "\nCreateLeafNode  Ln/Col %u/%u NewNode %p  Op %s\n\n",
    665         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode));
    666 
    667     return (Op);
    668 }
    669 
    670 
    671 /*******************************************************************************
    672  *
    673  * FUNCTION:    TrCreateNullTarget
    674  *
    675  * PARAMETERS:  None
    676  *
    677  * RETURN:      Pointer to the new node. Aborts on allocation failure
    678  *
    679  * DESCRIPTION: Create a "null" target node. This is defined by the ACPI
    680  *              specification to be a zero AML opcode, and indicates that
    681  *              no target has been specified for the parent operation
    682  *
    683  ******************************************************************************/
    684 
    685 ACPI_PARSE_OBJECT *
    686 TrCreateNullTarget (
    687     void)
    688 {
    689     ACPI_PARSE_OBJECT       *Op;
    690 
    691 
    692     Op = TrAllocateNode (PARSEOP_ZERO);
    693     Op->Asl.CompileFlags |= (NODE_IS_TARGET | NODE_COMPILE_TIME_CONST);
    694 
    695     DbgPrint (ASL_PARSE_OUTPUT,
    696         "\nCreateNullTarget  Ln/Col %u/%u NewNode %p  Op %s\n",
    697         Op->Asl.LineNumber, Op->Asl.Column, Op,
    698         UtGetOpName (Op->Asl.ParseOpcode));
    699 
    700     return (Op);
    701 }
    702 
    703 
    704 /*******************************************************************************
    705  *
    706  * FUNCTION:    TrCreateConstantLeafNode
    707  *
    708  * PARAMETERS:  ParseOpcode         - The constant opcode
    709  *
    710  * RETURN:      Pointer to the new node. Aborts on allocation failure
    711  *
    712  * DESCRIPTION: Create a leaf node (no children or peers) for one of the
    713  *              special constants - __LINE__, __FILE__, and __DATE__.
    714  *
    715  * Note: An implemenation of __FUNC__ cannot happen here because we don't
    716  * have a full parse tree at this time and cannot find the parent control
    717  * method. If it is ever needed, __FUNC__ must be implemented later, after
    718  * the parse tree has been fully constructed.
    719  *
    720  ******************************************************************************/
    721 
    722 ACPI_PARSE_OBJECT *
    723 TrCreateConstantLeafNode (
    724     UINT32                  ParseOpcode)
    725 {
    726     ACPI_PARSE_OBJECT       *Op = NULL;
    727     time_t                  CurrentTime;
    728     char                    *StaticTimeString;
    729     char                    *TimeString;
    730     char                    *Filename;
    731 
    732 
    733     switch (ParseOpcode)
    734     {
    735     case PARSEOP___LINE__:
    736 
    737         Op = TrAllocateNode (PARSEOP_INTEGER);
    738         Op->Asl.Value.Integer = Op->Asl.LineNumber;
    739         break;
    740 
    741     case PARSEOP___PATH__:
    742 
    743         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
    744 
    745         /* Op.Asl.Filename contains the full pathname to the file */
    746 
    747         Op->Asl.Value.String = Op->Asl.Filename;
    748         break;
    749 
    750     case PARSEOP___FILE__:
    751 
    752         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
    753 
    754         /* Get the simple filename from the full path */
    755 
    756         FlSplitInputPathname (Op->Asl.Filename, NULL, &Filename);
    757         Op->Asl.Value.String = Filename;
    758         break;
    759 
    760     case PARSEOP___DATE__:
    761 
    762         Op = TrAllocateNode (PARSEOP_STRING_LITERAL);
    763 
    764         /* Get a copy of the current time */
    765 
    766         CurrentTime = time (NULL);
    767         StaticTimeString = ctime (&CurrentTime);
    768         TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1);
    769         strcpy (TimeString, StaticTimeString);
    770 
    771         TimeString[strlen(TimeString) -1] = 0;  /* Remove trailing newline */
    772         Op->Asl.Value.String = TimeString;
    773         break;
    774 
    775     default: /* This would be an internal error */
    776 
    777         return (NULL);
    778     }
    779 
    780     DbgPrint (ASL_PARSE_OUTPUT,
    781         "\nCreateConstantLeafNode  Ln/Col %u/%u NewNode %p  "
    782         "Op %s  Value %8.8X%8.8X  \n",
    783         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode),
    784         ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer));
    785     return (Op);
    786 }
    787 
    788 
    789 /*******************************************************************************
    790  *
    791  * FUNCTION:    TrCreateTargetOperand
    792  *
    793  * PARAMETERS:  OriginalOp          - Op to be copied
    794  *
    795  * RETURN:      Pointer to the new node. Aborts on allocation failure
    796  *
    797  * DESCRIPTION: Copy an existing node (and subtree). Used in ASL+ (C-style)
    798  *              expressions where the target is the same as one of the
    799  *              operands. A new node and subtree must be created from the
    800  *              original so that the parse tree can be linked properly.
    801  *
    802  * NOTE:        This code is specific to target operands that are the last
    803  *              operand in an ASL/AML operator. Meaning that the top-level
    804  *              parse Op in a possible subtree has a NULL Next pointer.
    805  *              This simplifies the recursion.
    806  *
    807  *              Subtree example:
    808  *                  DeRefOf (Local1) += 32
    809  *
    810  *              This gets converted to:
    811  *                  Add (DeRefOf (Local1), 32, DeRefOf (Local1))
    812  *
    813  *              Each DeRefOf has a single child, Local1. Even more complex
    814  *              subtrees can be created via the Index and DeRefOf operators.
    815  *
    816  ******************************************************************************/
    817 
    818 ACPI_PARSE_OBJECT *
    819 TrCreateTargetOperand (
    820     ACPI_PARSE_OBJECT       *OriginalOp,
    821     ACPI_PARSE_OBJECT       *ParentOp)
    822 {
    823     ACPI_PARSE_OBJECT       *Op;
    824 
    825 
    826     if (!OriginalOp)
    827     {
    828         return (NULL);
    829     }
    830 
    831     Op = TrGetNextNode ();
    832 
    833     /* Copy the pertinent values (omit link pointer fields) */
    834 
    835     Op->Asl.Value               = OriginalOp->Asl.Value;
    836     Op->Asl.Filename            = OriginalOp->Asl.Filename;
    837     Op->Asl.LineNumber          = OriginalOp->Asl.LineNumber;
    838     Op->Asl.LogicalLineNumber   = OriginalOp->Asl.LogicalLineNumber;
    839     Op->Asl.LogicalByteOffset   = OriginalOp->Asl.LogicalByteOffset;
    840     Op->Asl.Column              = OriginalOp->Asl.Column;
    841     Op->Asl.Flags               = OriginalOp->Asl.Flags;
    842     Op->Asl.CompileFlags        = OriginalOp->Asl.CompileFlags;
    843     Op->Asl.AmlOpcode           = OriginalOp->Asl.AmlOpcode;
    844     Op->Asl.ParseOpcode         = OriginalOp->Asl.ParseOpcode;
    845     Op->Asl.Parent              = ParentOp;
    846     UtSetParseOpName (Op);
    847 
    848     /* Copy a possible subtree below this node */
    849 
    850     if (OriginalOp->Asl.Child)
    851     {
    852         Op->Asl.Child = TrCreateTargetOperand (OriginalOp->Asl.Child, Op);
    853     }
    854 
    855     if (OriginalOp->Asl.Next) /* Null for top-level node */
    856     {
    857         Op->Asl.Next = TrCreateTargetOperand (OriginalOp->Asl.Next, ParentOp);
    858     }
    859 
    860     return (Op);
    861 }
    862 
    863 
    864 /*******************************************************************************
    865  *
    866  * FUNCTION:    TrCreateValuedLeafNode
    867  *
    868  * PARAMETERS:  ParseOpcode         - New opcode to be assigned to the node
    869  *              Value               - Value to be assigned to the node
    870  *
    871  * RETURN:      Pointer to the new node. Aborts on allocation failure
    872  *
    873  * DESCRIPTION: Create a leaf node (no children or peers) with a value
    874  *              assigned to it
    875  *
    876  ******************************************************************************/
    877 
    878 ACPI_PARSE_OBJECT *
    879 TrCreateValuedLeafNode (
    880     UINT32                  ParseOpcode,
    881     UINT64                  Value)
    882 {
    883     ACPI_PARSE_OBJECT       *Op;
    884 
    885 
    886     Op = TrAllocateNode (ParseOpcode);
    887 
    888     DbgPrint (ASL_PARSE_OUTPUT,
    889         "\nCreateValuedLeafNode  Ln/Col %u/%u NewNode %p  "
    890         "Op %s  Value %8.8X%8.8X  ",
    891         Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode),
    892         ACPI_FORMAT_UINT64 (Value));
    893     Op->Asl.Value.Integer = Value;
    894 
    895     switch (ParseOpcode)
    896     {
    897     case PARSEOP_STRING_LITERAL:
    898 
    899         DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value);
    900         break;
    901 
    902     case PARSEOP_NAMESEG:
    903 
    904         DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value);
    905         break;
    906 
    907     case PARSEOP_NAMESTRING:
    908 
    909         DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value);
    910         break;
    911 
    912     case PARSEOP_EISAID:
    913 
    914         DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value);
    915         break;
    916 
    917     case PARSEOP_METHOD:
    918 
    919         DbgPrint (ASL_PARSE_OUTPUT, "METHOD");
    920         break;
    921 
    922     case PARSEOP_INTEGER:
    923 
    924         DbgPrint (ASL_PARSE_OUTPUT, "INTEGER->%8.8X%8.8X",
    925             ACPI_FORMAT_UINT64 (Value));
    926         break;
    927 
    928     default:
    929 
    930         break;
    931     }
    932 
    933     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
    934     return (Op);
    935 }
    936 
    937 
    938 /*******************************************************************************
    939  *
    940  * FUNCTION:    TrCreateNode
    941  *
    942  * PARAMETERS:  ParseOpcode         - Opcode to be assigned to the node
    943  *              NumChildren         - Number of children to follow
    944  *              ...                 - A list of child nodes to link to the new
    945  *                                    node. NumChildren long.
    946  *
    947  * RETURN:      Pointer to the new node. Aborts on allocation failure
    948  *
    949  * DESCRIPTION: Create a new parse node and link together a list of child
    950  *              nodes underneath the new node.
    951  *
    952  ******************************************************************************/
    953 
    954 ACPI_PARSE_OBJECT *
    955 TrCreateNode (
    956     UINT32                  ParseOpcode,
    957     UINT32                  NumChildren,
    958     ...)
    959 {
    960     ACPI_PARSE_OBJECT       *Op;
    961     ACPI_PARSE_OBJECT       *Child;
    962     ACPI_PARSE_OBJECT       *PrevChild;
    963     va_list                 ap;
    964     UINT32                  i;
    965     BOOLEAN                 FirstChild;
    966 
    967 
    968     va_start (ap, NumChildren);
    969 
    970     /* Allocate one new node */
    971 
    972     Op = TrAllocateNode (ParseOpcode);
    973 
    974     DbgPrint (ASL_PARSE_OUTPUT,
    975         "\nCreateNode  Ln/Col %u/%u NewParent %p Child %u Op %s  ",
    976         Op->Asl.LineNumber, Op->Asl.Column, Op,
    977         NumChildren, UtGetOpName(ParseOpcode));
    978 
    979     /* Some extra debug output based on the parse opcode */
    980 
    981     switch (ParseOpcode)
    982     {
    983     case PARSEOP_ASL_CODE:
    984 
    985         RootNode = Op;
    986         Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
    987         DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
    988         break;
    989 
    990     case PARSEOP_DEFINITION_BLOCK:
    991 
    992         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
    993         break;
    994 
    995     case PARSEOP_OPERATIONREGION:
    996 
    997         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
    998         break;
    999 
   1000     case PARSEOP_OR:
   1001 
   1002         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
   1003         break;
   1004 
   1005     default:
   1006 
   1007         /* Nothing to do for other opcodes */
   1008 
   1009         break;
   1010     }
   1011 
   1012     /* Link the new node to its children */
   1013 
   1014     PrevChild = NULL;
   1015     FirstChild = TRUE;
   1016     for (i = 0; i < NumChildren; i++)
   1017     {
   1018         /* Get the next child */
   1019 
   1020         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
   1021         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
   1022 
   1023         /*
   1024          * If child is NULL, this means that an optional argument
   1025          * was omitted. We must create a placeholder with a special
   1026          * opcode (DEFAULT_ARG) so that the code generator will know
   1027          * that it must emit the correct default for this argument
   1028          */
   1029         if (!Child)
   1030         {
   1031             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
   1032         }
   1033 
   1034         /* Link first child to parent */
   1035 
   1036         if (FirstChild)
   1037         {
   1038             FirstChild = FALSE;
   1039             Op->Asl.Child = Child;
   1040         }
   1041 
   1042         /* Point all children to parent */
   1043 
   1044         Child->Asl.Parent = Op;
   1045 
   1046         /* Link children in a peer list */
   1047 
   1048         if (PrevChild)
   1049         {
   1050             PrevChild->Asl.Next = Child;
   1051         };
   1052 
   1053         /*
   1054          * This child might be a list, point all nodes in the list
   1055          * to the same parent
   1056          */
   1057         while (Child->Asl.Next)
   1058         {
   1059             Child = Child->Asl.Next;
   1060             Child->Asl.Parent = Op;
   1061         }
   1062 
   1063         PrevChild = Child;
   1064     }
   1065     va_end(ap);
   1066 
   1067     DbgPrint (ASL_PARSE_OUTPUT, "\n");
   1068     return (Op);
   1069 }
   1070 
   1071 
   1072 /*******************************************************************************
   1073  *
   1074  * FUNCTION:    TrLinkChildren
   1075  *
   1076  * PARAMETERS:  Op                - An existing parse node
   1077  *              NumChildren         - Number of children to follow
   1078  *              ...                 - A list of child nodes to link to the new
   1079  *                                    node. NumChildren long.
   1080  *
   1081  * RETURN:      The updated (linked) node
   1082  *
   1083  * DESCRIPTION: Link a group of nodes to an existing parse node
   1084  *
   1085  ******************************************************************************/
   1086 
   1087 ACPI_PARSE_OBJECT *
   1088 TrLinkChildren (
   1089     ACPI_PARSE_OBJECT       *Op,
   1090     UINT32                  NumChildren,
   1091     ...)
   1092 {
   1093     ACPI_PARSE_OBJECT       *Child;
   1094     ACPI_PARSE_OBJECT       *PrevChild;
   1095     va_list                 ap;
   1096     UINT32                  i;
   1097     BOOLEAN                 FirstChild;
   1098 
   1099 
   1100     va_start (ap, NumChildren);
   1101 
   1102 
   1103     TrSetEndLineNumber (Op);
   1104 
   1105     DbgPrint (ASL_PARSE_OUTPUT,
   1106         "\nLinkChildren  Line [%u to %u] NewParent %p Child %u Op %s  ",
   1107         Op->Asl.LineNumber, Op->Asl.EndLine,
   1108         Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode));
   1109 
   1110     switch (Op->Asl.ParseOpcode)
   1111     {
   1112     case PARSEOP_ASL_CODE:
   1113 
   1114         RootNode = Op;
   1115         Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
   1116         DbgPrint (ASL_PARSE_OUTPUT, "ASLCODE (Tree Completed)->");
   1117         break;
   1118 
   1119     case PARSEOP_DEFINITION_BLOCK:
   1120 
   1121         DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->");
   1122         break;
   1123 
   1124     case PARSEOP_OPERATIONREGION:
   1125 
   1126         DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->");
   1127         break;
   1128 
   1129     case PARSEOP_OR:
   1130 
   1131         DbgPrint (ASL_PARSE_OUTPUT, "OR->");
   1132         break;
   1133 
   1134     default:
   1135 
   1136         /* Nothing to do for other opcodes */
   1137 
   1138         break;
   1139     }
   1140 
   1141     /* Link the new node to it's children */
   1142 
   1143     PrevChild = NULL;
   1144     FirstChild = TRUE;
   1145     for (i = 0; i < NumChildren; i++)
   1146     {
   1147         Child = va_arg (ap, ACPI_PARSE_OBJECT *);
   1148 
   1149         if ((Child == PrevChild) && (Child != NULL))
   1150         {
   1151             AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child,
   1152                 "Child node list invalid");
   1153             va_end(ap);
   1154             return (Op);
   1155         }
   1156 
   1157         DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child);
   1158 
   1159         /*
   1160          * If child is NULL, this means that an optional argument
   1161          * was omitted. We must create a placeholder with a special
   1162          * opcode (DEFAULT_ARG) so that the code generator will know
   1163          * that it must emit the correct default for this argument
   1164          */
   1165         if (!Child)
   1166         {
   1167             Child = TrAllocateNode (PARSEOP_DEFAULT_ARG);
   1168         }
   1169 
   1170         /* Link first child to parent */
   1171 
   1172         if (FirstChild)
   1173         {
   1174             FirstChild = FALSE;
   1175             Op->Asl.Child = Child;
   1176         }
   1177 
   1178         /* Point all children to parent */
   1179 
   1180         Child->Asl.Parent = Op;
   1181 
   1182         /* Link children in a peer list */
   1183 
   1184         if (PrevChild)
   1185         {
   1186             PrevChild->Asl.Next = Child;
   1187         };
   1188 
   1189         /*
   1190          * This child might be a list, point all nodes in the list
   1191          * to the same parent
   1192          */
   1193         while (Child->Asl.Next)
   1194         {
   1195             Child = Child->Asl.Next;
   1196             Child->Asl.Parent = Op;
   1197         }
   1198 
   1199         PrevChild = Child;
   1200     }
   1201 
   1202     va_end(ap);
   1203     DbgPrint (ASL_PARSE_OUTPUT, "\n\n");
   1204     return (Op);
   1205 }
   1206 
   1207 
   1208 /*******************************************************************************
   1209  *
   1210  * FUNCTION:    TrLinkPeerNode
   1211  *
   1212  * PARAMETERS:  Op1           - First peer
   1213  *              Op2           - Second peer
   1214  *
   1215  * RETURN:      Op1 or the non-null node.
   1216  *
   1217  * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null.
   1218  *
   1219  ******************************************************************************/
   1220 
   1221 ACPI_PARSE_OBJECT *
   1222 TrLinkPeerNode (
   1223     ACPI_PARSE_OBJECT       *Op1,
   1224     ACPI_PARSE_OBJECT       *Op2)
   1225 {
   1226     ACPI_PARSE_OBJECT       *Next;
   1227 
   1228 
   1229     DbgPrint (ASL_PARSE_OUTPUT,
   1230         "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n",
   1231         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL,
   1232         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL);
   1233 
   1234 
   1235     if ((!Op1) && (!Op2))
   1236     {
   1237         DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n");
   1238         return (Op1);
   1239     }
   1240 
   1241     /* If one of the nodes is null, just return the non-null node */
   1242 
   1243     if (!Op2)
   1244     {
   1245         return (Op1);
   1246     }
   1247 
   1248     if (!Op1)
   1249     {
   1250         return (Op2);
   1251     }
   1252 
   1253     if (Op1 == Op2)
   1254     {
   1255         DbgPrint (ASL_DEBUG_OUTPUT,
   1256             "\n************* Internal error, linking node to itself %p\n",
   1257             Op1);
   1258         AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1,
   1259             "Linking node to itself");
   1260         return (Op1);
   1261     }
   1262 
   1263     Op1->Asl.Parent = Op2->Asl.Parent;
   1264 
   1265     /*
   1266      * Op 1 may already have a peer list (such as an IF/ELSE pair),
   1267      * so we must walk to the end of the list and attach the new
   1268      * peer at the end
   1269      */
   1270     Next = Op1;
   1271     while (Next->Asl.Next)
   1272     {
   1273         Next = Next->Asl.Next;
   1274     }
   1275 
   1276     Next->Asl.Next = Op2;
   1277     return (Op1);
   1278 }
   1279 
   1280 
   1281 /*******************************************************************************
   1282  *
   1283  * FUNCTION:    TrLinkPeerNodes
   1284  *
   1285  * PARAMETERS:  NumPeers            - The number of nodes in the list to follow
   1286  *              ...                 - A list of nodes to link together as peers
   1287  *
   1288  * RETURN:      The first node in the list (head of the peer list)
   1289  *
   1290  * DESCRIPTION: Link together an arbitrary number of peer nodes.
   1291  *
   1292  ******************************************************************************/
   1293 
   1294 ACPI_PARSE_OBJECT *
   1295 TrLinkPeerNodes (
   1296     UINT32                  NumPeers,
   1297     ...)
   1298 {
   1299     ACPI_PARSE_OBJECT       *This;
   1300     ACPI_PARSE_OBJECT       *Next;
   1301     va_list                 ap;
   1302     UINT32                  i;
   1303     ACPI_PARSE_OBJECT       *Start;
   1304 
   1305 
   1306     DbgPrint (ASL_PARSE_OUTPUT,
   1307         "\nLinkPeerNodes: (%u) ", NumPeers);
   1308 
   1309     va_start (ap, NumPeers);
   1310     This = va_arg (ap, ACPI_PARSE_OBJECT *);
   1311     Start = This;
   1312 
   1313     /*
   1314      * Link all peers
   1315      */
   1316     for (i = 0; i < (NumPeers -1); i++)
   1317     {
   1318         DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This);
   1319 
   1320         while (This->Asl.Next)
   1321         {
   1322             This = This->Asl.Next;
   1323         }
   1324 
   1325         /* Get another peer node */
   1326 
   1327         Next = va_arg (ap, ACPI_PARSE_OBJECT *);
   1328         if (!Next)
   1329         {
   1330             Next = TrAllocateNode (PARSEOP_DEFAULT_ARG);
   1331         }
   1332 
   1333         /* link new node to the current node */
   1334 
   1335         This->Asl.Next = Next;
   1336         This = Next;
   1337     }
   1338     va_end (ap);
   1339 
   1340     DbgPrint (ASL_PARSE_OUTPUT,"\n");
   1341     return (Start);
   1342 }
   1343 
   1344 
   1345 /*******************************************************************************
   1346  *
   1347  * FUNCTION:    TrLinkChildNode
   1348  *
   1349  * PARAMETERS:  Op1           - Parent node
   1350  *              Op2           - Op to become a child
   1351  *
   1352  * RETURN:      The parent node
   1353  *
   1354  * DESCRIPTION: Link two nodes together as a parent and child
   1355  *
   1356  ******************************************************************************/
   1357 
   1358 ACPI_PARSE_OBJECT *
   1359 TrLinkChildNode (
   1360     ACPI_PARSE_OBJECT       *Op1,
   1361     ACPI_PARSE_OBJECT       *Op2)
   1362 {
   1363     ACPI_PARSE_OBJECT       *Next;
   1364 
   1365 
   1366     DbgPrint (ASL_PARSE_OUTPUT,
   1367         "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n",
   1368         Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL,
   1369         Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL);
   1370 
   1371     if (!Op1 || !Op2)
   1372     {
   1373         return (Op1);
   1374     }
   1375 
   1376     Op1->Asl.Child = Op2;
   1377 
   1378     /* Set the child and all peers of the child to point to the parent */
   1379 
   1380     Next = Op2;
   1381     while (Next)
   1382     {
   1383         Next->Asl.Parent = Op1;
   1384         Next = Next->Asl.Next;
   1385     }
   1386 
   1387     return (Op1);
   1388 }
   1389 
   1390 
   1391 /*******************************************************************************
   1392  *
   1393  * FUNCTION:    TrWalkParseTree
   1394  *
   1395  * PARAMETERS:  Visitation              - Type of walk
   1396  *              DescendingCallback      - Called during tree descent
   1397  *              AscendingCallback       - Called during tree ascent
   1398  *              Context                 - To be passed to the callbacks
   1399  *
   1400  * RETURN:      Status from callback(s)
   1401  *
   1402  * DESCRIPTION: Walk the entire parse tree.
   1403  *
   1404  ******************************************************************************/
   1405 
   1406 ACPI_STATUS
   1407 TrWalkParseTree (
   1408     ACPI_PARSE_OBJECT       *Op,
   1409     UINT32                  Visitation,
   1410     ASL_WALK_CALLBACK       DescendingCallback,
   1411     ASL_WALK_CALLBACK       AscendingCallback,
   1412     void                    *Context)
   1413 {
   1414     UINT32                  Level;
   1415     BOOLEAN                 NodePreviouslyVisited;
   1416     ACPI_PARSE_OBJECT       *StartOp = Op;
   1417     ACPI_STATUS             Status;
   1418 
   1419 
   1420     if (!RootNode)
   1421     {
   1422         return (AE_OK);
   1423     }
   1424 
   1425     Level = 0;
   1426     NodePreviouslyVisited = FALSE;
   1427 
   1428     switch (Visitation)
   1429     {
   1430     case ASL_WALK_VISIT_DOWNWARD:
   1431 
   1432         while (Op)
   1433         {
   1434             if (!NodePreviouslyVisited)
   1435             {
   1436                 /* Let the callback process the node. */
   1437 
   1438                 Status = DescendingCallback (Op, Level, Context);
   1439                 if (ACPI_SUCCESS (Status))
   1440                 {
   1441                     /* Visit children first, once */
   1442 
   1443                     if (Op->Asl.Child)
   1444                     {
   1445                         Level++;
   1446                         Op = Op->Asl.Child;
   1447                         continue;
   1448                     }
   1449                 }
   1450                 else if (Status != AE_CTRL_DEPTH)
   1451                 {
   1452                     /* Exit immediately on any error */
   1453 
   1454                     return (Status);
   1455                 }
   1456             }
   1457 
   1458             /* Terminate walk at start op */
   1459 
   1460             if (Op == StartOp)
   1461             {
   1462                 break;
   1463             }
   1464 
   1465             /* No more children, visit peers */
   1466 
   1467             if (Op->Asl.Next)
   1468             {
   1469                 Op = Op->Asl.Next;
   1470                 NodePreviouslyVisited = FALSE;
   1471             }
   1472             else
   1473             {
   1474                 /* No children or peers, re-visit parent */
   1475 
   1476                 if (Level != 0 )
   1477                 {
   1478                     Level--;
   1479                 }
   1480                 Op = Op->Asl.Parent;
   1481                 NodePreviouslyVisited = TRUE;
   1482             }
   1483         }
   1484         break;
   1485 
   1486     case ASL_WALK_VISIT_UPWARD:
   1487 
   1488         while (Op)
   1489         {
   1490             /* Visit leaf node (no children) or parent node on return trip */
   1491 
   1492             if ((!Op->Asl.Child) ||
   1493                 (NodePreviouslyVisited))
   1494             {
   1495                 /* Let the callback process the node. */
   1496 
   1497                 Status = AscendingCallback (Op, Level, Context);
   1498                 if (ACPI_FAILURE (Status))
   1499                 {
   1500                     return (Status);
   1501                 }
   1502             }
   1503             else
   1504             {
   1505                 /* Visit children first, once */
   1506 
   1507                 Level++;
   1508                 Op = Op->Asl.Child;
   1509                 continue;
   1510             }
   1511 
   1512             /* Terminate walk at start op */
   1513 
   1514             if (Op == StartOp)
   1515             {
   1516                 break;
   1517             }
   1518 
   1519             /* No more children, visit peers */
   1520 
   1521             if (Op->Asl.Next)
   1522             {
   1523                 Op = Op->Asl.Next;
   1524                 NodePreviouslyVisited = FALSE;
   1525             }
   1526             else
   1527             {
   1528                 /* No children or peers, re-visit parent */
   1529 
   1530                 if (Level != 0 )
   1531                 {
   1532                     Level--;
   1533                 }
   1534                 Op = Op->Asl.Parent;
   1535                 NodePreviouslyVisited = TRUE;
   1536             }
   1537         }
   1538         break;
   1539 
   1540      case ASL_WALK_VISIT_TWICE:
   1541 
   1542         while (Op)
   1543         {
   1544             if (NodePreviouslyVisited)
   1545             {
   1546                 Status = AscendingCallback (Op, Level, Context);
   1547                 if (ACPI_FAILURE (Status))
   1548                 {
   1549                     return (Status);
   1550                 }
   1551             }
   1552             else
   1553             {
   1554                 /* Let the callback process the node. */
   1555 
   1556                 Status = DescendingCallback (Op, Level, Context);
   1557                 if (ACPI_SUCCESS (Status))
   1558                 {
   1559                     /* Visit children first, once */
   1560 
   1561                     if (Op->Asl.Child)
   1562                     {
   1563                         Level++;
   1564                         Op = Op->Asl.Child;
   1565                         continue;
   1566                     }
   1567                 }
   1568                 else if (Status != AE_CTRL_DEPTH)
   1569                 {
   1570                     /* Exit immediately on any error */
   1571 
   1572                     return (Status);
   1573                 }
   1574             }
   1575 
   1576             /* Terminate walk at start op */
   1577 
   1578             if (Op == StartOp)
   1579             {
   1580                 break;
   1581             }
   1582 
   1583             /* No more children, visit peers */
   1584 
   1585             if (Op->Asl.Next)
   1586             {
   1587                 Op = Op->Asl.Next;
   1588                 NodePreviouslyVisited = FALSE;
   1589             }
   1590             else
   1591             {
   1592                 /* No children or peers, re-visit parent */
   1593 
   1594                 if (Level != 0 )
   1595                 {
   1596                     Level--;
   1597                 }
   1598                 Op = Op->Asl.Parent;
   1599                 NodePreviouslyVisited = TRUE;
   1600             }
   1601         }
   1602         break;
   1603 
   1604     default:
   1605         /* No other types supported */
   1606         break;
   1607     }
   1608 
   1609     /* If we get here, the walk completed with no errors */
   1610 
   1611     return (AE_OK);
   1612 }
   1613