1118611Snjl/****************************************************************************** 2118611Snjl * 3118611Snjl * Module Name: asltransform - Parse tree transforms 4118611Snjl * 5118611Snjl *****************************************************************************/ 6118611Snjl 7217365Sjkim/* 8281075Sdim * Copyright (C) 2000 - 2015, 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 44151937Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h> 45118611Snjl#include "aslcompiler.y.h" 46118611Snjl 47118611Snjl#define _COMPONENT ACPI_COMPILER 48118611Snjl ACPI_MODULE_NAME ("asltransform") 49118611Snjl 50151937Sjkim/* Local prototypes */ 51118611Snjl 52151937Sjkimstatic void 53151937SjkimTrTransformSubtree ( 54151937Sjkim ACPI_PARSE_OBJECT *Op); 55151937Sjkim 56151937Sjkimstatic char * 57151937SjkimTrAmlGetNextTempName ( 58151937Sjkim ACPI_PARSE_OBJECT *Op, 59151937Sjkim UINT8 *TempCount); 60151937Sjkim 61151937Sjkimstatic void 62151937SjkimTrAmlInitLineNumbers ( 63151937Sjkim ACPI_PARSE_OBJECT *Op, 64151937Sjkim ACPI_PARSE_OBJECT *Neighbor); 65151937Sjkim 66151937Sjkimstatic void 67151937SjkimTrAmlInitNode ( 68151937Sjkim ACPI_PARSE_OBJECT *Op, 69151937Sjkim UINT16 ParseOpcode); 70151937Sjkim 71151937Sjkimstatic void 72151937SjkimTrAmlSetSubtreeParent ( 73151937Sjkim ACPI_PARSE_OBJECT *Op, 74151937Sjkim ACPI_PARSE_OBJECT *Parent); 75151937Sjkim 76151937Sjkimstatic void 77151937SjkimTrAmlInsertPeer ( 78151937Sjkim ACPI_PARSE_OBJECT *Op, 79151937Sjkim ACPI_PARSE_OBJECT *NewPeer); 80151937Sjkim 81151937Sjkimstatic void 82151937SjkimTrDoDefinitionBlock ( 83151937Sjkim ACPI_PARSE_OBJECT *Op); 84151937Sjkim 85151937Sjkimstatic void 86151937SjkimTrDoSwitch ( 87151937Sjkim ACPI_PARSE_OBJECT *StartNode); 88151937Sjkim 89151937Sjkim 90118611Snjl/******************************************************************************* 91118611Snjl * 92118611Snjl * FUNCTION: TrAmlGetNextTempName 93118611Snjl * 94151937Sjkim * PARAMETERS: Op - Current parse op 95151937Sjkim * TempCount - Current temporary counter. Was originally 96151937Sjkim * per-module; Currently per method, could be 97151937Sjkim * expanded to per-scope. 98118611Snjl * 99151937Sjkim * RETURN: A pointer to name (allocated here). 100118611Snjl * 101241973Sjkim * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are 102151937Sjkim * reserved for use by the ASL compiler. (_T_0 through _T_Z) 103118611Snjl * 104118611Snjl ******************************************************************************/ 105118611Snjl 106151937Sjkimstatic char * 107118611SnjlTrAmlGetNextTempName ( 108151937Sjkim ACPI_PARSE_OBJECT *Op, 109151937Sjkim UINT8 *TempCount) 110118611Snjl{ 111118611Snjl char *TempName; 112118611Snjl 113118611Snjl 114151937Sjkim if (*TempCount >= (10+26)) /* 0-35 valid: 0-9 and A-Z for TempName[3] */ 115118611Snjl { 116118611Snjl /* Too many temps */ 117151937Sjkim 118151937Sjkim AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL); 119151937Sjkim return (NULL); 120118611Snjl } 121118611Snjl 122151937Sjkim TempName = UtLocalCalloc (5); 123138287Smarks 124151937Sjkim if (*TempCount < 10) /* 0-9 */ 125138287Smarks { 126151937Sjkim TempName[3] = (char) (*TempCount + '0'); 127138287Smarks } 128151937Sjkim else /* 10-35: A-Z */ 129138287Smarks { 130151937Sjkim TempName[3] = (char) (*TempCount + ('A' - 10)); 131138287Smarks } 132151937Sjkim (*TempCount)++; 133118611Snjl 134151937Sjkim /* First three characters are always "_T_" */ 135118611Snjl 136151937Sjkim TempName[0] = '_'; 137151937Sjkim TempName[1] = 'T'; 138151937Sjkim TempName[2] = '_'; 139118611Snjl 140151937Sjkim return (TempName); 141118611Snjl} 142118611Snjl 143118611Snjl 144118611Snjl/******************************************************************************* 145118611Snjl * 146118611Snjl * FUNCTION: TrAmlInitLineNumbers 147118611Snjl * 148151937Sjkim * PARAMETERS: Op - Op to be initialized 149118611Snjl * Neighbor - Op used for initialization values 150118611Snjl * 151118611Snjl * RETURN: None 152118611Snjl * 153118611Snjl * DESCRIPTION: Initialized the various line numbers for a parse node. 154118611Snjl * 155118611Snjl ******************************************************************************/ 156118611Snjl 157151937Sjkimstatic void 158118611SnjlTrAmlInitLineNumbers ( 159118611Snjl ACPI_PARSE_OBJECT *Op, 160118611Snjl ACPI_PARSE_OBJECT *Neighbor) 161118611Snjl{ 162118611Snjl 163118611Snjl Op->Asl.EndLine = Neighbor->Asl.EndLine; 164118611Snjl Op->Asl.EndLogicalLine = Neighbor->Asl.EndLogicalLine; 165118611Snjl Op->Asl.LineNumber = Neighbor->Asl.LineNumber; 166118611Snjl Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset; 167118611Snjl Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber; 168118611Snjl} 169118611Snjl 170118611Snjl 171118611Snjl/******************************************************************************* 172118611Snjl * 173118611Snjl * FUNCTION: TrAmlInitNode 174118611Snjl * 175151937Sjkim * PARAMETERS: Op - Op to be initialized 176118611Snjl * ParseOpcode - Opcode for this node 177118611Snjl * 178118611Snjl * RETURN: None 179118611Snjl * 180118611Snjl * DESCRIPTION: Initialize a node with the parse opcode and opcode name. 181118611Snjl * 182118611Snjl ******************************************************************************/ 183118611Snjl 184151937Sjkimstatic void 185118611SnjlTrAmlInitNode ( 186118611Snjl ACPI_PARSE_OBJECT *Op, 187118611Snjl UINT16 ParseOpcode) 188118611Snjl{ 189118611Snjl 190118611Snjl Op->Asl.ParseOpcode = ParseOpcode; 191118611Snjl UtSetParseOpName (Op); 192118611Snjl} 193118611Snjl 194118611Snjl 195118611Snjl/******************************************************************************* 196118611Snjl * 197118611Snjl * FUNCTION: TrAmlSetSubtreeParent 198118611Snjl * 199151937Sjkim * PARAMETERS: Op - First node in a list of peer nodes 200118611Snjl * Parent - Parent of the subtree 201118611Snjl * 202118611Snjl * RETURN: None 203118611Snjl * 204118611Snjl * DESCRIPTION: Set the parent for all peer nodes in a subtree 205118611Snjl * 206118611Snjl ******************************************************************************/ 207118611Snjl 208151937Sjkimstatic void 209118611SnjlTrAmlSetSubtreeParent ( 210118611Snjl ACPI_PARSE_OBJECT *Op, 211118611Snjl ACPI_PARSE_OBJECT *Parent) 212118611Snjl{ 213118611Snjl ACPI_PARSE_OBJECT *Next; 214118611Snjl 215118611Snjl 216118611Snjl Next = Op; 217118611Snjl while (Next) 218118611Snjl { 219118611Snjl Next->Asl.Parent = Parent; 220118611Snjl Next = Next->Asl.Next; 221118611Snjl } 222118611Snjl} 223118611Snjl 224118611Snjl 225118611Snjl/******************************************************************************* 226118611Snjl * 227118611Snjl * FUNCTION: TrAmlInsertPeer 228118611Snjl * 229151937Sjkim * PARAMETERS: Op - First node in a list of peer nodes 230118611Snjl * NewPeer - Peer node to insert 231118611Snjl * 232118611Snjl * RETURN: None 233118611Snjl * 234118611Snjl * DESCRIPTION: Insert a new peer node into a list of peers. 235118611Snjl * 236118611Snjl ******************************************************************************/ 237118611Snjl 238151937Sjkimstatic void 239118611SnjlTrAmlInsertPeer ( 240118611Snjl ACPI_PARSE_OBJECT *Op, 241118611Snjl ACPI_PARSE_OBJECT *NewPeer) 242118611Snjl{ 243118611Snjl 244118611Snjl NewPeer->Asl.Next = Op->Asl.Next; 245118611Snjl Op->Asl.Next = NewPeer; 246118611Snjl} 247118611Snjl 248118611Snjl 249118611Snjl/******************************************************************************* 250118611Snjl * 251118611Snjl * FUNCTION: TrAmlTransformWalk 252118611Snjl * 253118611Snjl * PARAMETERS: ASL_WALK_CALLBACK 254118611Snjl * 255118611Snjl * RETURN: None 256118611Snjl * 257118611Snjl * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 258118611Snjl * operands. 259118611Snjl * 260118611Snjl ******************************************************************************/ 261118611Snjl 262118611SnjlACPI_STATUS 263118611SnjlTrAmlTransformWalk ( 264118611Snjl ACPI_PARSE_OBJECT *Op, 265118611Snjl UINT32 Level, 266118611Snjl void *Context) 267118611Snjl{ 268118611Snjl 269118611Snjl TrTransformSubtree (Op); 270118611Snjl return (AE_OK); 271118611Snjl} 272118611Snjl 273118611Snjl 274118611Snjl/******************************************************************************* 275118611Snjl * 276118611Snjl * FUNCTION: TrTransformSubtree 277118611Snjl * 278118611Snjl * PARAMETERS: Op - The parent parse node 279118611Snjl * 280118611Snjl * RETURN: None 281118611Snjl * 282241973Sjkim * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 283118611Snjl * complex AML opcodes require processing of the child nodes 284118611Snjl * (arguments/operands). 285118611Snjl * 286118611Snjl ******************************************************************************/ 287118611Snjl 288151937Sjkimstatic void 289118611SnjlTrTransformSubtree ( 290118611Snjl ACPI_PARSE_OBJECT *Op) 291118611Snjl{ 292118611Snjl 293118611Snjl if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 294118611Snjl { 295118611Snjl return; 296118611Snjl } 297118611Snjl 298118611Snjl switch (Op->Asl.ParseOpcode) 299118611Snjl { 300118611Snjl case PARSEOP_DEFINITIONBLOCK: 301250838Sjkim 302118611Snjl TrDoDefinitionBlock (Op); 303118611Snjl break; 304118611Snjl 305118611Snjl case PARSEOP_SWITCH: 306250838Sjkim 307118611Snjl TrDoSwitch (Op); 308118611Snjl break; 309118611Snjl 310151937Sjkim case PARSEOP_METHOD: 311151937Sjkim /* 312151937Sjkim * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, 313151937Sjkim * however 314151937Sjkim */ 315151937Sjkim Gbl_TempCount = 0; 316151937Sjkim break; 317151937Sjkim 318118611Snjl default: 319250838Sjkim 320118611Snjl /* Nothing to do here for other opcodes */ 321250838Sjkim 322118611Snjl break; 323118611Snjl } 324118611Snjl} 325118611Snjl 326118611Snjl 327118611Snjl/******************************************************************************* 328118611Snjl * 329118611Snjl * FUNCTION: TrDoDefinitionBlock 330118611Snjl * 331118611Snjl * PARAMETERS: Op - Parse node 332118611Snjl * 333118611Snjl * RETURN: None 334118611Snjl * 335118611Snjl * DESCRIPTION: Find the end of the definition block and set a global to this 336241973Sjkim * node. It is used by the compiler to insert compiler-generated 337118611Snjl * names at the root level of the namespace. 338118611Snjl * 339118611Snjl ******************************************************************************/ 340118611Snjl 341151937Sjkimstatic void 342118611SnjlTrDoDefinitionBlock ( 343118611Snjl ACPI_PARSE_OBJECT *Op) 344118611Snjl{ 345118611Snjl ACPI_PARSE_OBJECT *Next; 346118611Snjl UINT32 i; 347118611Snjl 348118611Snjl 349118611Snjl Next = Op->Asl.Child; 350118611Snjl for (i = 0; i < 5; i++) 351118611Snjl { 352118611Snjl Next = Next->Asl.Next; 353151937Sjkim if (i == 0) 354151937Sjkim { 355151937Sjkim /* 356151937Sjkim * This is the table signature. Only the DSDT can be assumed 357151937Sjkim * to be at the root of the namespace; Therefore, namepath 358151937Sjkim * optimization can only be performed on the DSDT. 359151937Sjkim */ 360167802Sjkim if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT)) 361151937Sjkim { 362151937Sjkim Gbl_ReferenceOptimizationFlag = FALSE; 363151937Sjkim } 364151937Sjkim } 365118611Snjl } 366118611Snjl 367118611Snjl Gbl_FirstLevelInsertionNode = Next; 368118611Snjl} 369118611Snjl 370118611Snjl 371118611Snjl/******************************************************************************* 372118611Snjl * 373118611Snjl * FUNCTION: TrDoSwitch 374118611Snjl * 375118611Snjl * PARAMETERS: StartNode - Parse node for SWITCH 376118611Snjl * 377118611Snjl * RETURN: None 378118611Snjl * 379241973Sjkim * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is 380118611Snjl * no actual AML opcode for SWITCH -- it must be simulated. 381118611Snjl * 382118611Snjl ******************************************************************************/ 383118611Snjl 384151937Sjkimstatic void 385118611SnjlTrDoSwitch ( 386118611Snjl ACPI_PARSE_OBJECT *StartNode) 387118611Snjl{ 388118611Snjl ACPI_PARSE_OBJECT *Next; 389118611Snjl ACPI_PARSE_OBJECT *CaseOp = NULL; 390118611Snjl ACPI_PARSE_OBJECT *CaseBlock = NULL; 391118611Snjl ACPI_PARSE_OBJECT *DefaultOp = NULL; 392118611Snjl ACPI_PARSE_OBJECT *CurrentParentNode; 393118611Snjl ACPI_PARSE_OBJECT *Conditional = NULL; 394118611Snjl ACPI_PARSE_OBJECT *Predicate; 395118611Snjl ACPI_PARSE_OBJECT *Peer; 396118611Snjl ACPI_PARSE_OBJECT *NewOp; 397118611Snjl ACPI_PARSE_OBJECT *NewOp2; 398193529Sjkim ACPI_PARSE_OBJECT *MethodOp; 399199337Sjkim ACPI_PARSE_OBJECT *StoreOp; 400199337Sjkim ACPI_PARSE_OBJECT *BreakOp; 401228110Sjkim ACPI_PARSE_OBJECT *BufferOp; 402118611Snjl char *PredicateValueName; 403151937Sjkim UINT16 Index; 404151937Sjkim UINT32 Btype; 405118611Snjl 406118611Snjl 407151937Sjkim /* Start node is the Switch() node */ 408151937Sjkim 409118611Snjl CurrentParentNode = StartNode; 410118611Snjl 411151937Sjkim /* Create a new temp name of the form _T_x */ 412118611Snjl 413151937Sjkim PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount); 414151937Sjkim if (!PredicateValueName) 415151937Sjkim { 416151937Sjkim return; 417151937Sjkim } 418151937Sjkim 419151937Sjkim /* First child is the Switch() predicate */ 420151937Sjkim 421118611Snjl Next = StartNode->Asl.Child; 422118611Snjl 423151937Sjkim /* 424151937Sjkim * Examine the return type of the Switch Value - 425151937Sjkim * must be Integer/Buffer/String 426151937Sjkim */ 427151937Sjkim Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 428151937Sjkim Btype = AslKeywordMapping[Index].AcpiBtype; 429151937Sjkim if ((Btype != ACPI_BTYPE_INTEGER) && 430151937Sjkim (Btype != ACPI_BTYPE_STRING) && 431151937Sjkim (Btype != ACPI_BTYPE_BUFFER)) 432151937Sjkim { 433151937Sjkim AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); 434151937Sjkim Btype = ACPI_BTYPE_INTEGER; 435151937Sjkim } 436151937Sjkim 437118611Snjl /* CASE statements start at next child */ 438118611Snjl 439151937Sjkim Peer = Next->Asl.Next; 440118611Snjl while (Peer) 441118611Snjl { 442118611Snjl Next = Peer; 443118611Snjl Peer = Next->Asl.Next; 444118611Snjl 445118611Snjl if (Next->Asl.ParseOpcode == PARSEOP_CASE) 446118611Snjl { 447118611Snjl if (CaseOp) 448118611Snjl { 449118611Snjl /* Add an ELSE to complete the previous CASE */ 450118611Snjl 451118611Snjl NewOp = TrCreateLeafNode (PARSEOP_ELSE); 452118611Snjl NewOp->Asl.Parent = Conditional->Asl.Parent; 453118611Snjl TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); 454118611Snjl 455118611Snjl /* Link ELSE node as a peer to the previous IF */ 456118611Snjl 457118611Snjl TrAmlInsertPeer (Conditional, NewOp); 458118611Snjl CurrentParentNode = NewOp; 459118611Snjl } 460118611Snjl 461118611Snjl CaseOp = Next; 462118611Snjl Conditional = CaseOp; 463118611Snjl CaseBlock = CaseOp->Asl.Child->Asl.Next; 464118611Snjl Conditional->Asl.Child->Asl.Next = NULL; 465138287Smarks Predicate = CaseOp->Asl.Child; 466118611Snjl 467151937Sjkim if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || 468151937Sjkim (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 469138287Smarks { 470138287Smarks /* 471138287Smarks * Convert the package declaration to this form: 472138287Smarks * 473151937Sjkim * If (LNotEqual (Match (Package(<size>){<data>}, 474151937Sjkim * MEQ, _T_x, MTR, Zero, Zero), Ones)) 475138287Smarks */ 476138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ); 477138287Smarks Predicate->Asl.Next = NewOp2; 478138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 479118611Snjl 480138287Smarks NewOp = NewOp2; 481138287Smarks NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 482202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 483138287Smarks NewOp->Asl.Next = NewOp2; 484138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 485118611Snjl 486138287Smarks NewOp = NewOp2; 487138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR); 488138287Smarks NewOp->Asl.Next = NewOp2; 489138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 490118611Snjl 491138287Smarks NewOp = NewOp2; 492138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 493138287Smarks NewOp->Asl.Next = NewOp2; 494138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 495118611Snjl 496138287Smarks NewOp = NewOp2; 497138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 498138287Smarks NewOp->Asl.Next = NewOp2; 499138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 500118611Snjl 501138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCH); 502138287Smarks NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ 503138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 504138287Smarks TrAmlSetSubtreeParent (Predicate, NewOp2); 505138287Smarks 506138287Smarks NewOp = NewOp2; 507138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ONES); 508138287Smarks NewOp->Asl.Next = NewOp2; 509138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 510138287Smarks 511138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 512138287Smarks NewOp2->Asl.Child = NewOp; 513138287Smarks NewOp->Asl.Parent = NewOp2; 514138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 515138287Smarks TrAmlSetSubtreeParent (NewOp, NewOp2); 516138287Smarks 517138287Smarks NewOp = NewOp2; 518138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LNOT); 519138287Smarks NewOp2->Asl.Child = NewOp; 520138287Smarks NewOp2->Asl.Parent = Conditional; 521138287Smarks NewOp->Asl.Parent = NewOp2; 522138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 523138287Smarks 524138287Smarks Conditional->Asl.Child = NewOp2; 525138287Smarks NewOp2->Asl.Next = CaseBlock; 526138287Smarks } 527138287Smarks else 528138287Smarks { 529138287Smarks /* 530151937Sjkim * Integer and Buffer case. 531151937Sjkim * 532151937Sjkim * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} 533151937Sjkim * Note: SwitchValue is first to allow the CaseValue to be implicitly 534151937Sjkim * converted to the type of SwitchValue if necessary. 535151937Sjkim * 536138287Smarks * CaseOp->Child is the case value 537138287Smarks * CaseOp->Child->Peer is the beginning of the case block 538138287Smarks */ 539138287Smarks NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 540202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 541151937Sjkim NewOp->Asl.Next = Predicate; 542138287Smarks TrAmlInitLineNumbers (NewOp, Predicate); 543138287Smarks 544138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 545138287Smarks NewOp2->Asl.Parent = Conditional; 546151937Sjkim NewOp2->Asl.Child = NewOp; 547138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 548138287Smarks 549151937Sjkim TrAmlSetSubtreeParent (NewOp, NewOp2); 550138287Smarks 551138287Smarks Predicate = NewOp2; 552138287Smarks Predicate->Asl.Next = CaseBlock; 553138287Smarks 554138287Smarks TrAmlSetSubtreeParent (Predicate, Conditional); 555138287Smarks Conditional->Asl.Child = Predicate; 556138287Smarks } 557138287Smarks 558118611Snjl /* Reinitialize the CASE node to an IF node */ 559118611Snjl 560118611Snjl TrAmlInitNode (Conditional, PARSEOP_IF); 561118611Snjl 562118611Snjl /* 563118611Snjl * The first CASE(IF) is not nested under an ELSE. 564118611Snjl * All other CASEs are children of a parent ELSE. 565118611Snjl */ 566118611Snjl if (CurrentParentNode == StartNode) 567118611Snjl { 568199337Sjkim Conditional->Asl.Next = NULL; 569118611Snjl } 570118611Snjl else 571118611Snjl { 572118611Snjl /* 573241973Sjkim * The IF is a child of previous IF/ELSE. It 574118611Snjl * is therefore without peer. 575118611Snjl */ 576118611Snjl CurrentParentNode->Asl.Child = Conditional; 577118611Snjl Conditional->Asl.Parent = CurrentParentNode; 578118611Snjl Conditional->Asl.Next = NULL; 579118611Snjl } 580118611Snjl } 581118611Snjl else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) 582118611Snjl { 583118611Snjl if (DefaultOp) 584118611Snjl { 585138287Smarks /* 586138287Smarks * More than one Default 587167802Sjkim * (Parser does not catch this, must check here) 588138287Smarks */ 589167802Sjkim AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); 590118611Snjl } 591167802Sjkim else 592167802Sjkim { 593167802Sjkim /* Save the DEFAULT node for later, after CASEs */ 594118611Snjl 595167802Sjkim DefaultOp = Next; 596167802Sjkim } 597118611Snjl } 598118611Snjl else 599118611Snjl { 600138287Smarks /* Unknown peer opcode */ 601118611Snjl 602209746Sjkim AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", 603118611Snjl Next->Asl.ParseOpName, Next->Asl.ParseOpcode); 604118611Snjl } 605118611Snjl } 606118611Snjl 607151937Sjkim /* Add the default case at the end of the if/else construct */ 608151937Sjkim 609118611Snjl if (DefaultOp) 610118611Snjl { 611138287Smarks /* If no CASE statements, this is an error - see below */ 612138287Smarks 613118611Snjl if (CaseOp) 614118611Snjl { 615138287Smarks /* Convert the DEFAULT node to an ELSE */ 616118611Snjl 617118611Snjl TrAmlInitNode (DefaultOp, PARSEOP_ELSE); 618118611Snjl DefaultOp->Asl.Parent = Conditional->Asl.Parent; 619118611Snjl 620138287Smarks /* Link ELSE node as a peer to the previous IF */ 621138287Smarks 622138287Smarks TrAmlInsertPeer (Conditional, DefaultOp); 623118611Snjl } 624118611Snjl } 625118611Snjl 626138287Smarks if (!CaseOp) 627138287Smarks { 628138287Smarks AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); 629138287Smarks } 630138287Smarks 631167802Sjkim 632118611Snjl /* 633167802Sjkim * Create a Name(_T_x, ...) statement. This statement must appear at the 634167802Sjkim * method level, in case a loop surrounds the switch statement and could 635167802Sjkim * cause the name to be created twice (error). 636118611Snjl */ 637167802Sjkim 638167802Sjkim /* Create the Name node */ 639167802Sjkim 640151937Sjkim Predicate = StartNode->Asl.Child; 641167802Sjkim NewOp = TrCreateLeafNode (PARSEOP_NAME); 642228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 643151937Sjkim 644167802Sjkim /* Find the parent method */ 645151937Sjkim 646167802Sjkim Next = StartNode; 647167802Sjkim while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && 648167802Sjkim (Next->Asl.ParseOpcode != PARSEOP_DEFINITIONBLOCK)) 649167802Sjkim { 650167802Sjkim Next = Next->Asl.Parent; 651167802Sjkim } 652193529Sjkim MethodOp = Next; 653167802Sjkim 654138287Smarks NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED; 655167802Sjkim NewOp->Asl.Parent = Next; 656118611Snjl 657167802Sjkim /* Insert name after the method name and arguments */ 658167802Sjkim 659193529Sjkim Next = Next->Asl.Child; /* Name */ 660193529Sjkim Next = Next->Asl.Next; /* NumArgs */ 661193529Sjkim Next = Next->Asl.Next; /* SerializeRule */ 662167802Sjkim 663193529Sjkim /* 664193529Sjkim * If method is not Serialized, we must make is so, because of the way 665193529Sjkim * that Switch() must be implemented -- we cannot allow multiple threads 666193529Sjkim * to execute this method concurrently since we need to create local 667193529Sjkim * temporary name(s). 668193529Sjkim */ 669193529Sjkim if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) 670193529Sjkim { 671193529Sjkim AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, "Due to use of Switch operator"); 672193529Sjkim Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; 673193529Sjkim } 674193529Sjkim 675193529Sjkim Next = Next->Asl.Next; /* SyncLevel */ 676193529Sjkim Next = Next->Asl.Next; /* ReturnType */ 677193529Sjkim Next = Next->Asl.Next; /* ParameterTypes */ 678193529Sjkim 679167802Sjkim TrAmlInsertPeer (Next, NewOp); 680167802Sjkim TrAmlInitLineNumbers (NewOp, Next); 681167802Sjkim 682167802Sjkim /* Create the NameSeg child for the Name node */ 683167802Sjkim 684151937Sjkim NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 685202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 686228110Sjkim TrAmlInitLineNumbers (NewOp2, NewOp); 687151937Sjkim NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION; 688118611Snjl NewOp->Asl.Child = NewOp2; 689118611Snjl 690167802Sjkim /* Create the initial value for the Name. Btype was already validated above */ 691118611Snjl 692151937Sjkim switch (Btype) 693151937Sjkim { 694151937Sjkim case ACPI_BTYPE_INTEGER: 695250838Sjkim 696167802Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO, 697202771Sjkim (UINT64) 0); 698228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 699151937Sjkim break; 700118611Snjl 701151937Sjkim case ACPI_BTYPE_STRING: 702250838Sjkim 703151937Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, 704202771Sjkim (UINT64) ACPI_TO_INTEGER ("")); 705228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 706151937Sjkim break; 707118611Snjl 708151937Sjkim case ACPI_BTYPE_BUFFER: 709250838Sjkim 710151937Sjkim (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER, 711202771Sjkim (UINT64) 0)); 712151937Sjkim Next = NewOp2->Asl.Next; 713228110Sjkim TrAmlInitLineNumbers (Next, NewOp2); 714151937Sjkim (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO, 715202771Sjkim (UINT64) 1)); 716228110Sjkim TrAmlInitLineNumbers (Next->Asl.Child, Next); 717151937Sjkim 718228110Sjkim BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0); 719228110Sjkim TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); 720228110Sjkim (void) TrLinkPeerNode (Next->Asl.Child, BufferOp); 721228110Sjkim 722151937Sjkim TrAmlSetSubtreeParent (Next->Asl.Child, Next); 723151937Sjkim break; 724151937Sjkim 725151937Sjkim default: 726250838Sjkim 727151937Sjkim break; 728151937Sjkim } 729151937Sjkim 730151937Sjkim TrAmlSetSubtreeParent (NewOp2, NewOp); 731151937Sjkim 732118611Snjl /* 733199337Sjkim * Transform the Switch() into a While(One)-Break node. 734199337Sjkim * And create a Store() node which will be used to save the 735241973Sjkim * Switch() value. The store is of the form: Store (Value, _T_x) 736151937Sjkim * where _T_x is the temp variable. 737118611Snjl */ 738199337Sjkim TrAmlInitNode (StartNode, PARSEOP_WHILE); 739199337Sjkim NewOp = TrCreateLeafNode (PARSEOP_ONE); 740228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 741199337Sjkim NewOp->Asl.Next = Predicate->Asl.Next; 742199337Sjkim NewOp->Asl.Parent = StartNode; 743199337Sjkim StartNode->Asl.Child = NewOp; 744118611Snjl 745199337Sjkim /* Create a Store() node */ 746199337Sjkim 747199337Sjkim StoreOp = TrCreateLeafNode (PARSEOP_STORE); 748228110Sjkim TrAmlInitLineNumbers (StoreOp, NewOp); 749199337Sjkim StoreOp->Asl.Parent = StartNode; 750199337Sjkim TrAmlInsertPeer (NewOp, StoreOp); 751199337Sjkim 752151937Sjkim /* Complete the Store subtree */ 753151937Sjkim 754199337Sjkim StoreOp->Asl.Child = Predicate; 755199337Sjkim Predicate->Asl.Parent = StoreOp; 756151937Sjkim 757151937Sjkim NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 758202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 759228110Sjkim TrAmlInitLineNumbers (NewOp, StoreOp); 760199337Sjkim NewOp->Asl.Parent = StoreOp; 761118611Snjl Predicate->Asl.Next = NewOp; 762199337Sjkim 763199337Sjkim /* Create a Break() node and insert it into the end of While() */ 764199337Sjkim 765199337Sjkim Conditional = StartNode->Asl.Child; 766199337Sjkim while (Conditional->Asl.Next) 767199337Sjkim { 768199337Sjkim Conditional = Conditional->Asl.Next; 769199337Sjkim } 770199337Sjkim 771199337Sjkim BreakOp = TrCreateLeafNode (PARSEOP_BREAK); 772228110Sjkim TrAmlInitLineNumbers (BreakOp, NewOp); 773199337Sjkim BreakOp->Asl.Parent = StartNode; 774199337Sjkim TrAmlInsertPeer (Conditional, BreakOp); 775118611Snjl} 776