1118611Snjl/****************************************************************************** 2118611Snjl * 3118611Snjl * Module Name: asltransform - Parse tree transforms 4118611Snjl * 5118611Snjl *****************************************************************************/ 6118611Snjl 7217365Sjkim/* 8245582Sjkim * Copyright (C) 2000 - 2013, Intel Corp. 9118611Snjl * All rights reserved. 10118611Snjl * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 25118611Snjl * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 29118611Snjl * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 43118611Snjl 44118611Snjl 45151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h> 46118611Snjl#include "aslcompiler.y.h" 47118611Snjl 48118611Snjl#define _COMPONENT ACPI_COMPILER 49118611Snjl ACPI_MODULE_NAME ("asltransform") 50118611Snjl 51151937Sjkim/* Local prototypes */ 52118611Snjl 53151937Sjkimstatic void 54151937SjkimTrTransformSubtree ( 55151937Sjkim ACPI_PARSE_OBJECT *Op); 56151937Sjkim 57151937Sjkimstatic char * 58151937SjkimTrAmlGetNextTempName ( 59151937Sjkim ACPI_PARSE_OBJECT *Op, 60151937Sjkim UINT8 *TempCount); 61151937Sjkim 62151937Sjkimstatic void 63151937SjkimTrAmlInitLineNumbers ( 64151937Sjkim ACPI_PARSE_OBJECT *Op, 65151937Sjkim ACPI_PARSE_OBJECT *Neighbor); 66151937Sjkim 67151937Sjkimstatic void 68151937SjkimTrAmlInitNode ( 69151937Sjkim ACPI_PARSE_OBJECT *Op, 70151937Sjkim UINT16 ParseOpcode); 71151937Sjkim 72151937Sjkimstatic void 73151937SjkimTrAmlSetSubtreeParent ( 74151937Sjkim ACPI_PARSE_OBJECT *Op, 75151937Sjkim ACPI_PARSE_OBJECT *Parent); 76151937Sjkim 77151937Sjkimstatic void 78151937SjkimTrAmlInsertPeer ( 79151937Sjkim ACPI_PARSE_OBJECT *Op, 80151937Sjkim ACPI_PARSE_OBJECT *NewPeer); 81151937Sjkim 82151937Sjkimstatic void 83151937SjkimTrDoDefinitionBlock ( 84151937Sjkim ACPI_PARSE_OBJECT *Op); 85151937Sjkim 86151937Sjkimstatic void 87151937SjkimTrDoSwitch ( 88151937Sjkim ACPI_PARSE_OBJECT *StartNode); 89151937Sjkim 90151937Sjkim 91118611Snjl/******************************************************************************* 92118611Snjl * 93118611Snjl * FUNCTION: TrAmlGetNextTempName 94118611Snjl * 95151937Sjkim * PARAMETERS: Op - Current parse op 96151937Sjkim * TempCount - Current temporary counter. Was originally 97151937Sjkim * per-module; Currently per method, could be 98151937Sjkim * expanded to per-scope. 99118611Snjl * 100151937Sjkim * RETURN: A pointer to name (allocated here). 101118611Snjl * 102241973Sjkim * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are 103151937Sjkim * reserved for use by the ASL compiler. (_T_0 through _T_Z) 104118611Snjl * 105118611Snjl ******************************************************************************/ 106118611Snjl 107151937Sjkimstatic char * 108118611SnjlTrAmlGetNextTempName ( 109151937Sjkim ACPI_PARSE_OBJECT *Op, 110151937Sjkim UINT8 *TempCount) 111118611Snjl{ 112118611Snjl char *TempName; 113118611Snjl 114118611Snjl 115151937Sjkim if (*TempCount >= (10+26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */ 116118611Snjl { 117118611Snjl /* Too many temps */ 118151937Sjkim 119151937Sjkim AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL); 120151937Sjkim return (NULL); 121118611Snjl } 122118611Snjl 123151937Sjkim TempName = UtLocalCalloc (5); 124138287Smarks 125151937Sjkim if (*TempCount < 10) /* 0-9 */ 126138287Smarks { 127151937Sjkim TempName[3] = (char) (*TempCount + '0'); 128138287Smarks } 129151937Sjkim else /* 10-35: A-Z */ 130138287Smarks { 131151937Sjkim TempName[3] = (char) (*TempCount + ('A' - 10)); 132138287Smarks } 133151937Sjkim (*TempCount)++; 134118611Snjl 135151937Sjkim /* First three characters are always "_T_" */ 136118611Snjl 137151937Sjkim TempName[0] = '_'; 138151937Sjkim TempName[1] = 'T'; 139151937Sjkim TempName[2] = '_'; 140118611Snjl 141151937Sjkim return (TempName); 142118611Snjl} 143118611Snjl 144118611Snjl 145118611Snjl/******************************************************************************* 146118611Snjl * 147118611Snjl * FUNCTION: TrAmlInitLineNumbers 148118611Snjl * 149151937Sjkim * PARAMETERS: Op - Op to be initialized 150118611Snjl * Neighbor - Op used for initialization values 151118611Snjl * 152118611Snjl * RETURN: None 153118611Snjl * 154118611Snjl * DESCRIPTION: Initialized the various line numbers for a parse node. 155118611Snjl * 156118611Snjl ******************************************************************************/ 157118611Snjl 158151937Sjkimstatic void 159118611SnjlTrAmlInitLineNumbers ( 160118611Snjl ACPI_PARSE_OBJECT *Op, 161118611Snjl ACPI_PARSE_OBJECT *Neighbor) 162118611Snjl{ 163118611Snjl 164118611Snjl Op->Asl.EndLine = Neighbor->Asl.EndLine; 165118611Snjl Op->Asl.EndLogicalLine = Neighbor->Asl.EndLogicalLine; 166118611Snjl Op->Asl.LineNumber = Neighbor->Asl.LineNumber; 167118611Snjl Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset; 168118611Snjl Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber; 169118611Snjl} 170118611Snjl 171118611Snjl 172118611Snjl/******************************************************************************* 173118611Snjl * 174118611Snjl * FUNCTION: TrAmlInitNode 175118611Snjl * 176151937Sjkim * PARAMETERS: Op - Op to be initialized 177118611Snjl * ParseOpcode - Opcode for this node 178118611Snjl * 179118611Snjl * RETURN: None 180118611Snjl * 181118611Snjl * DESCRIPTION: Initialize a node with the parse opcode and opcode name. 182118611Snjl * 183118611Snjl ******************************************************************************/ 184118611Snjl 185151937Sjkimstatic void 186118611SnjlTrAmlInitNode ( 187118611Snjl ACPI_PARSE_OBJECT *Op, 188118611Snjl UINT16 ParseOpcode) 189118611Snjl{ 190118611Snjl 191118611Snjl Op->Asl.ParseOpcode = ParseOpcode; 192118611Snjl UtSetParseOpName (Op); 193118611Snjl} 194118611Snjl 195118611Snjl 196118611Snjl/******************************************************************************* 197118611Snjl * 198118611Snjl * FUNCTION: TrAmlSetSubtreeParent 199118611Snjl * 200151937Sjkim * PARAMETERS: Op - First node in a list of peer nodes 201118611Snjl * Parent - Parent of the subtree 202118611Snjl * 203118611Snjl * RETURN: None 204118611Snjl * 205118611Snjl * DESCRIPTION: Set the parent for all peer nodes in a subtree 206118611Snjl * 207118611Snjl ******************************************************************************/ 208118611Snjl 209151937Sjkimstatic void 210118611SnjlTrAmlSetSubtreeParent ( 211118611Snjl ACPI_PARSE_OBJECT *Op, 212118611Snjl ACPI_PARSE_OBJECT *Parent) 213118611Snjl{ 214118611Snjl ACPI_PARSE_OBJECT *Next; 215118611Snjl 216118611Snjl 217118611Snjl Next = Op; 218118611Snjl while (Next) 219118611Snjl { 220118611Snjl Next->Asl.Parent = Parent; 221118611Snjl Next = Next->Asl.Next; 222118611Snjl } 223118611Snjl} 224118611Snjl 225118611Snjl 226118611Snjl/******************************************************************************* 227118611Snjl * 228118611Snjl * FUNCTION: TrAmlInsertPeer 229118611Snjl * 230151937Sjkim * PARAMETERS: Op - First node in a list of peer nodes 231118611Snjl * NewPeer - Peer node to insert 232118611Snjl * 233118611Snjl * RETURN: None 234118611Snjl * 235118611Snjl * DESCRIPTION: Insert a new peer node into a list of peers. 236118611Snjl * 237118611Snjl ******************************************************************************/ 238118611Snjl 239151937Sjkimstatic void 240118611SnjlTrAmlInsertPeer ( 241118611Snjl ACPI_PARSE_OBJECT *Op, 242118611Snjl ACPI_PARSE_OBJECT *NewPeer) 243118611Snjl{ 244118611Snjl 245118611Snjl NewPeer->Asl.Next = Op->Asl.Next; 246118611Snjl Op->Asl.Next = NewPeer; 247118611Snjl} 248118611Snjl 249118611Snjl 250118611Snjl/******************************************************************************* 251118611Snjl * 252118611Snjl * FUNCTION: TrAmlTransformWalk 253118611Snjl * 254118611Snjl * PARAMETERS: ASL_WALK_CALLBACK 255118611Snjl * 256118611Snjl * RETURN: None 257118611Snjl * 258118611Snjl * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 259118611Snjl * operands. 260118611Snjl * 261118611Snjl ******************************************************************************/ 262118611Snjl 263118611SnjlACPI_STATUS 264118611SnjlTrAmlTransformWalk ( 265118611Snjl ACPI_PARSE_OBJECT *Op, 266118611Snjl UINT32 Level, 267118611Snjl void *Context) 268118611Snjl{ 269118611Snjl 270118611Snjl TrTransformSubtree (Op); 271118611Snjl return (AE_OK); 272118611Snjl} 273118611Snjl 274118611Snjl 275118611Snjl/******************************************************************************* 276118611Snjl * 277118611Snjl * FUNCTION: TrTransformSubtree 278118611Snjl * 279118611Snjl * PARAMETERS: Op - The parent parse node 280118611Snjl * 281118611Snjl * RETURN: None 282118611Snjl * 283241973Sjkim * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 284118611Snjl * complex AML opcodes require processing of the child nodes 285118611Snjl * (arguments/operands). 286118611Snjl * 287118611Snjl ******************************************************************************/ 288118611Snjl 289151937Sjkimstatic void 290118611SnjlTrTransformSubtree ( 291118611Snjl ACPI_PARSE_OBJECT *Op) 292118611Snjl{ 293118611Snjl 294118611Snjl if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 295118611Snjl { 296118611Snjl return; 297118611Snjl } 298118611Snjl 299118611Snjl switch (Op->Asl.ParseOpcode) 300118611Snjl { 301118611Snjl case PARSEOP_DEFINITIONBLOCK: 302250838Sjkim 303118611Snjl TrDoDefinitionBlock (Op); 304118611Snjl break; 305118611Snjl 306118611Snjl case PARSEOP_SWITCH: 307250838Sjkim 308118611Snjl TrDoSwitch (Op); 309118611Snjl break; 310118611Snjl 311151937Sjkim case PARSEOP_METHOD: 312151937Sjkim /* 313151937Sjkim * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, 314151937Sjkim * however 315151937Sjkim */ 316151937Sjkim Gbl_TempCount = 0; 317151937Sjkim break; 318151937Sjkim 319118611Snjl default: 320250838Sjkim 321118611Snjl /* Nothing to do here for other opcodes */ 322250838Sjkim 323118611Snjl break; 324118611Snjl } 325118611Snjl} 326118611Snjl 327118611Snjl 328118611Snjl/******************************************************************************* 329118611Snjl * 330118611Snjl * FUNCTION: TrDoDefinitionBlock 331118611Snjl * 332118611Snjl * PARAMETERS: Op - Parse node 333118611Snjl * 334118611Snjl * RETURN: None 335118611Snjl * 336118611Snjl * DESCRIPTION: Find the end of the definition block and set a global to this 337241973Sjkim * node. It is used by the compiler to insert compiler-generated 338118611Snjl * names at the root level of the namespace. 339118611Snjl * 340118611Snjl ******************************************************************************/ 341118611Snjl 342151937Sjkimstatic void 343118611SnjlTrDoDefinitionBlock ( 344118611Snjl ACPI_PARSE_OBJECT *Op) 345118611Snjl{ 346118611Snjl ACPI_PARSE_OBJECT *Next; 347118611Snjl UINT32 i; 348118611Snjl 349118611Snjl 350118611Snjl Next = Op->Asl.Child; 351118611Snjl for (i = 0; i < 5; i++) 352118611Snjl { 353118611Snjl Next = Next->Asl.Next; 354151937Sjkim if (i == 0) 355151937Sjkim { 356151937Sjkim /* 357151937Sjkim * This is the table signature. Only the DSDT can be assumed 358151937Sjkim * to be at the root of the namespace; Therefore, namepath 359151937Sjkim * optimization can only be performed on the DSDT. 360151937Sjkim */ 361167802Sjkim if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT)) 362151937Sjkim { 363151937Sjkim Gbl_ReferenceOptimizationFlag = FALSE; 364151937Sjkim } 365151937Sjkim } 366118611Snjl } 367118611Snjl 368118611Snjl Gbl_FirstLevelInsertionNode = Next; 369118611Snjl} 370118611Snjl 371118611Snjl 372118611Snjl/******************************************************************************* 373118611Snjl * 374118611Snjl * FUNCTION: TrDoSwitch 375118611Snjl * 376118611Snjl * PARAMETERS: StartNode - Parse node for SWITCH 377118611Snjl * 378118611Snjl * RETURN: None 379118611Snjl * 380118611Snjl * 381241973Sjkim * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is 382118611Snjl * no actual AML opcode for SWITCH -- it must be simulated. 383118611Snjl * 384118611Snjl ******************************************************************************/ 385118611Snjl 386151937Sjkimstatic void 387118611SnjlTrDoSwitch ( 388118611Snjl ACPI_PARSE_OBJECT *StartNode) 389118611Snjl{ 390118611Snjl ACPI_PARSE_OBJECT *Next; 391118611Snjl ACPI_PARSE_OBJECT *CaseOp = NULL; 392118611Snjl ACPI_PARSE_OBJECT *CaseBlock = NULL; 393118611Snjl ACPI_PARSE_OBJECT *DefaultOp = NULL; 394118611Snjl ACPI_PARSE_OBJECT *CurrentParentNode; 395118611Snjl ACPI_PARSE_OBJECT *Conditional = NULL; 396118611Snjl ACPI_PARSE_OBJECT *Predicate; 397118611Snjl ACPI_PARSE_OBJECT *Peer; 398118611Snjl ACPI_PARSE_OBJECT *NewOp; 399118611Snjl ACPI_PARSE_OBJECT *NewOp2; 400193529Sjkim ACPI_PARSE_OBJECT *MethodOp; 401199337Sjkim ACPI_PARSE_OBJECT *StoreOp; 402199337Sjkim ACPI_PARSE_OBJECT *BreakOp; 403228110Sjkim ACPI_PARSE_OBJECT *BufferOp; 404118611Snjl char *PredicateValueName; 405151937Sjkim UINT16 Index; 406151937Sjkim UINT32 Btype; 407118611Snjl 408118611Snjl 409151937Sjkim /* Start node is the Switch() node */ 410151937Sjkim 411118611Snjl CurrentParentNode = StartNode; 412118611Snjl 413151937Sjkim /* Create a new temp name of the form _T_x */ 414118611Snjl 415151937Sjkim PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount); 416151937Sjkim if (!PredicateValueName) 417151937Sjkim { 418151937Sjkim return; 419151937Sjkim } 420151937Sjkim 421151937Sjkim /* First child is the Switch() predicate */ 422151937Sjkim 423118611Snjl Next = StartNode->Asl.Child; 424118611Snjl 425151937Sjkim /* 426151937Sjkim * Examine the return type of the Switch Value - 427151937Sjkim * must be Integer/Buffer/String 428151937Sjkim */ 429151937Sjkim Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 430151937Sjkim Btype = AslKeywordMapping[Index].AcpiBtype; 431151937Sjkim if ((Btype != ACPI_BTYPE_INTEGER) && 432151937Sjkim (Btype != ACPI_BTYPE_STRING) && 433151937Sjkim (Btype != ACPI_BTYPE_BUFFER)) 434151937Sjkim { 435151937Sjkim AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); 436151937Sjkim Btype = ACPI_BTYPE_INTEGER; 437151937Sjkim } 438151937Sjkim 439118611Snjl /* CASE statements start at next child */ 440118611Snjl 441151937Sjkim Peer = Next->Asl.Next; 442118611Snjl while (Peer) 443118611Snjl { 444118611Snjl Next = Peer; 445118611Snjl Peer = Next->Asl.Next; 446118611Snjl 447118611Snjl if (Next->Asl.ParseOpcode == PARSEOP_CASE) 448118611Snjl { 449118611Snjl if (CaseOp) 450118611Snjl { 451118611Snjl /* Add an ELSE to complete the previous CASE */ 452118611Snjl 453151937Sjkim if (!Conditional) 454151937Sjkim { 455151937Sjkim return; 456151937Sjkim } 457118611Snjl NewOp = TrCreateLeafNode (PARSEOP_ELSE); 458118611Snjl NewOp->Asl.Parent = Conditional->Asl.Parent; 459118611Snjl TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); 460118611Snjl 461118611Snjl /* Link ELSE node as a peer to the previous IF */ 462118611Snjl 463118611Snjl TrAmlInsertPeer (Conditional, NewOp); 464118611Snjl CurrentParentNode = NewOp; 465118611Snjl } 466118611Snjl 467118611Snjl CaseOp = Next; 468118611Snjl Conditional = CaseOp; 469118611Snjl CaseBlock = CaseOp->Asl.Child->Asl.Next; 470118611Snjl Conditional->Asl.Child->Asl.Next = NULL; 471138287Smarks Predicate = CaseOp->Asl.Child; 472118611Snjl 473151937Sjkim if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || 474151937Sjkim (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 475138287Smarks { 476138287Smarks /* 477138287Smarks * Convert the package declaration to this form: 478138287Smarks * 479151937Sjkim * If (LNotEqual (Match (Package(<size>){<data>}, 480151937Sjkim * MEQ, _T_x, MTR, Zero, Zero), Ones)) 481138287Smarks */ 482138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ); 483138287Smarks Predicate->Asl.Next = NewOp2; 484138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 485118611Snjl 486138287Smarks NewOp = NewOp2; 487138287Smarks NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 488202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 489138287Smarks NewOp->Asl.Next = NewOp2; 490138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 491118611Snjl 492138287Smarks NewOp = NewOp2; 493138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR); 494138287Smarks NewOp->Asl.Next = NewOp2; 495138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 496118611Snjl 497138287Smarks NewOp = NewOp2; 498138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 499138287Smarks NewOp->Asl.Next = NewOp2; 500138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 501118611Snjl 502138287Smarks NewOp = NewOp2; 503138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 504138287Smarks NewOp->Asl.Next = NewOp2; 505138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 506118611Snjl 507138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCH); 508138287Smarks NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ 509138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 510138287Smarks TrAmlSetSubtreeParent (Predicate, NewOp2); 511138287Smarks 512138287Smarks NewOp = NewOp2; 513138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ONES); 514138287Smarks NewOp->Asl.Next = NewOp2; 515138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 516138287Smarks 517138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 518138287Smarks NewOp2->Asl.Child = NewOp; 519138287Smarks NewOp->Asl.Parent = NewOp2; 520138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 521138287Smarks TrAmlSetSubtreeParent (NewOp, NewOp2); 522138287Smarks 523138287Smarks NewOp = NewOp2; 524138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LNOT); 525138287Smarks NewOp2->Asl.Child = NewOp; 526138287Smarks NewOp2->Asl.Parent = Conditional; 527138287Smarks NewOp->Asl.Parent = NewOp2; 528138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 529138287Smarks 530138287Smarks Conditional->Asl.Child = NewOp2; 531138287Smarks NewOp2->Asl.Next = CaseBlock; 532138287Smarks } 533138287Smarks else 534138287Smarks { 535138287Smarks /* 536151937Sjkim * Integer and Buffer case. 537151937Sjkim * 538151937Sjkim * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} 539151937Sjkim * Note: SwitchValue is first to allow the CaseValue to be implicitly 540151937Sjkim * converted to the type of SwitchValue if necessary. 541151937Sjkim * 542138287Smarks * CaseOp->Child is the case value 543138287Smarks * CaseOp->Child->Peer is the beginning of the case block 544138287Smarks */ 545138287Smarks NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 546202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 547151937Sjkim NewOp->Asl.Next = Predicate; 548138287Smarks TrAmlInitLineNumbers (NewOp, Predicate); 549138287Smarks 550138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 551138287Smarks NewOp2->Asl.Parent = Conditional; 552151937Sjkim NewOp2->Asl.Child = NewOp; 553138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 554138287Smarks 555151937Sjkim TrAmlSetSubtreeParent (NewOp, NewOp2); 556138287Smarks 557138287Smarks Predicate = NewOp2; 558138287Smarks Predicate->Asl.Next = CaseBlock; 559138287Smarks 560138287Smarks TrAmlSetSubtreeParent (Predicate, Conditional); 561138287Smarks Conditional->Asl.Child = Predicate; 562138287Smarks } 563138287Smarks 564118611Snjl /* Reinitialize the CASE node to an IF node */ 565118611Snjl 566118611Snjl TrAmlInitNode (Conditional, PARSEOP_IF); 567118611Snjl 568118611Snjl /* 569118611Snjl * The first CASE(IF) is not nested under an ELSE. 570118611Snjl * All other CASEs are children of a parent ELSE. 571118611Snjl */ 572118611Snjl if (CurrentParentNode == StartNode) 573118611Snjl { 574199337Sjkim Conditional->Asl.Next = NULL; 575118611Snjl } 576118611Snjl else 577118611Snjl { 578118611Snjl /* 579241973Sjkim * The IF is a child of previous IF/ELSE. It 580118611Snjl * is therefore without peer. 581118611Snjl */ 582118611Snjl CurrentParentNode->Asl.Child = Conditional; 583118611Snjl Conditional->Asl.Parent = CurrentParentNode; 584118611Snjl Conditional->Asl.Next = NULL; 585118611Snjl } 586118611Snjl } 587118611Snjl else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) 588118611Snjl { 589118611Snjl if (DefaultOp) 590118611Snjl { 591138287Smarks /* 592138287Smarks * More than one Default 593167802Sjkim * (Parser does not catch this, must check here) 594138287Smarks */ 595167802Sjkim AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); 596118611Snjl } 597167802Sjkim else 598167802Sjkim { 599167802Sjkim /* Save the DEFAULT node for later, after CASEs */ 600118611Snjl 601167802Sjkim DefaultOp = Next; 602167802Sjkim } 603118611Snjl } 604118611Snjl else 605118611Snjl { 606138287Smarks /* Unknown peer opcode */ 607118611Snjl 608209746Sjkim AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", 609118611Snjl Next->Asl.ParseOpName, Next->Asl.ParseOpcode); 610118611Snjl } 611118611Snjl } 612118611Snjl 613151937Sjkim /* Add the default case at the end of the if/else construct */ 614151937Sjkim 615118611Snjl if (DefaultOp) 616118611Snjl { 617138287Smarks /* If no CASE statements, this is an error - see below */ 618138287Smarks 619118611Snjl if (CaseOp) 620118611Snjl { 621138287Smarks /* Convert the DEFAULT node to an ELSE */ 622118611Snjl 623151937Sjkim if (!Conditional) 624151937Sjkim { 625151937Sjkim return; 626151937Sjkim } 627199337Sjkim 628118611Snjl TrAmlInitNode (DefaultOp, PARSEOP_ELSE); 629118611Snjl DefaultOp->Asl.Parent = Conditional->Asl.Parent; 630118611Snjl 631138287Smarks /* Link ELSE node as a peer to the previous IF */ 632138287Smarks 633138287Smarks TrAmlInsertPeer (Conditional, DefaultOp); 634118611Snjl } 635118611Snjl } 636118611Snjl 637138287Smarks if (!CaseOp) 638138287Smarks { 639138287Smarks AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); 640138287Smarks } 641138287Smarks 642167802Sjkim 643118611Snjl /* 644167802Sjkim * Create a Name(_T_x, ...) statement. This statement must appear at the 645167802Sjkim * method level, in case a loop surrounds the switch statement and could 646167802Sjkim * cause the name to be created twice (error). 647118611Snjl */ 648167802Sjkim 649167802Sjkim /* Create the Name node */ 650167802Sjkim 651151937Sjkim Predicate = StartNode->Asl.Child; 652167802Sjkim NewOp = TrCreateLeafNode (PARSEOP_NAME); 653228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 654151937Sjkim 655167802Sjkim /* Find the parent method */ 656151937Sjkim 657167802Sjkim Next = StartNode; 658167802Sjkim while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && 659167802Sjkim (Next->Asl.ParseOpcode != PARSEOP_DEFINITIONBLOCK)) 660167802Sjkim { 661167802Sjkim Next = Next->Asl.Parent; 662167802Sjkim } 663193529Sjkim MethodOp = Next; 664167802Sjkim 665138287Smarks NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED; 666167802Sjkim NewOp->Asl.Parent = Next; 667118611Snjl 668167802Sjkim /* Insert name after the method name and arguments */ 669167802Sjkim 670193529Sjkim Next = Next->Asl.Child; /* Name */ 671193529Sjkim Next = Next->Asl.Next; /* NumArgs */ 672193529Sjkim Next = Next->Asl.Next; /* SerializeRule */ 673167802Sjkim 674193529Sjkim /* 675193529Sjkim * If method is not Serialized, we must make is so, because of the way 676193529Sjkim * that Switch() must be implemented -- we cannot allow multiple threads 677193529Sjkim * to execute this method concurrently since we need to create local 678193529Sjkim * temporary name(s). 679193529Sjkim */ 680193529Sjkim if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) 681193529Sjkim { 682193529Sjkim AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, "Due to use of Switch operator"); 683193529Sjkim Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; 684193529Sjkim } 685193529Sjkim 686193529Sjkim Next = Next->Asl.Next; /* SyncLevel */ 687193529Sjkim Next = Next->Asl.Next; /* ReturnType */ 688193529Sjkim Next = Next->Asl.Next; /* ParameterTypes */ 689193529Sjkim 690167802Sjkim TrAmlInsertPeer (Next, NewOp); 691167802Sjkim TrAmlInitLineNumbers (NewOp, Next); 692167802Sjkim 693167802Sjkim /* Create the NameSeg child for the Name node */ 694167802Sjkim 695151937Sjkim NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 696202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 697228110Sjkim TrAmlInitLineNumbers (NewOp2, NewOp); 698151937Sjkim NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION; 699118611Snjl NewOp->Asl.Child = NewOp2; 700118611Snjl 701167802Sjkim /* Create the initial value for the Name. Btype was already validated above */ 702118611Snjl 703151937Sjkim switch (Btype) 704151937Sjkim { 705151937Sjkim case ACPI_BTYPE_INTEGER: 706250838Sjkim 707167802Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO, 708202771Sjkim (UINT64) 0); 709228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 710151937Sjkim break; 711118611Snjl 712151937Sjkim case ACPI_BTYPE_STRING: 713250838Sjkim 714151937Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, 715202771Sjkim (UINT64) ACPI_TO_INTEGER ("")); 716228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 717151937Sjkim break; 718118611Snjl 719151937Sjkim case ACPI_BTYPE_BUFFER: 720250838Sjkim 721151937Sjkim (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER, 722202771Sjkim (UINT64) 0)); 723151937Sjkim Next = NewOp2->Asl.Next; 724228110Sjkim TrAmlInitLineNumbers (Next, NewOp2); 725151937Sjkim (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO, 726202771Sjkim (UINT64) 1)); 727228110Sjkim TrAmlInitLineNumbers (Next->Asl.Child, Next); 728151937Sjkim 729228110Sjkim BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0); 730228110Sjkim TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); 731228110Sjkim (void) TrLinkPeerNode (Next->Asl.Child, BufferOp); 732228110Sjkim 733151937Sjkim TrAmlSetSubtreeParent (Next->Asl.Child, Next); 734151937Sjkim break; 735151937Sjkim 736151937Sjkim default: 737250838Sjkim 738151937Sjkim break; 739151937Sjkim } 740151937Sjkim 741151937Sjkim TrAmlSetSubtreeParent (NewOp2, NewOp); 742151937Sjkim 743118611Snjl /* 744199337Sjkim * Transform the Switch() into a While(One)-Break node. 745199337Sjkim * And create a Store() node which will be used to save the 746241973Sjkim * Switch() value. The store is of the form: Store (Value, _T_x) 747151937Sjkim * where _T_x is the temp variable. 748118611Snjl */ 749199337Sjkim TrAmlInitNode (StartNode, PARSEOP_WHILE); 750199337Sjkim NewOp = TrCreateLeafNode (PARSEOP_ONE); 751228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 752199337Sjkim NewOp->Asl.Next = Predicate->Asl.Next; 753199337Sjkim NewOp->Asl.Parent = StartNode; 754199337Sjkim StartNode->Asl.Child = NewOp; 755118611Snjl 756199337Sjkim /* Create a Store() node */ 757199337Sjkim 758199337Sjkim StoreOp = TrCreateLeafNode (PARSEOP_STORE); 759228110Sjkim TrAmlInitLineNumbers (StoreOp, NewOp); 760199337Sjkim StoreOp->Asl.Parent = StartNode; 761199337Sjkim TrAmlInsertPeer (NewOp, StoreOp); 762199337Sjkim 763151937Sjkim /* Complete the Store subtree */ 764151937Sjkim 765199337Sjkim StoreOp->Asl.Child = Predicate; 766199337Sjkim Predicate->Asl.Parent = StoreOp; 767151937Sjkim 768151937Sjkim NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 769202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 770228110Sjkim TrAmlInitLineNumbers (NewOp, StoreOp); 771199337Sjkim NewOp->Asl.Parent = StoreOp; 772118611Snjl Predicate->Asl.Next = NewOp; 773199337Sjkim 774199337Sjkim /* Create a Break() node and insert it into the end of While() */ 775199337Sjkim 776199337Sjkim Conditional = StartNode->Asl.Child; 777199337Sjkim while (Conditional->Asl.Next) 778199337Sjkim { 779199337Sjkim Conditional = Conditional->Asl.Next; 780199337Sjkim } 781199337Sjkim 782199337Sjkim BreakOp = TrCreateLeafNode (PARSEOP_BREAK); 783228110Sjkim TrAmlInitLineNumbers (BreakOp, NewOp); 784199337Sjkim BreakOp->Asl.Parent = StartNode; 785199337Sjkim TrAmlInsertPeer (Conditional, BreakOp); 786118611Snjl} 787