asltree.c revision 239340
1118611Snjl 2118611Snjl/****************************************************************************** 3118611Snjl * 4118611Snjl * Module Name: asltree - parse tree management 5118611Snjl * 6118611Snjl *****************************************************************************/ 7118611Snjl 8217365Sjkim/* 9229989Sjkim * Copyright (C) 2000 - 2012, Intel Corp. 10118611Snjl * All rights reserved. 11118611Snjl * 12217365Sjkim * Redistribution and use in source and binary forms, with or without 13217365Sjkim * modification, are permitted provided that the following conditions 14217365Sjkim * are met: 15217365Sjkim * 1. Redistributions of source code must retain the above copyright 16217365Sjkim * notice, this list of conditions, and the following disclaimer, 17217365Sjkim * without modification. 18217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 19217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 20217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 21217365Sjkim * including a substantially similar Disclaimer requirement for further 22217365Sjkim * binary redistribution. 23217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 24217365Sjkim * of any contributors may be used to endorse or promote products derived 25217365Sjkim * from this software without specific prior written permission. 26118611Snjl * 27217365Sjkim * Alternatively, this software may be distributed under the terms of the 28217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 29217365Sjkim * Software Foundation. 30118611Snjl * 31217365Sjkim * NO WARRANTY 32217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 35217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 36217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 40217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 41217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 42217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 43217365Sjkim */ 44118611Snjl 45118611Snjl 46151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h> 47118611Snjl#include "aslcompiler.y.h" 48228110Sjkim#include <contrib/dev/acpica/include/acapps.h> 49218590Sjkim#include <time.h> 50118611Snjl 51118611Snjl#define _COMPONENT ACPI_COMPILER 52118611Snjl ACPI_MODULE_NAME ("asltree") 53118611Snjl 54151937Sjkim/* Local prototypes */ 55118611Snjl 56151937Sjkimstatic ACPI_PARSE_OBJECT * 57151937SjkimTrGetNextNode ( 58151937Sjkim void); 59151937Sjkim 60151937Sjkimstatic char * 61151937SjkimTrGetNodeFlagName ( 62151937Sjkim UINT32 Flags); 63151937Sjkim 64151937Sjkim 65118611Snjl/******************************************************************************* 66118611Snjl * 67118611Snjl * FUNCTION: TrGetNextNode 68118611Snjl * 69118611Snjl * PARAMETERS: None 70118611Snjl * 71239340Sjkim * RETURN: New parse node. Aborts on allocation failure 72118611Snjl * 73239340Sjkim * DESCRIPTION: Allocate a new parse node for the parse tree. Bypass the local 74118611Snjl * dynamic memory manager for performance reasons (This has a 75118611Snjl * major impact on the speed of the compiler.) 76118611Snjl * 77118611Snjl ******************************************************************************/ 78118611Snjl 79151937Sjkimstatic ACPI_PARSE_OBJECT * 80151937SjkimTrGetNextNode ( 81151937Sjkim void) 82118611Snjl{ 83118611Snjl 84118611Snjl if (Gbl_NodeCacheNext >= Gbl_NodeCacheLast) 85118611Snjl { 86151937Sjkim Gbl_NodeCacheNext = UtLocalCalloc (sizeof (ACPI_PARSE_OBJECT) * 87151937Sjkim ASL_NODE_CACHE_SIZE); 88118611Snjl Gbl_NodeCacheLast = Gbl_NodeCacheNext + ASL_NODE_CACHE_SIZE; 89118611Snjl } 90118611Snjl 91118611Snjl return (Gbl_NodeCacheNext++); 92118611Snjl} 93118611Snjl 94118611Snjl 95118611Snjl/******************************************************************************* 96118611Snjl * 97118611Snjl * FUNCTION: TrAllocateNode 98118611Snjl * 99118611Snjl * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 100118611Snjl * 101239340Sjkim * RETURN: New parse node. Aborts on allocation failure 102118611Snjl * 103118611Snjl * DESCRIPTION: Allocate and initialize a new parse node for the parse tree 104118611Snjl * 105118611Snjl ******************************************************************************/ 106118611Snjl 107118611SnjlACPI_PARSE_OBJECT * 108118611SnjlTrAllocateNode ( 109118611Snjl UINT32 ParseOpcode) 110118611Snjl{ 111118611Snjl ACPI_PARSE_OBJECT *Op; 112118611Snjl 113118611Snjl 114118611Snjl Op = TrGetNextNode (); 115118611Snjl 116118611Snjl Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 117118611Snjl Op->Asl.Filename = Gbl_Files[ASL_FILE_INPUT].Filename; 118118611Snjl Op->Asl.LineNumber = Gbl_CurrentLineNumber; 119118611Snjl Op->Asl.LogicalLineNumber = Gbl_LogicalLineNumber; 120118611Snjl Op->Asl.LogicalByteOffset = Gbl_CurrentLineOffset; 121118611Snjl Op->Asl.Column = Gbl_CurrentColumn; 122118611Snjl 123118611Snjl UtSetParseOpName (Op); 124118611Snjl return Op; 125118611Snjl} 126118611Snjl 127118611Snjl 128118611Snjl/******************************************************************************* 129118611Snjl * 130118611Snjl * FUNCTION: TrReleaseNode 131118611Snjl * 132118611Snjl * PARAMETERS: Op - Op to be released 133118611Snjl * 134118611Snjl * RETURN: None 135118611Snjl * 136239340Sjkim * DESCRIPTION: "release" a node. In truth, nothing is done since the node 137118611Snjl * is part of a larger buffer 138118611Snjl * 139118611Snjl ******************************************************************************/ 140118611Snjl 141118611Snjlvoid 142118611SnjlTrReleaseNode ( 143118611Snjl ACPI_PARSE_OBJECT *Op) 144118611Snjl{ 145118611Snjl 146118611Snjl return; 147118611Snjl} 148118611Snjl 149118611Snjl 150118611Snjl/******************************************************************************* 151118611Snjl * 152118611Snjl * FUNCTION: TrUpdateNode 153118611Snjl * 154118611Snjl * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 155118611Snjl * Op - An existing parse node 156118611Snjl * 157118611Snjl * RETURN: The updated node 158118611Snjl * 159239340Sjkim * DESCRIPTION: Change the parse opcode assigned to a node. Usually used to 160118611Snjl * change an opcode to DEFAULT_ARG so that the node is ignored 161239340Sjkim * during the code generation. Also used to set generic integers 162118611Snjl * to a specific size (8, 16, 32, or 64 bits) 163118611Snjl * 164118611Snjl ******************************************************************************/ 165118611Snjl 166118611SnjlACPI_PARSE_OBJECT * 167118611SnjlTrUpdateNode ( 168118611Snjl UINT32 ParseOpcode, 169118611Snjl ACPI_PARSE_OBJECT *Op) 170118611Snjl{ 171118611Snjl 172118611Snjl if (!Op) 173118611Snjl { 174118611Snjl return NULL; 175118611Snjl } 176118611Snjl 177118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 178118611Snjl "\nUpdateNode: Old - %s, New - %s\n\n", 179118611Snjl UtGetOpName (Op->Asl.ParseOpcode), 180118611Snjl UtGetOpName (ParseOpcode)); 181118611Snjl 182118611Snjl /* Assign new opcode and name */ 183118611Snjl 184118611Snjl if (Op->Asl.ParseOpcode == PARSEOP_ONES) 185118611Snjl { 186118611Snjl switch (ParseOpcode) 187118611Snjl { 188118611Snjl case PARSEOP_BYTECONST: 189239340Sjkim Op->Asl.Value.Integer = ACPI_UINT8_MAX; 190118611Snjl break; 191118611Snjl 192118611Snjl case PARSEOP_WORDCONST: 193239340Sjkim Op->Asl.Value.Integer = ACPI_UINT16_MAX; 194118611Snjl break; 195118611Snjl 196118611Snjl case PARSEOP_DWORDCONST: 197239340Sjkim Op->Asl.Value.Integer = ACPI_UINT32_MAX; 198118611Snjl break; 199118611Snjl 200239340Sjkim /* Don't need to do the QWORD case */ 201239340Sjkim 202118611Snjl default: 203239340Sjkim /* Don't care about others */ 204118611Snjl break; 205118611Snjl } 206118611Snjl } 207118611Snjl 208118611Snjl Op->Asl.ParseOpcode = (UINT16) ParseOpcode; 209118611Snjl UtSetParseOpName (Op); 210118611Snjl 211118611Snjl /* 212118611Snjl * For the BYTE, WORD, and DWORD constants, make sure that the integer 213118611Snjl * that was passed in will actually fit into the data type 214118611Snjl */ 215118611Snjl switch (ParseOpcode) 216118611Snjl { 217118611Snjl case PARSEOP_BYTECONST: 218239340Sjkim UtCheckIntegerRange (Op, 0x00, ACPI_UINT8_MAX); 219239340Sjkim Op->Asl.Value.Integer &= ACPI_UINT8_MAX; 220118611Snjl break; 221118611Snjl 222118611Snjl case PARSEOP_WORDCONST: 223239340Sjkim UtCheckIntegerRange (Op, 0x00, ACPI_UINT16_MAX); 224239340Sjkim Op->Asl.Value.Integer &= ACPI_UINT16_MAX; 225118611Snjl break; 226118611Snjl 227118611Snjl case PARSEOP_DWORDCONST: 228239340Sjkim UtCheckIntegerRange (Op, 0x00, ACPI_UINT32_MAX); 229239340Sjkim Op->Asl.Value.Integer &= ACPI_UINT32_MAX; 230118611Snjl break; 231118611Snjl 232118611Snjl default: 233118611Snjl /* Don't care about others, don't need to check QWORD */ 234118611Snjl break; 235118611Snjl } 236118611Snjl 237118611Snjl return Op; 238118611Snjl} 239118611Snjl 240118611Snjl 241118611Snjl/******************************************************************************* 242118611Snjl * 243118611Snjl * FUNCTION: TrGetNodeFlagName 244118611Snjl * 245118611Snjl * PARAMETERS: Flags - Flags word to be decoded 246118611Snjl * 247151937Sjkim * RETURN: Name string. Always returns a valid string pointer. 248118611Snjl * 249118611Snjl * DESCRIPTION: Decode a flags word 250118611Snjl * 251118611Snjl ******************************************************************************/ 252118611Snjl 253151937Sjkimstatic char * 254118611SnjlTrGetNodeFlagName ( 255118611Snjl UINT32 Flags) 256118611Snjl{ 257118611Snjl 258118611Snjl switch (Flags) 259118611Snjl { 260118611Snjl case NODE_VISITED: 261118611Snjl return ("NODE_VISITED"); 262118611Snjl 263118611Snjl case NODE_AML_PACKAGE: 264118611Snjl return ("NODE_AML_PACKAGE"); 265118611Snjl 266118611Snjl case NODE_IS_TARGET: 267118611Snjl return ("NODE_IS_TARGET"); 268118611Snjl 269118611Snjl case NODE_IS_RESOURCE_DESC: 270118611Snjl return ("NODE_IS_RESOURCE_DESC"); 271118611Snjl 272118611Snjl case NODE_IS_RESOURCE_FIELD: 273118611Snjl return ("NODE_IS_RESOURCE_FIELD"); 274118611Snjl 275118611Snjl case NODE_HAS_NO_EXIT: 276118611Snjl return ("NODE_HAS_NO_EXIT"); 277118611Snjl 278118611Snjl case NODE_IF_HAS_NO_EXIT: 279118611Snjl return ("NODE_IF_HAS_NO_EXIT"); 280118611Snjl 281118611Snjl case NODE_NAME_INTERNALIZED: 282118611Snjl return ("NODE_NAME_INTERNALIZED"); 283118611Snjl 284118611Snjl case NODE_METHOD_NO_RETVAL: 285118611Snjl return ("NODE_METHOD_NO_RETVAL"); 286118611Snjl 287118611Snjl case NODE_METHOD_SOME_NO_RETVAL: 288118611Snjl return ("NODE_METHOD_SOME_NO_RETVAL"); 289118611Snjl 290118611Snjl case NODE_RESULT_NOT_USED: 291118611Snjl return ("NODE_RESULT_NOT_USED"); 292118611Snjl 293118611Snjl case NODE_METHOD_TYPED: 294118611Snjl return ("NODE_METHOD_TYPED"); 295118611Snjl 296118611Snjl case NODE_COMPILE_TIME_CONST: 297118611Snjl return ("NODE_COMPILE_TIME_CONST"); 298118611Snjl 299118611Snjl case NODE_IS_TERM_ARG: 300118611Snjl return ("NODE_IS_TERM_ARG"); 301118611Snjl 302118611Snjl case NODE_WAS_ONES_OP: 303118611Snjl return ("NODE_WAS_ONES_OP"); 304118611Snjl 305118611Snjl case NODE_IS_NAME_DECLARATION: 306118611Snjl return ("NODE_IS_NAME_DECLARATION"); 307118611Snjl 308118611Snjl default: 309118611Snjl return ("Multiple Flags (or unknown flag) set"); 310118611Snjl } 311118611Snjl} 312118611Snjl 313118611Snjl 314118611Snjl/******************************************************************************* 315118611Snjl * 316118611Snjl * FUNCTION: TrSetNodeFlags 317118611Snjl * 318151937Sjkim * PARAMETERS: Op - An existing parse node 319118611Snjl * Flags - New flags word 320118611Snjl * 321151937Sjkim * RETURN: The updated parser op 322118611Snjl * 323239340Sjkim * DESCRIPTION: Set bits in the node flags word. Will not clear bits, only set 324118611Snjl * 325118611Snjl ******************************************************************************/ 326118611Snjl 327118611SnjlACPI_PARSE_OBJECT * 328118611SnjlTrSetNodeFlags ( 329118611Snjl ACPI_PARSE_OBJECT *Op, 330118611Snjl UINT32 Flags) 331118611Snjl{ 332118611Snjl 333118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 334151937Sjkim "\nSetNodeFlags: Op %p, %8.8X %s\n\n", Op, Flags, 335151937Sjkim TrGetNodeFlagName (Flags)); 336118611Snjl 337118611Snjl if (!Op) 338118611Snjl { 339118611Snjl return NULL; 340118611Snjl } 341118611Snjl 342118611Snjl Op->Asl.CompileFlags |= Flags; 343239340Sjkim return (Op); 344239340Sjkim} 345118611Snjl 346239340Sjkim 347239340Sjkim/******************************************************************************* 348239340Sjkim * 349239340Sjkim * FUNCTION: TrSetNodeAmlLength 350239340Sjkim * 351239340Sjkim * PARAMETERS: Op - An existing parse node 352239340Sjkim * Length - AML Length 353239340Sjkim * 354239340Sjkim * RETURN: The updated parser op 355239340Sjkim * 356239340Sjkim * DESCRIPTION: Set the AML Length in a node. Used by the parser to indicate 357239340Sjkim * the presence of a node that must be reduced to a fixed length 358239340Sjkim * constant. 359239340Sjkim * 360239340Sjkim ******************************************************************************/ 361239340Sjkim 362239340SjkimACPI_PARSE_OBJECT * 363239340SjkimTrSetNodeAmlLength ( 364239340Sjkim ACPI_PARSE_OBJECT *Op, 365239340Sjkim UINT32 Length) 366239340Sjkim{ 367239340Sjkim 368239340Sjkim DbgPrint (ASL_PARSE_OUTPUT, 369239340Sjkim "\nSetNodeAmlLength: Op %p, %8.8X\n", Op, Length); 370239340Sjkim 371239340Sjkim if (!Op) 372239340Sjkim { 373239340Sjkim return NULL; 374239340Sjkim } 375239340Sjkim 376239340Sjkim Op->Asl.AmlLength = Length; 377239340Sjkim return (Op); 378118611Snjl} 379118611Snjl 380118611Snjl 381118611Snjl/******************************************************************************* 382118611Snjl * 383118611Snjl * FUNCTION: TrSetEndLineNumber 384118611Snjl * 385118611Snjl * PARAMETERS: Op - An existing parse node 386118611Snjl * 387118611Snjl * RETURN: None. 388118611Snjl * 389118611Snjl * DESCRIPTION: Set the ending line numbers (file line and logical line) of a 390118611Snjl * parse node to the current line numbers. 391118611Snjl * 392118611Snjl ******************************************************************************/ 393118611Snjl 394118611Snjlvoid 395118611SnjlTrSetEndLineNumber ( 396118611Snjl ACPI_PARSE_OBJECT *Op) 397118611Snjl{ 398118611Snjl 399118611Snjl /* If the end line # is already set, just return */ 400118611Snjl 401118611Snjl if (Op->Asl.EndLine) 402118611Snjl { 403118611Snjl return; 404118611Snjl } 405118611Snjl 406118611Snjl Op->Asl.EndLine = Gbl_CurrentLineNumber; 407118611Snjl Op->Asl.EndLogicalLine = Gbl_LogicalLineNumber; 408118611Snjl} 409118611Snjl 410118611Snjl 411118611Snjl/******************************************************************************* 412118611Snjl * 413118611Snjl * FUNCTION: TrCreateLeafNode 414118611Snjl * 415118611Snjl * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 416118611Snjl * 417239340Sjkim * RETURN: Pointer to the new node. Aborts on allocation failure 418118611Snjl * 419118611Snjl * DESCRIPTION: Create a simple leaf node (no children or peers, and no value 420118611Snjl * assigned to the node) 421118611Snjl * 422118611Snjl ******************************************************************************/ 423118611Snjl 424118611SnjlACPI_PARSE_OBJECT * 425118611SnjlTrCreateLeafNode ( 426118611Snjl UINT32 ParseOpcode) 427118611Snjl{ 428118611Snjl ACPI_PARSE_OBJECT *Op; 429118611Snjl 430118611Snjl 431118611Snjl Op = TrAllocateNode (ParseOpcode); 432118611Snjl 433118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 434209746Sjkim "\nCreateLeafNode Ln/Col %u/%u NewNode %p Op %s\n\n", 435167802Sjkim Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode)); 436118611Snjl 437118611Snjl return Op; 438118611Snjl} 439118611Snjl 440118611Snjl 441118611Snjl/******************************************************************************* 442118611Snjl * 443218590Sjkim * FUNCTION: TrCreateConstantLeafNode 444218590Sjkim * 445218590Sjkim * PARAMETERS: ParseOpcode - The constant opcode 446218590Sjkim * 447239340Sjkim * RETURN: Pointer to the new node. Aborts on allocation failure 448218590Sjkim * 449218590Sjkim * DESCRIPTION: Create a leaf node (no children or peers) for one of the 450218590Sjkim * special constants - __LINE__, __FILE__, and __DATE__. 451218590Sjkim * 452218590Sjkim * Note: An implemenation of __FUNC__ cannot happen here because we don't 453218590Sjkim * have a full parse tree at this time and cannot find the parent control 454218590Sjkim * method. If it is ever needed, __FUNC__ must be implemented later, after 455218590Sjkim * the parse tree has been fully constructed. 456218590Sjkim * 457218590Sjkim ******************************************************************************/ 458218590Sjkim 459218590SjkimACPI_PARSE_OBJECT * 460218590SjkimTrCreateConstantLeafNode ( 461218590Sjkim UINT32 ParseOpcode) 462218590Sjkim{ 463218590Sjkim ACPI_PARSE_OBJECT *Op = NULL; 464218590Sjkim time_t CurrentTime; 465218590Sjkim char *StaticTimeString; 466218590Sjkim char *TimeString; 467228110Sjkim char *Path; 468228110Sjkim char *Filename; 469218590Sjkim 470218590Sjkim 471218590Sjkim switch (ParseOpcode) 472218590Sjkim { 473218590Sjkim case PARSEOP___LINE__: 474218590Sjkim Op = TrAllocateNode (PARSEOP_INTEGER); 475218590Sjkim Op->Asl.Value.Integer = Op->Asl.LineNumber; 476218590Sjkim break; 477218590Sjkim 478228110Sjkim case PARSEOP___PATH__: 479218590Sjkim Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 480218590Sjkim 481218590Sjkim /* Op.Asl.Filename contains the full pathname to the file */ 482218590Sjkim 483218590Sjkim Op->Asl.Value.String = Op->Asl.Filename; 484218590Sjkim break; 485218590Sjkim 486228110Sjkim case PARSEOP___FILE__: 487218590Sjkim Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 488218590Sjkim 489228110Sjkim /* Get the simple filename from the full path */ 490228110Sjkim 491228110Sjkim FlSplitInputPathname (Op->Asl.Filename, &Path, &Filename); 492228110Sjkim ACPI_FREE (Path); 493228110Sjkim Op->Asl.Value.String = Filename; 494228110Sjkim break; 495228110Sjkim 496228110Sjkim case PARSEOP___DATE__: 497228110Sjkim Op = TrAllocateNode (PARSEOP_STRING_LITERAL); 498228110Sjkim 499218590Sjkim /* Get a copy of the current time */ 500218590Sjkim 501218590Sjkim CurrentTime = time (NULL); 502218590Sjkim StaticTimeString = ctime (&CurrentTime); 503218590Sjkim TimeString = UtLocalCalloc (strlen (StaticTimeString) + 1); 504218590Sjkim strcpy (TimeString, StaticTimeString); 505218590Sjkim 506218590Sjkim TimeString[strlen(TimeString) -1] = 0; /* Remove trailing newline */ 507218590Sjkim Op->Asl.Value.String = TimeString; 508218590Sjkim break; 509218590Sjkim 510218590Sjkim default: /* This would be an internal error */ 511218590Sjkim return (NULL); 512218590Sjkim } 513218590Sjkim 514218590Sjkim DbgPrint (ASL_PARSE_OUTPUT, 515218590Sjkim "\nCreateConstantLeafNode Ln/Col %u/%u NewNode %p Op %s Value %8.8X%8.8X ", 516218590Sjkim Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName (ParseOpcode), 517218590Sjkim ACPI_FORMAT_UINT64 (Op->Asl.Value.Integer)); 518218590Sjkim return (Op); 519218590Sjkim} 520218590Sjkim 521218590Sjkim 522218590Sjkim/******************************************************************************* 523218590Sjkim * 524118611Snjl * FUNCTION: TrCreateValuedLeafNode 525118611Snjl * 526118611Snjl * PARAMETERS: ParseOpcode - New opcode to be assigned to the node 527118611Snjl * Value - Value to be assigned to the node 528118611Snjl * 529239340Sjkim * RETURN: Pointer to the new node. Aborts on allocation failure 530118611Snjl * 531118611Snjl * DESCRIPTION: Create a leaf node (no children or peers) with a value 532118611Snjl * assigned to it 533118611Snjl * 534118611Snjl ******************************************************************************/ 535118611Snjl 536118611SnjlACPI_PARSE_OBJECT * 537118611SnjlTrCreateValuedLeafNode ( 538118611Snjl UINT32 ParseOpcode, 539202771Sjkim UINT64 Value) 540118611Snjl{ 541118611Snjl ACPI_PARSE_OBJECT *Op; 542118611Snjl 543118611Snjl 544118611Snjl Op = TrAllocateNode (ParseOpcode); 545118611Snjl 546118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 547209746Sjkim "\nCreateValuedLeafNode Ln/Col %u/%u NewNode %p Op %s Value %8.8X%8.8X ", 548167802Sjkim Op->Asl.LineNumber, Op->Asl.Column, Op, UtGetOpName(ParseOpcode), 549123315Snjl ACPI_FORMAT_UINT64 (Value)); 550118611Snjl Op->Asl.Value.Integer = Value; 551118611Snjl 552118611Snjl switch (ParseOpcode) 553118611Snjl { 554118611Snjl case PARSEOP_STRING_LITERAL: 555118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "STRING->%s", Value); 556118611Snjl break; 557118611Snjl 558118611Snjl case PARSEOP_NAMESEG: 559118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "NAMESEG->%s", Value); 560118611Snjl break; 561118611Snjl 562118611Snjl case PARSEOP_NAMESTRING: 563118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "NAMESTRING->%s", Value); 564118611Snjl break; 565118611Snjl 566118611Snjl case PARSEOP_EISAID: 567118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "EISAID->%s", Value); 568118611Snjl break; 569118611Snjl 570118611Snjl case PARSEOP_METHOD: 571118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "METHOD"); 572118611Snjl break; 573118611Snjl 574118611Snjl case PARSEOP_INTEGER: 575118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "INTEGER"); 576118611Snjl break; 577118611Snjl 578118611Snjl default: 579118611Snjl break; 580118611Snjl } 581118611Snjl 582118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 583118611Snjl return Op; 584118611Snjl} 585118611Snjl 586118611Snjl 587118611Snjl/******************************************************************************* 588118611Snjl * 589118611Snjl * FUNCTION: TrCreateNode 590118611Snjl * 591118611Snjl * PARAMETERS: ParseOpcode - Opcode to be assigned to the node 592118611Snjl * NumChildren - Number of children to follow 593118611Snjl * ... - A list of child nodes to link to the new 594239340Sjkim * node. NumChildren long. 595118611Snjl * 596239340Sjkim * RETURN: Pointer to the new node. Aborts on allocation failure 597118611Snjl * 598118611Snjl * DESCRIPTION: Create a new parse node and link together a list of child 599118611Snjl * nodes underneath the new node. 600118611Snjl * 601118611Snjl ******************************************************************************/ 602118611Snjl 603118611SnjlACPI_PARSE_OBJECT * 604118611SnjlTrCreateNode ( 605118611Snjl UINT32 ParseOpcode, 606118611Snjl UINT32 NumChildren, 607118611Snjl ...) 608118611Snjl{ 609118611Snjl ACPI_PARSE_OBJECT *Op; 610118611Snjl ACPI_PARSE_OBJECT *Child; 611118611Snjl ACPI_PARSE_OBJECT *PrevChild; 612118611Snjl va_list ap; 613118611Snjl UINT32 i; 614118611Snjl BOOLEAN FirstChild; 615118611Snjl 616118611Snjl 617118611Snjl va_start (ap, NumChildren); 618118611Snjl 619118611Snjl /* Allocate one new node */ 620118611Snjl 621118611Snjl Op = TrAllocateNode (ParseOpcode); 622118611Snjl 623118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 624209746Sjkim "\nCreateNode Ln/Col %u/%u NewParent %p Child %u Op %s ", 625167802Sjkim Op->Asl.LineNumber, Op->Asl.Column, Op, NumChildren, UtGetOpName(ParseOpcode)); 626118611Snjl 627118611Snjl /* Some extra debug output based on the parse opcode */ 628118611Snjl 629118611Snjl switch (ParseOpcode) 630118611Snjl { 631118611Snjl case PARSEOP_DEFINITIONBLOCK: 632118611Snjl RootNode = Op; 633118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 634118611Snjl break; 635118611Snjl 636118611Snjl case PARSEOP_OPERATIONREGION: 637118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 638118611Snjl break; 639118611Snjl 640118611Snjl case PARSEOP_OR: 641118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 642118611Snjl break; 643118611Snjl 644118611Snjl default: 645118611Snjl /* Nothing to do for other opcodes */ 646118611Snjl break; 647118611Snjl } 648118611Snjl 649118611Snjl /* Link the new node to its children */ 650118611Snjl 651118611Snjl PrevChild = NULL; 652118611Snjl FirstChild = TRUE; 653118611Snjl for (i = 0; i < NumChildren; i++) 654118611Snjl { 655118611Snjl /* Get the next child */ 656118611Snjl 657118611Snjl Child = va_arg (ap, ACPI_PARSE_OBJECT *); 658118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 659118611Snjl 660118611Snjl /* 661118611Snjl * If child is NULL, this means that an optional argument 662239340Sjkim * was omitted. We must create a placeholder with a special 663118611Snjl * opcode (DEFAULT_ARG) so that the code generator will know 664118611Snjl * that it must emit the correct default for this argument 665118611Snjl */ 666118611Snjl if (!Child) 667118611Snjl { 668118611Snjl Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 669118611Snjl } 670118611Snjl 671118611Snjl /* Link first child to parent */ 672118611Snjl 673118611Snjl if (FirstChild) 674118611Snjl { 675118611Snjl FirstChild = FALSE; 676118611Snjl Op->Asl.Child = Child; 677118611Snjl } 678118611Snjl 679118611Snjl /* Point all children to parent */ 680118611Snjl 681118611Snjl Child->Asl.Parent = Op; 682118611Snjl 683118611Snjl /* Link children in a peer list */ 684118611Snjl 685118611Snjl if (PrevChild) 686118611Snjl { 687118611Snjl PrevChild->Asl.Next = Child; 688118611Snjl }; 689118611Snjl 690118611Snjl /* 691118611Snjl * This child might be a list, point all nodes in the list 692118611Snjl * to the same parent 693118611Snjl */ 694118611Snjl while (Child->Asl.Next) 695118611Snjl { 696118611Snjl Child = Child->Asl.Next; 697118611Snjl Child->Asl.Parent = Op; 698118611Snjl } 699118611Snjl 700118611Snjl PrevChild = Child; 701118611Snjl } 702118611Snjl va_end(ap); 703118611Snjl 704118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 705118611Snjl return Op; 706118611Snjl} 707118611Snjl 708118611Snjl 709118611Snjl/******************************************************************************* 710118611Snjl * 711118611Snjl * FUNCTION: TrLinkChildren 712118611Snjl * 713118611Snjl * PARAMETERS: Op - An existing parse node 714118611Snjl * NumChildren - Number of children to follow 715118611Snjl * ... - A list of child nodes to link to the new 716239340Sjkim * node. NumChildren long. 717118611Snjl * 718118611Snjl * RETURN: The updated (linked) node 719118611Snjl * 720118611Snjl * DESCRIPTION: Link a group of nodes to an existing parse node 721118611Snjl * 722118611Snjl ******************************************************************************/ 723118611Snjl 724118611SnjlACPI_PARSE_OBJECT * 725118611SnjlTrLinkChildren ( 726118611Snjl ACPI_PARSE_OBJECT *Op, 727118611Snjl UINT32 NumChildren, 728118611Snjl ...) 729118611Snjl{ 730118611Snjl ACPI_PARSE_OBJECT *Child; 731118611Snjl ACPI_PARSE_OBJECT *PrevChild; 732118611Snjl va_list ap; 733118611Snjl UINT32 i; 734118611Snjl BOOLEAN FirstChild; 735118611Snjl 736118611Snjl 737118611Snjl va_start (ap, NumChildren); 738118611Snjl 739118611Snjl 740118611Snjl TrSetEndLineNumber (Op); 741118611Snjl 742118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 743209746Sjkim "\nLinkChildren Line [%u to %u] NewParent %p Child %u Op %s ", 744118611Snjl Op->Asl.LineNumber, Op->Asl.EndLine, 745118611Snjl Op, NumChildren, UtGetOpName(Op->Asl.ParseOpcode)); 746118611Snjl 747118611Snjl switch (Op->Asl.ParseOpcode) 748118611Snjl { 749118611Snjl case PARSEOP_DEFINITIONBLOCK: 750118611Snjl RootNode = Op; 751118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "DEFINITION_BLOCK (Tree Completed)->"); 752118611Snjl break; 753118611Snjl 754118611Snjl case PARSEOP_OPERATIONREGION: 755118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "OPREGION->"); 756118611Snjl break; 757118611Snjl 758118611Snjl case PARSEOP_OR: 759118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "OR->"); 760118611Snjl break; 761118611Snjl 762118611Snjl default: 763118611Snjl /* Nothing to do for other opcodes */ 764118611Snjl break; 765118611Snjl } 766118611Snjl 767118611Snjl /* Link the new node to it's children */ 768118611Snjl 769118611Snjl PrevChild = NULL; 770118611Snjl FirstChild = TRUE; 771118611Snjl for (i = 0; i < NumChildren; i++) 772118611Snjl { 773118611Snjl Child = va_arg (ap, ACPI_PARSE_OBJECT *); 774118611Snjl 775118611Snjl if ((Child == PrevChild) && (Child != NULL)) 776118611Snjl { 777151937Sjkim AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Child, 778151937Sjkim "Child node list invalid"); 779118611Snjl return Op; 780118611Snjl } 781118611Snjl 782118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "%p, ", Child); 783118611Snjl 784118611Snjl /* 785118611Snjl * If child is NULL, this means that an optional argument 786239340Sjkim * was omitted. We must create a placeholder with a special 787118611Snjl * opcode (DEFAULT_ARG) so that the code generator will know 788118611Snjl * that it must emit the correct default for this argument 789118611Snjl */ 790118611Snjl if (!Child) 791118611Snjl { 792118611Snjl Child = TrAllocateNode (PARSEOP_DEFAULT_ARG); 793118611Snjl } 794118611Snjl 795118611Snjl /* Link first child to parent */ 796118611Snjl 797118611Snjl if (FirstChild) 798118611Snjl { 799118611Snjl FirstChild = FALSE; 800118611Snjl Op->Asl.Child = Child; 801118611Snjl } 802118611Snjl 803118611Snjl /* Point all children to parent */ 804118611Snjl 805118611Snjl Child->Asl.Parent = Op; 806118611Snjl 807118611Snjl /* Link children in a peer list */ 808118611Snjl 809118611Snjl if (PrevChild) 810118611Snjl { 811118611Snjl PrevChild->Asl.Next = Child; 812118611Snjl }; 813118611Snjl 814118611Snjl /* 815118611Snjl * This child might be a list, point all nodes in the list 816118611Snjl * to the same parent 817118611Snjl */ 818118611Snjl while (Child->Asl.Next) 819118611Snjl { 820118611Snjl Child = Child->Asl.Next; 821118611Snjl Child->Asl.Parent = Op; 822118611Snjl } 823118611Snjl PrevChild = Child; 824118611Snjl } 825118611Snjl va_end(ap); 826118611Snjl 827118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "\n\n"); 828118611Snjl return Op; 829118611Snjl} 830118611Snjl 831118611Snjl 832118611Snjl/******************************************************************************* 833118611Snjl * 834118611Snjl * FUNCTION: TrLinkPeerNode 835118611Snjl * 836118611Snjl * PARAMETERS: Op1 - First peer 837118611Snjl * Op2 - Second peer 838118611Snjl * 839118611Snjl * RETURN: Op1 or the non-null node. 840118611Snjl * 841239340Sjkim * DESCRIPTION: Link two nodes as peers. Handles cases where one peer is null. 842118611Snjl * 843118611Snjl ******************************************************************************/ 844118611Snjl 845118611SnjlACPI_PARSE_OBJECT * 846118611SnjlTrLinkPeerNode ( 847118611Snjl ACPI_PARSE_OBJECT *Op1, 848118611Snjl ACPI_PARSE_OBJECT *Op2) 849118611Snjl{ 850118611Snjl ACPI_PARSE_OBJECT *Next; 851118611Snjl 852118611Snjl 853118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 854118611Snjl "\nLinkPeerNode: 1=%p (%s), 2=%p (%s)\n\n", 855118611Snjl Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode) : NULL, 856118611Snjl Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode) : NULL); 857118611Snjl 858118611Snjl 859118611Snjl if ((!Op1) && (!Op2)) 860118611Snjl { 861118611Snjl DbgPrint (ASL_PARSE_OUTPUT, "\nTwo Null nodes!\n"); 862118611Snjl return Op1; 863118611Snjl } 864118611Snjl 865118611Snjl /* If one of the nodes is null, just return the non-null node */ 866118611Snjl 867118611Snjl if (!Op2) 868118611Snjl { 869118611Snjl return Op1; 870118611Snjl } 871118611Snjl 872118611Snjl if (!Op1) 873118611Snjl { 874118611Snjl return Op2; 875118611Snjl } 876118611Snjl 877118611Snjl if (Op1 == Op2) 878118611Snjl { 879118611Snjl DbgPrint (ASL_DEBUG_OUTPUT, 880151937Sjkim "\n\n************* Internal error, linking node to itself %p\n\n\n", 881151937Sjkim Op1); 882151937Sjkim AslError (ASL_WARNING, ASL_MSG_COMPILER_INTERNAL, Op1, 883151937Sjkim "Linking node to itself"); 884118611Snjl return Op1; 885118611Snjl } 886118611Snjl 887118611Snjl Op1->Asl.Parent = Op2->Asl.Parent; 888118611Snjl 889118611Snjl /* 890118611Snjl * Op 1 may already have a peer list (such as an IF/ELSE pair), 891118611Snjl * so we must walk to the end of the list and attach the new 892118611Snjl * peer at the end 893118611Snjl */ 894118611Snjl Next = Op1; 895118611Snjl while (Next->Asl.Next) 896118611Snjl { 897118611Snjl Next = Next->Asl.Next; 898118611Snjl } 899118611Snjl 900118611Snjl Next->Asl.Next = Op2; 901118611Snjl return Op1; 902118611Snjl} 903118611Snjl 904118611Snjl 905118611Snjl/******************************************************************************* 906118611Snjl * 907118611Snjl * FUNCTION: TrLinkPeerNodes 908118611Snjl * 909118611Snjl * PARAMETERS: NumPeers - The number of nodes in the list to follow 910118611Snjl * ... - A list of nodes to link together as peers 911118611Snjl * 912118611Snjl * RETURN: The first node in the list (head of the peer list) 913118611Snjl * 914118611Snjl * DESCRIPTION: Link together an arbitrary number of peer nodes. 915118611Snjl * 916118611Snjl ******************************************************************************/ 917118611Snjl 918118611SnjlACPI_PARSE_OBJECT * 919118611SnjlTrLinkPeerNodes ( 920118611Snjl UINT32 NumPeers, 921118611Snjl ...) 922118611Snjl{ 923118611Snjl ACPI_PARSE_OBJECT *This; 924118611Snjl ACPI_PARSE_OBJECT *Next; 925118611Snjl va_list ap; 926118611Snjl UINT32 i; 927118611Snjl ACPI_PARSE_OBJECT *Start; 928118611Snjl 929118611Snjl 930118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 931209746Sjkim "\nLinkPeerNodes: (%u) ", NumPeers); 932118611Snjl 933118611Snjl va_start (ap, NumPeers); 934118611Snjl This = va_arg (ap, ACPI_PARSE_OBJECT *); 935118611Snjl Start = This; 936118611Snjl 937118611Snjl /* 938118611Snjl * Link all peers 939118611Snjl */ 940118611Snjl for (i = 0; i < (NumPeers -1); i++) 941118611Snjl { 942209746Sjkim DbgPrint (ASL_PARSE_OUTPUT, "%u=%p ", (i+1), This); 943118611Snjl 944118611Snjl while (This->Asl.Next) 945118611Snjl { 946118611Snjl This = This->Asl.Next; 947118611Snjl } 948118611Snjl 949118611Snjl /* Get another peer node */ 950118611Snjl 951118611Snjl Next = va_arg (ap, ACPI_PARSE_OBJECT *); 952118611Snjl if (!Next) 953118611Snjl { 954118611Snjl Next = TrAllocateNode (PARSEOP_DEFAULT_ARG); 955118611Snjl } 956118611Snjl 957118611Snjl /* link new node to the current node */ 958118611Snjl 959118611Snjl This->Asl.Next = Next; 960118611Snjl This = Next; 961118611Snjl } 962193529Sjkim va_end (ap); 963118611Snjl 964118611Snjl DbgPrint (ASL_PARSE_OUTPUT,"\n\n"); 965118611Snjl return (Start); 966118611Snjl} 967118611Snjl 968118611Snjl 969118611Snjl/******************************************************************************* 970118611Snjl * 971118611Snjl * FUNCTION: TrLinkChildNode 972118611Snjl * 973118611Snjl * PARAMETERS: Op1 - Parent node 974118611Snjl * Op2 - Op to become a child 975118611Snjl * 976118611Snjl * RETURN: The parent node 977118611Snjl * 978118611Snjl * DESCRIPTION: Link two nodes together as a parent and child 979118611Snjl * 980118611Snjl ******************************************************************************/ 981118611Snjl 982118611SnjlACPI_PARSE_OBJECT * 983118611SnjlTrLinkChildNode ( 984118611Snjl ACPI_PARSE_OBJECT *Op1, 985118611Snjl ACPI_PARSE_OBJECT *Op2) 986118611Snjl{ 987118611Snjl ACPI_PARSE_OBJECT *Next; 988118611Snjl 989118611Snjl 990118611Snjl DbgPrint (ASL_PARSE_OUTPUT, 991118611Snjl "\nLinkChildNode: Parent=%p (%s), Child=%p (%s)\n\n", 992118611Snjl Op1, Op1 ? UtGetOpName(Op1->Asl.ParseOpcode): NULL, 993118611Snjl Op2, Op2 ? UtGetOpName(Op2->Asl.ParseOpcode): NULL); 994118611Snjl 995118611Snjl if (!Op1 || !Op2) 996118611Snjl { 997118611Snjl return Op1; 998118611Snjl } 999118611Snjl 1000118611Snjl Op1->Asl.Child = Op2; 1001118611Snjl 1002118611Snjl /* Set the child and all peers of the child to point to the parent */ 1003118611Snjl 1004118611Snjl Next = Op2; 1005118611Snjl while (Next) 1006118611Snjl { 1007118611Snjl Next->Asl.Parent = Op1; 1008118611Snjl Next = Next->Asl.Next; 1009118611Snjl } 1010118611Snjl 1011118611Snjl return Op1; 1012118611Snjl} 1013118611Snjl 1014118611Snjl 1015118611Snjl/******************************************************************************* 1016118611Snjl * 1017118611Snjl * FUNCTION: TrWalkParseTree 1018118611Snjl * 1019118611Snjl * PARAMETERS: Visitation - Type of walk 1020118611Snjl * DescendingCallback - Called during tree descent 1021118611Snjl * AscendingCallback - Called during tree ascent 1022118611Snjl * Context - To be passed to the callbacks 1023118611Snjl * 1024118611Snjl * RETURN: Status from callback(s) 1025118611Snjl * 1026118611Snjl * DESCRIPTION: Walk the entire parse tree. 1027118611Snjl * 1028118611Snjl ******************************************************************************/ 1029118611Snjl 1030118611SnjlACPI_STATUS 1031118611SnjlTrWalkParseTree ( 1032118611Snjl ACPI_PARSE_OBJECT *Op, 1033118611Snjl UINT32 Visitation, 1034118611Snjl ASL_WALK_CALLBACK DescendingCallback, 1035118611Snjl ASL_WALK_CALLBACK AscendingCallback, 1036118611Snjl void *Context) 1037118611Snjl{ 1038118611Snjl UINT32 Level; 1039118611Snjl BOOLEAN NodePreviouslyVisited; 1040118611Snjl ACPI_PARSE_OBJECT *StartOp = Op; 1041118611Snjl ACPI_STATUS Status; 1042118611Snjl 1043118611Snjl 1044118611Snjl if (!RootNode) 1045118611Snjl { 1046118611Snjl return (AE_OK); 1047118611Snjl } 1048118611Snjl 1049118611Snjl Level = 0; 1050118611Snjl NodePreviouslyVisited = FALSE; 1051118611Snjl 1052118611Snjl switch (Visitation) 1053118611Snjl { 1054118611Snjl case ASL_WALK_VISIT_DOWNWARD: 1055118611Snjl 1056118611Snjl while (Op) 1057118611Snjl { 1058118611Snjl if (!NodePreviouslyVisited) 1059118611Snjl { 1060151937Sjkim /* Let the callback process the node. */ 1061151937Sjkim 1062118611Snjl Status = DescendingCallback (Op, Level, Context); 1063118611Snjl if (ACPI_SUCCESS (Status)) 1064118611Snjl { 1065118611Snjl /* Visit children first, once */ 1066118611Snjl 1067118611Snjl if (Op->Asl.Child) 1068118611Snjl { 1069118611Snjl Level++; 1070118611Snjl Op = Op->Asl.Child; 1071118611Snjl continue; 1072118611Snjl } 1073118611Snjl } 1074118611Snjl else if (Status != AE_CTRL_DEPTH) 1075118611Snjl { 1076118611Snjl /* Exit immediately on any error */ 1077118611Snjl 1078118611Snjl return (Status); 1079118611Snjl } 1080118611Snjl } 1081118611Snjl 1082118611Snjl /* Terminate walk at start op */ 1083118611Snjl 1084118611Snjl if (Op == StartOp) 1085118611Snjl { 1086118611Snjl break; 1087118611Snjl } 1088118611Snjl 1089118611Snjl /* No more children, visit peers */ 1090118611Snjl 1091118611Snjl if (Op->Asl.Next) 1092118611Snjl { 1093118611Snjl Op = Op->Asl.Next; 1094118611Snjl NodePreviouslyVisited = FALSE; 1095118611Snjl } 1096118611Snjl else 1097118611Snjl { 1098118611Snjl /* No children or peers, re-visit parent */ 1099118611Snjl 1100118611Snjl if (Level != 0 ) 1101118611Snjl { 1102118611Snjl Level--; 1103118611Snjl } 1104118611Snjl Op = Op->Asl.Parent; 1105118611Snjl NodePreviouslyVisited = TRUE; 1106118611Snjl } 1107118611Snjl } 1108118611Snjl break; 1109118611Snjl 1110118611Snjl 1111118611Snjl case ASL_WALK_VISIT_UPWARD: 1112118611Snjl 1113118611Snjl while (Op) 1114118611Snjl { 1115118611Snjl /* Visit leaf node (no children) or parent node on return trip */ 1116118611Snjl 1117118611Snjl if ((!Op->Asl.Child) || 1118118611Snjl (NodePreviouslyVisited)) 1119118611Snjl { 1120151937Sjkim /* Let the callback process the node. */ 1121151937Sjkim 1122118611Snjl Status = AscendingCallback (Op, Level, Context); 1123118611Snjl if (ACPI_FAILURE (Status)) 1124118611Snjl { 1125118611Snjl return (Status); 1126118611Snjl } 1127118611Snjl } 1128118611Snjl else 1129118611Snjl { 1130118611Snjl /* Visit children first, once */ 1131118611Snjl 1132118611Snjl Level++; 1133118611Snjl Op = Op->Asl.Child; 1134118611Snjl continue; 1135118611Snjl } 1136118611Snjl 1137118611Snjl /* Terminate walk at start op */ 1138118611Snjl 1139118611Snjl if (Op == StartOp) 1140118611Snjl { 1141118611Snjl break; 1142118611Snjl } 1143118611Snjl 1144118611Snjl /* No more children, visit peers */ 1145118611Snjl 1146118611Snjl if (Op->Asl.Next) 1147118611Snjl { 1148118611Snjl Op = Op->Asl.Next; 1149118611Snjl NodePreviouslyVisited = FALSE; 1150118611Snjl } 1151118611Snjl else 1152118611Snjl { 1153118611Snjl /* No children or peers, re-visit parent */ 1154118611Snjl 1155118611Snjl if (Level != 0 ) 1156118611Snjl { 1157118611Snjl Level--; 1158118611Snjl } 1159118611Snjl Op = Op->Asl.Parent; 1160118611Snjl NodePreviouslyVisited = TRUE; 1161118611Snjl } 1162118611Snjl } 1163118611Snjl break; 1164118611Snjl 1165118611Snjl 1166118611Snjl case ASL_WALK_VISIT_TWICE: 1167118611Snjl 1168118611Snjl while (Op) 1169118611Snjl { 1170118611Snjl if (NodePreviouslyVisited) 1171118611Snjl { 1172118611Snjl Status = AscendingCallback (Op, Level, Context); 1173118611Snjl if (ACPI_FAILURE (Status)) 1174118611Snjl { 1175118611Snjl return (Status); 1176118611Snjl } 1177118611Snjl } 1178118611Snjl else 1179118611Snjl { 1180151937Sjkim /* Let the callback process the node. */ 1181151937Sjkim 1182118611Snjl Status = DescendingCallback (Op, Level, Context); 1183118611Snjl if (ACPI_SUCCESS (Status)) 1184118611Snjl { 1185118611Snjl /* Visit children first, once */ 1186118611Snjl 1187118611Snjl if (Op->Asl.Child) 1188118611Snjl { 1189118611Snjl Level++; 1190118611Snjl Op = Op->Asl.Child; 1191118611Snjl continue; 1192118611Snjl } 1193118611Snjl } 1194118611Snjl else if (Status != AE_CTRL_DEPTH) 1195118611Snjl { 1196118611Snjl /* Exit immediately on any error */ 1197118611Snjl 1198118611Snjl return (Status); 1199118611Snjl } 1200118611Snjl } 1201118611Snjl 1202118611Snjl /* Terminate walk at start op */ 1203118611Snjl 1204118611Snjl if (Op == StartOp) 1205118611Snjl { 1206118611Snjl break; 1207118611Snjl } 1208118611Snjl 1209118611Snjl /* No more children, visit peers */ 1210118611Snjl 1211118611Snjl if (Op->Asl.Next) 1212118611Snjl { 1213118611Snjl Op = Op->Asl.Next; 1214118611Snjl NodePreviouslyVisited = FALSE; 1215118611Snjl } 1216118611Snjl else 1217118611Snjl { 1218118611Snjl /* No children or peers, re-visit parent */ 1219118611Snjl 1220118611Snjl if (Level != 0 ) 1221118611Snjl { 1222118611Snjl Level--; 1223118611Snjl } 1224118611Snjl Op = Op->Asl.Parent; 1225118611Snjl NodePreviouslyVisited = TRUE; 1226118611Snjl } 1227118611Snjl } 1228118611Snjl break; 1229118611Snjl 1230118611Snjl default: 1231118611Snjl /* No other types supported */ 1232118611Snjl break; 1233118611Snjl } 1234118611Snjl 1235118611Snjl /* If we get here, the walk completed with no errors */ 1236118611Snjl 1237118611Snjl return (AE_OK); 1238118611Snjl} 1239118611Snjl 1240118611Snjl 1241