1118611Snjl/****************************************************************************** 2118611Snjl * 3118611Snjl * Module Name: asltransform - Parse tree transforms 4118611Snjl * 5118611Snjl *****************************************************************************/ 6118611Snjl 7217365Sjkim/* 8306536Sjkim * Copyright (C) 2000 - 2016, 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 114306536Sjkim 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 } 132306536Sjkim 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; 221306536Sjkim 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; 246306536Sjkim Op->Asl.Next = NewPeer; 247118611Snjl} 248118611Snjl 249118611Snjl 250118611Snjl/******************************************************************************* 251118611Snjl * 252306536Sjkim * FUNCTION: TrAmlTransformWalkBegin 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 264306536SjkimTrAmlTransformWalkBegin ( 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 * 277306536Sjkim * FUNCTION: TrAmlTransformWalkEnd 278306536Sjkim * 279306536Sjkim * PARAMETERS: ASL_WALK_CALLBACK 280306536Sjkim * 281306536Sjkim * RETURN: None 282306536Sjkim * 283306536Sjkim * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML 284306536Sjkim * operands. 285306536Sjkim * 286306536Sjkim ******************************************************************************/ 287306536Sjkim 288306536SjkimACPI_STATUS 289306536SjkimTrAmlTransformWalkEnd ( 290306536Sjkim ACPI_PARSE_OBJECT *Op, 291306536Sjkim UINT32 Level, 292306536Sjkim void *Context) 293306536Sjkim{ 294306536Sjkim 295306536Sjkim /* Save possible Externals list in the DefintionBlock Op */ 296306536Sjkim 297306536Sjkim if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK) 298306536Sjkim { 299306536Sjkim Op->Asl.Value.Arg = Gbl_ExternalsListHead; 300306536Sjkim Gbl_ExternalsListHead = NULL; 301306536Sjkim } 302306536Sjkim 303306536Sjkim return (AE_OK); 304306536Sjkim} 305306536Sjkim 306306536Sjkim 307306536Sjkim/******************************************************************************* 308306536Sjkim * 309118611Snjl * FUNCTION: TrTransformSubtree 310118611Snjl * 311118611Snjl * PARAMETERS: Op - The parent parse node 312118611Snjl * 313118611Snjl * RETURN: None 314118611Snjl * 315241973Sjkim * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more 316118611Snjl * complex AML opcodes require processing of the child nodes 317118611Snjl * (arguments/operands). 318118611Snjl * 319118611Snjl ******************************************************************************/ 320118611Snjl 321151937Sjkimstatic void 322118611SnjlTrTransformSubtree ( 323118611Snjl ACPI_PARSE_OBJECT *Op) 324118611Snjl{ 325118611Snjl 326118611Snjl if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE) 327118611Snjl { 328118611Snjl return; 329118611Snjl } 330118611Snjl 331118611Snjl switch (Op->Asl.ParseOpcode) 332118611Snjl { 333306536Sjkim case PARSEOP_DEFINITION_BLOCK: 334250838Sjkim 335118611Snjl TrDoDefinitionBlock (Op); 336118611Snjl break; 337118611Snjl 338118611Snjl case PARSEOP_SWITCH: 339250838Sjkim 340118611Snjl TrDoSwitch (Op); 341118611Snjl break; 342118611Snjl 343151937Sjkim case PARSEOP_METHOD: 344151937Sjkim /* 345151937Sjkim * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global, 346151937Sjkim * however 347151937Sjkim */ 348151937Sjkim Gbl_TempCount = 0; 349151937Sjkim break; 350151937Sjkim 351306536Sjkim case PARSEOP_EXTERNAL: 352306536Sjkim 353306536Sjkim if (Gbl_DoExternals == TRUE) 354306536Sjkim { 355306536Sjkim ExDoExternal (Op); 356306536Sjkim } 357306536Sjkim 358306536Sjkim break; 359306536Sjkim 360118611Snjl default: 361250838Sjkim 362118611Snjl /* Nothing to do here for other opcodes */ 363250838Sjkim 364118611Snjl break; 365118611Snjl } 366118611Snjl} 367118611Snjl 368118611Snjl 369118611Snjl/******************************************************************************* 370118611Snjl * 371118611Snjl * FUNCTION: TrDoDefinitionBlock 372118611Snjl * 373118611Snjl * PARAMETERS: Op - Parse node 374118611Snjl * 375118611Snjl * RETURN: None 376118611Snjl * 377118611Snjl * DESCRIPTION: Find the end of the definition block and set a global to this 378241973Sjkim * node. It is used by the compiler to insert compiler-generated 379118611Snjl * names at the root level of the namespace. 380118611Snjl * 381118611Snjl ******************************************************************************/ 382118611Snjl 383151937Sjkimstatic void 384118611SnjlTrDoDefinitionBlock ( 385118611Snjl ACPI_PARSE_OBJECT *Op) 386118611Snjl{ 387118611Snjl ACPI_PARSE_OBJECT *Next; 388118611Snjl UINT32 i; 389118611Snjl 390118611Snjl 391306536Sjkim /* Reset external list when starting a definition block */ 392306536Sjkim 393306536Sjkim Gbl_ExternalsListHead = NULL; 394306536Sjkim 395118611Snjl Next = Op->Asl.Child; 396118611Snjl for (i = 0; i < 5; i++) 397118611Snjl { 398118611Snjl Next = Next->Asl.Next; 399151937Sjkim if (i == 0) 400151937Sjkim { 401151937Sjkim /* 402151937Sjkim * This is the table signature. Only the DSDT can be assumed 403151937Sjkim * to be at the root of the namespace; Therefore, namepath 404151937Sjkim * optimization can only be performed on the DSDT. 405151937Sjkim */ 406167802Sjkim if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT)) 407151937Sjkim { 408151937Sjkim Gbl_ReferenceOptimizationFlag = FALSE; 409151937Sjkim } 410151937Sjkim } 411118611Snjl } 412118611Snjl 413118611Snjl Gbl_FirstLevelInsertionNode = Next; 414118611Snjl} 415118611Snjl 416118611Snjl 417118611Snjl/******************************************************************************* 418118611Snjl * 419118611Snjl * FUNCTION: TrDoSwitch 420118611Snjl * 421118611Snjl * PARAMETERS: StartNode - Parse node for SWITCH 422118611Snjl * 423118611Snjl * RETURN: None 424118611Snjl * 425241973Sjkim * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is 426118611Snjl * no actual AML opcode for SWITCH -- it must be simulated. 427118611Snjl * 428118611Snjl ******************************************************************************/ 429118611Snjl 430151937Sjkimstatic void 431118611SnjlTrDoSwitch ( 432118611Snjl ACPI_PARSE_OBJECT *StartNode) 433118611Snjl{ 434118611Snjl ACPI_PARSE_OBJECT *Next; 435118611Snjl ACPI_PARSE_OBJECT *CaseOp = NULL; 436118611Snjl ACPI_PARSE_OBJECT *CaseBlock = NULL; 437118611Snjl ACPI_PARSE_OBJECT *DefaultOp = NULL; 438118611Snjl ACPI_PARSE_OBJECT *CurrentParentNode; 439118611Snjl ACPI_PARSE_OBJECT *Conditional = NULL; 440118611Snjl ACPI_PARSE_OBJECT *Predicate; 441118611Snjl ACPI_PARSE_OBJECT *Peer; 442118611Snjl ACPI_PARSE_OBJECT *NewOp; 443118611Snjl ACPI_PARSE_OBJECT *NewOp2; 444193529Sjkim ACPI_PARSE_OBJECT *MethodOp; 445199337Sjkim ACPI_PARSE_OBJECT *StoreOp; 446199337Sjkim ACPI_PARSE_OBJECT *BreakOp; 447228110Sjkim ACPI_PARSE_OBJECT *BufferOp; 448118611Snjl char *PredicateValueName; 449151937Sjkim UINT16 Index; 450151937Sjkim UINT32 Btype; 451118611Snjl 452118611Snjl 453151937Sjkim /* Start node is the Switch() node */ 454151937Sjkim 455118611Snjl CurrentParentNode = StartNode; 456118611Snjl 457151937Sjkim /* Create a new temp name of the form _T_x */ 458118611Snjl 459151937Sjkim PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount); 460151937Sjkim if (!PredicateValueName) 461151937Sjkim { 462151937Sjkim return; 463151937Sjkim } 464151937Sjkim 465151937Sjkim /* First child is the Switch() predicate */ 466151937Sjkim 467118611Snjl Next = StartNode->Asl.Child; 468118611Snjl 469151937Sjkim /* 470151937Sjkim * Examine the return type of the Switch Value - 471151937Sjkim * must be Integer/Buffer/String 472151937Sjkim */ 473151937Sjkim Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE); 474151937Sjkim Btype = AslKeywordMapping[Index].AcpiBtype; 475151937Sjkim if ((Btype != ACPI_BTYPE_INTEGER) && 476151937Sjkim (Btype != ACPI_BTYPE_STRING) && 477151937Sjkim (Btype != ACPI_BTYPE_BUFFER)) 478151937Sjkim { 479151937Sjkim AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL); 480151937Sjkim Btype = ACPI_BTYPE_INTEGER; 481151937Sjkim } 482151937Sjkim 483118611Snjl /* CASE statements start at next child */ 484118611Snjl 485151937Sjkim Peer = Next->Asl.Next; 486118611Snjl while (Peer) 487118611Snjl { 488118611Snjl Next = Peer; 489118611Snjl Peer = Next->Asl.Next; 490118611Snjl 491118611Snjl if (Next->Asl.ParseOpcode == PARSEOP_CASE) 492118611Snjl { 493118611Snjl if (CaseOp) 494118611Snjl { 495118611Snjl /* Add an ELSE to complete the previous CASE */ 496118611Snjl 497306536Sjkim NewOp = TrCreateLeafNode (PARSEOP_ELSE); 498118611Snjl NewOp->Asl.Parent = Conditional->Asl.Parent; 499118611Snjl TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent); 500118611Snjl 501118611Snjl /* Link ELSE node as a peer to the previous IF */ 502118611Snjl 503118611Snjl TrAmlInsertPeer (Conditional, NewOp); 504118611Snjl CurrentParentNode = NewOp; 505118611Snjl } 506118611Snjl 507306536Sjkim CaseOp = Next; 508118611Snjl Conditional = CaseOp; 509306536Sjkim CaseBlock = CaseOp->Asl.Child->Asl.Next; 510118611Snjl Conditional->Asl.Child->Asl.Next = NULL; 511138287Smarks Predicate = CaseOp->Asl.Child; 512118611Snjl 513151937Sjkim if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) || 514151937Sjkim (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)) 515138287Smarks { 516138287Smarks /* 517138287Smarks * Convert the package declaration to this form: 518138287Smarks * 519151937Sjkim * If (LNotEqual (Match (Package(<size>){<data>}, 520151937Sjkim * MEQ, _T_x, MTR, Zero, Zero), Ones)) 521138287Smarks */ 522138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ); 523138287Smarks Predicate->Asl.Next = NewOp2; 524138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 525118611Snjl 526138287Smarks NewOp = NewOp2; 527138287Smarks NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 528202771Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 529138287Smarks NewOp->Asl.Next = NewOp2; 530138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 531118611Snjl 532138287Smarks NewOp = NewOp2; 533138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR); 534138287Smarks NewOp->Asl.Next = NewOp2; 535138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 536118611Snjl 537138287Smarks NewOp = NewOp2; 538138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 539138287Smarks NewOp->Asl.Next = NewOp2; 540138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 541118611Snjl 542138287Smarks NewOp = NewOp2; 543138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ZERO); 544138287Smarks NewOp->Asl.Next = NewOp2; 545138287Smarks TrAmlInitLineNumbers (NewOp2, Predicate); 546118611Snjl 547138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_MATCH); 548138287Smarks NewOp2->Asl.Child = Predicate; /* PARSEOP_PACKAGE */ 549138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 550138287Smarks TrAmlSetSubtreeParent (Predicate, NewOp2); 551138287Smarks 552138287Smarks NewOp = NewOp2; 553138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_ONES); 554138287Smarks NewOp->Asl.Next = NewOp2; 555138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 556138287Smarks 557138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 558138287Smarks NewOp2->Asl.Child = NewOp; 559138287Smarks NewOp->Asl.Parent = NewOp2; 560138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 561138287Smarks TrAmlSetSubtreeParent (NewOp, NewOp2); 562138287Smarks 563138287Smarks NewOp = NewOp2; 564138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LNOT); 565138287Smarks NewOp2->Asl.Child = NewOp; 566138287Smarks NewOp2->Asl.Parent = Conditional; 567138287Smarks NewOp->Asl.Parent = NewOp2; 568138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 569138287Smarks 570138287Smarks Conditional->Asl.Child = NewOp2; 571138287Smarks NewOp2->Asl.Next = CaseBlock; 572138287Smarks } 573138287Smarks else 574138287Smarks { 575138287Smarks /* 576151937Sjkim * Integer and Buffer case. 577151937Sjkim * 578151937Sjkim * Change CaseOp() to: If (LEqual (SwitchValue, CaseValue)) {...} 579151937Sjkim * Note: SwitchValue is first to allow the CaseValue to be implicitly 580151937Sjkim * converted to the type of SwitchValue if necessary. 581151937Sjkim * 582138287Smarks * CaseOp->Child is the case value 583138287Smarks * CaseOp->Child->Peer is the beginning of the case block 584138287Smarks */ 585138287Smarks NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING, 586306536Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 587151937Sjkim NewOp->Asl.Next = Predicate; 588138287Smarks TrAmlInitLineNumbers (NewOp, Predicate); 589138287Smarks 590138287Smarks NewOp2 = TrCreateLeafNode (PARSEOP_LEQUAL); 591138287Smarks NewOp2->Asl.Parent = Conditional; 592151937Sjkim NewOp2->Asl.Child = NewOp; 593138287Smarks TrAmlInitLineNumbers (NewOp2, Conditional); 594138287Smarks 595151937Sjkim TrAmlSetSubtreeParent (NewOp, NewOp2); 596138287Smarks 597138287Smarks Predicate = NewOp2; 598138287Smarks Predicate->Asl.Next = CaseBlock; 599138287Smarks 600138287Smarks TrAmlSetSubtreeParent (Predicate, Conditional); 601138287Smarks Conditional->Asl.Child = Predicate; 602138287Smarks } 603138287Smarks 604118611Snjl /* Reinitialize the CASE node to an IF node */ 605118611Snjl 606118611Snjl TrAmlInitNode (Conditional, PARSEOP_IF); 607118611Snjl 608118611Snjl /* 609118611Snjl * The first CASE(IF) is not nested under an ELSE. 610118611Snjl * All other CASEs are children of a parent ELSE. 611118611Snjl */ 612118611Snjl if (CurrentParentNode == StartNode) 613118611Snjl { 614199337Sjkim Conditional->Asl.Next = NULL; 615118611Snjl } 616118611Snjl else 617118611Snjl { 618118611Snjl /* 619241973Sjkim * The IF is a child of previous IF/ELSE. It 620118611Snjl * is therefore without peer. 621118611Snjl */ 622118611Snjl CurrentParentNode->Asl.Child = Conditional; 623118611Snjl Conditional->Asl.Parent = CurrentParentNode; 624118611Snjl Conditional->Asl.Next = NULL; 625118611Snjl } 626118611Snjl } 627118611Snjl else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT) 628118611Snjl { 629118611Snjl if (DefaultOp) 630118611Snjl { 631138287Smarks /* 632138287Smarks * More than one Default 633167802Sjkim * (Parser does not catch this, must check here) 634138287Smarks */ 635167802Sjkim AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL); 636118611Snjl } 637167802Sjkim else 638167802Sjkim { 639167802Sjkim /* Save the DEFAULT node for later, after CASEs */ 640118611Snjl 641167802Sjkim DefaultOp = Next; 642167802Sjkim } 643118611Snjl } 644118611Snjl else 645118611Snjl { 646138287Smarks /* Unknown peer opcode */ 647118611Snjl 648209746Sjkim AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n", 649306536Sjkim Next->Asl.ParseOpName, Next->Asl.ParseOpcode); 650118611Snjl } 651118611Snjl } 652118611Snjl 653151937Sjkim /* Add the default case at the end of the if/else construct */ 654151937Sjkim 655118611Snjl if (DefaultOp) 656118611Snjl { 657138287Smarks /* If no CASE statements, this is an error - see below */ 658138287Smarks 659118611Snjl if (CaseOp) 660118611Snjl { 661138287Smarks /* Convert the DEFAULT node to an ELSE */ 662118611Snjl 663118611Snjl TrAmlInitNode (DefaultOp, PARSEOP_ELSE); 664118611Snjl DefaultOp->Asl.Parent = Conditional->Asl.Parent; 665118611Snjl 666138287Smarks /* Link ELSE node as a peer to the previous IF */ 667138287Smarks 668138287Smarks TrAmlInsertPeer (Conditional, DefaultOp); 669118611Snjl } 670118611Snjl } 671118611Snjl 672138287Smarks if (!CaseOp) 673138287Smarks { 674138287Smarks AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL); 675138287Smarks } 676138287Smarks 677167802Sjkim 678118611Snjl /* 679167802Sjkim * Create a Name(_T_x, ...) statement. This statement must appear at the 680167802Sjkim * method level, in case a loop surrounds the switch statement and could 681167802Sjkim * cause the name to be created twice (error). 682118611Snjl */ 683167802Sjkim 684167802Sjkim /* Create the Name node */ 685167802Sjkim 686151937Sjkim Predicate = StartNode->Asl.Child; 687167802Sjkim NewOp = TrCreateLeafNode (PARSEOP_NAME); 688228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 689151937Sjkim 690167802Sjkim /* Find the parent method */ 691151937Sjkim 692167802Sjkim Next = StartNode; 693167802Sjkim while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) && 694306536Sjkim (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK)) 695167802Sjkim { 696167802Sjkim Next = Next->Asl.Parent; 697167802Sjkim } 698193529Sjkim MethodOp = Next; 699167802Sjkim 700138287Smarks NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED; 701167802Sjkim NewOp->Asl.Parent = Next; 702118611Snjl 703167802Sjkim /* Insert name after the method name and arguments */ 704167802Sjkim 705193529Sjkim Next = Next->Asl.Child; /* Name */ 706193529Sjkim Next = Next->Asl.Next; /* NumArgs */ 707193529Sjkim Next = Next->Asl.Next; /* SerializeRule */ 708167802Sjkim 709193529Sjkim /* 710193529Sjkim * If method is not Serialized, we must make is so, because of the way 711193529Sjkim * that Switch() must be implemented -- we cannot allow multiple threads 712193529Sjkim * to execute this method concurrently since we need to create local 713193529Sjkim * temporary name(s). 714193529Sjkim */ 715193529Sjkim if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL) 716193529Sjkim { 717306536Sjkim AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp, 718306536Sjkim "Due to use of Switch operator"); 719193529Sjkim Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL; 720193529Sjkim } 721193529Sjkim 722193529Sjkim Next = Next->Asl.Next; /* SyncLevel */ 723193529Sjkim Next = Next->Asl.Next; /* ReturnType */ 724193529Sjkim Next = Next->Asl.Next; /* ParameterTypes */ 725193529Sjkim 726167802Sjkim TrAmlInsertPeer (Next, NewOp); 727167802Sjkim TrAmlInitLineNumbers (NewOp, Next); 728167802Sjkim 729167802Sjkim /* Create the NameSeg child for the Name node */ 730167802Sjkim 731151937Sjkim NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 732306536Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 733228110Sjkim TrAmlInitLineNumbers (NewOp2, NewOp); 734151937Sjkim NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION; 735118611Snjl NewOp->Asl.Child = NewOp2; 736118611Snjl 737167802Sjkim /* Create the initial value for the Name. Btype was already validated above */ 738118611Snjl 739151937Sjkim switch (Btype) 740151937Sjkim { 741151937Sjkim case ACPI_BTYPE_INTEGER: 742250838Sjkim 743167802Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO, 744306536Sjkim (UINT64) 0); 745228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 746151937Sjkim break; 747118611Snjl 748151937Sjkim case ACPI_BTYPE_STRING: 749250838Sjkim 750151937Sjkim NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL, 751306536Sjkim (UINT64) ACPI_TO_INTEGER ("")); 752228110Sjkim TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp); 753151937Sjkim break; 754118611Snjl 755151937Sjkim case ACPI_BTYPE_BUFFER: 756250838Sjkim 757151937Sjkim (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER, 758306536Sjkim (UINT64) 0)); 759151937Sjkim Next = NewOp2->Asl.Next; 760228110Sjkim TrAmlInitLineNumbers (Next, NewOp2); 761151937Sjkim (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO, 762306536Sjkim (UINT64) 1)); 763228110Sjkim TrAmlInitLineNumbers (Next->Asl.Child, Next); 764151937Sjkim 765228110Sjkim BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0); 766228110Sjkim TrAmlInitLineNumbers (BufferOp, Next->Asl.Child); 767228110Sjkim (void) TrLinkPeerNode (Next->Asl.Child, BufferOp); 768228110Sjkim 769151937Sjkim TrAmlSetSubtreeParent (Next->Asl.Child, Next); 770151937Sjkim break; 771151937Sjkim 772151937Sjkim default: 773250838Sjkim 774151937Sjkim break; 775151937Sjkim } 776151937Sjkim 777151937Sjkim TrAmlSetSubtreeParent (NewOp2, NewOp); 778151937Sjkim 779118611Snjl /* 780199337Sjkim * Transform the Switch() into a While(One)-Break node. 781199337Sjkim * And create a Store() node which will be used to save the 782241973Sjkim * Switch() value. The store is of the form: Store (Value, _T_x) 783151937Sjkim * where _T_x is the temp variable. 784118611Snjl */ 785199337Sjkim TrAmlInitNode (StartNode, PARSEOP_WHILE); 786199337Sjkim NewOp = TrCreateLeafNode (PARSEOP_ONE); 787228110Sjkim TrAmlInitLineNumbers (NewOp, StartNode); 788199337Sjkim NewOp->Asl.Next = Predicate->Asl.Next; 789199337Sjkim NewOp->Asl.Parent = StartNode; 790199337Sjkim StartNode->Asl.Child = NewOp; 791118611Snjl 792199337Sjkim /* Create a Store() node */ 793199337Sjkim 794199337Sjkim StoreOp = TrCreateLeafNode (PARSEOP_STORE); 795228110Sjkim TrAmlInitLineNumbers (StoreOp, NewOp); 796199337Sjkim StoreOp->Asl.Parent = StartNode; 797199337Sjkim TrAmlInsertPeer (NewOp, StoreOp); 798199337Sjkim 799151937Sjkim /* Complete the Store subtree */ 800151937Sjkim 801199337Sjkim StoreOp->Asl.Child = Predicate; 802199337Sjkim Predicate->Asl.Parent = StoreOp; 803151937Sjkim 804151937Sjkim NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG, 805306536Sjkim (UINT64) ACPI_TO_INTEGER (PredicateValueName)); 806228110Sjkim TrAmlInitLineNumbers (NewOp, StoreOp); 807199337Sjkim NewOp->Asl.Parent = StoreOp; 808118611Snjl Predicate->Asl.Next = NewOp; 809199337Sjkim 810199337Sjkim /* Create a Break() node and insert it into the end of While() */ 811199337Sjkim 812199337Sjkim Conditional = StartNode->Asl.Child; 813199337Sjkim while (Conditional->Asl.Next) 814199337Sjkim { 815199337Sjkim Conditional = Conditional->Asl.Next; 816199337Sjkim } 817199337Sjkim 818199337Sjkim BreakOp = TrCreateLeafNode (PARSEOP_BREAK); 819228110Sjkim TrAmlInitLineNumbers (BreakOp, NewOp); 820199337Sjkim BreakOp->Asl.Parent = StartNode; 821199337Sjkim TrAmlInsertPeer (Conditional, BreakOp); 822118611Snjl} 823