xref: /dflybsd-src/sys/contrib/dev/acpica/source/compiler/asltransform.c (revision 3eec877432eb8056a5450dd96fad6f6abad016b9)
1 /******************************************************************************
2  *
3  * Module Name: asltransform - Parse tree transforms
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, Intel Corp.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions, and the following disclaimer,
16  *    without modification.
17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18  *    substantially similar to the "NO WARRANTY" disclaimer below
19  *    ("Disclaimer") and any redistribution must be conditioned upon
20  *    including a substantially similar Disclaimer requirement for further
21  *    binary redistribution.
22  * 3. Neither the names of the above-listed copyright holders nor the names
23  *    of any contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * Alternatively, this software may be distributed under the terms of the
27  * GNU General Public License ("GPL") version 2 as published by the Free
28  * Software Foundation.
29  *
30  * NO WARRANTY
31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41  * POSSIBILITY OF SUCH DAMAGES.
42  */
43 
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 
47 #define _COMPONENT          ACPI_COMPILER
48         ACPI_MODULE_NAME    ("asltransform")
49 
50 /* Local prototypes */
51 
52 static void
53 TrTransformSubtree (
54     ACPI_PARSE_OBJECT       *Op);
55 
56 static char *
57 TrAmlGetNextTempName (
58     ACPI_PARSE_OBJECT       *Op,
59     UINT8                   *TempCount);
60 
61 static void
62 TrAmlInitLineNumbers (
63     ACPI_PARSE_OBJECT       *Op,
64     ACPI_PARSE_OBJECT       *Neighbor);
65 
66 static void
67 TrAmlInitNode (
68     ACPI_PARSE_OBJECT       *Op,
69     UINT16                  ParseOpcode);
70 
71 static void
72 TrAmlSetSubtreeParent (
73     ACPI_PARSE_OBJECT       *Op,
74     ACPI_PARSE_OBJECT       *Parent);
75 
76 static void
77 TrAmlInsertPeer (
78     ACPI_PARSE_OBJECT       *Op,
79     ACPI_PARSE_OBJECT       *NewPeer);
80 
81 static void
82 TrDoDefinitionBlock (
83     ACPI_PARSE_OBJECT       *Op);
84 
85 static void
86 TrDoSwitch (
87     ACPI_PARSE_OBJECT       *StartNode);
88 
89 
90 /*******************************************************************************
91  *
92  * FUNCTION:    TrAmlGetNextTempName
93  *
94  * PARAMETERS:  Op              - Current parse op
95  *              TempCount       - Current temporary counter. Was originally
96  *                                per-module; Currently per method, could be
97  *                                expanded to per-scope.
98  *
99  * RETURN:      A pointer to name (allocated here).
100  *
101  * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are
102  *              reserved for use by the ASL compiler. (_T_0 through _T_Z)
103  *
104  ******************************************************************************/
105 
106 static char *
107 TrAmlGetNextTempName (
108     ACPI_PARSE_OBJECT       *Op,
109     UINT8                   *TempCount)
110 {
111     char                    *TempName;
112 
113 
114     if (*TempCount >= (10 + 26))  /* 0-35 valid: 0-9 and A-Z for TempName[3] */
115     {
116         /* Too many temps */
117 
118         AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL);
119         return (NULL);
120     }
121 
122     TempName = UtLocalCalloc (5);
123 
124     if (*TempCount < 10)    /* 0-9 */
125     {
126         TempName[3] = (char) (*TempCount + '0');
127     }
128     else                    /* 10-35: A-Z */
129     {
130         TempName[3] = (char) (*TempCount + ('A' - 10));
131     }
132 
133     (*TempCount)++;
134 
135     /* First three characters are always "_T_" */
136 
137     TempName[0] = '_';
138     TempName[1] = 'T';
139     TempName[2] = '_';
140 
141     return (TempName);
142 }
143 
144 
145 /*******************************************************************************
146  *
147  * FUNCTION:    TrAmlInitLineNumbers
148  *
149  * PARAMETERS:  Op              - Op to be initialized
150  *              Neighbor        - Op used for initialization values
151  *
152  * RETURN:      None
153  *
154  * DESCRIPTION: Initialized the various line numbers for a parse node.
155  *
156  ******************************************************************************/
157 
158 static void
159 TrAmlInitLineNumbers (
160     ACPI_PARSE_OBJECT       *Op,
161     ACPI_PARSE_OBJECT       *Neighbor)
162 {
163 
164     Op->Asl.EndLine           = Neighbor->Asl.EndLine;
165     Op->Asl.EndLogicalLine    = Neighbor->Asl.EndLogicalLine;
166     Op->Asl.LineNumber        = Neighbor->Asl.LineNumber;
167     Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset;
168     Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber;
169 }
170 
171 
172 /*******************************************************************************
173  *
174  * FUNCTION:    TrAmlInitNode
175  *
176  * PARAMETERS:  Op              - Op to be initialized
177  *              ParseOpcode     - Opcode for this node
178  *
179  * RETURN:      None
180  *
181  * DESCRIPTION: Initialize a node with the parse opcode and opcode name.
182  *
183  ******************************************************************************/
184 
185 static void
186 TrAmlInitNode (
187     ACPI_PARSE_OBJECT       *Op,
188     UINT16                  ParseOpcode)
189 {
190 
191     Op->Asl.ParseOpcode = ParseOpcode;
192     UtSetParseOpName (Op);
193 }
194 
195 
196 /*******************************************************************************
197  *
198  * FUNCTION:    TrAmlSetSubtreeParent
199  *
200  * PARAMETERS:  Op              - First node in a list of peer nodes
201  *              Parent          - Parent of the subtree
202  *
203  * RETURN:      None
204  *
205  * DESCRIPTION: Set the parent for all peer nodes in a subtree
206  *
207  ******************************************************************************/
208 
209 static void
210 TrAmlSetSubtreeParent (
211     ACPI_PARSE_OBJECT       *Op,
212     ACPI_PARSE_OBJECT       *Parent)
213 {
214     ACPI_PARSE_OBJECT       *Next;
215 
216 
217     Next = Op;
218     while (Next)
219     {
220         Next->Asl.Parent = Parent;
221         Next = Next->Asl.Next;
222     }
223 }
224 
225 
226 /*******************************************************************************
227  *
228  * FUNCTION:    TrAmlInsertPeer
229  *
230  * PARAMETERS:  Op              - First node in a list of peer nodes
231  *              NewPeer         - Peer node to insert
232  *
233  * RETURN:      None
234  *
235  * DESCRIPTION: Insert a new peer node into a list of peers.
236  *
237  ******************************************************************************/
238 
239 static void
240 TrAmlInsertPeer (
241     ACPI_PARSE_OBJECT       *Op,
242     ACPI_PARSE_OBJECT       *NewPeer)
243 {
244 
245     NewPeer->Asl.Next = Op->Asl.Next;
246     Op->Asl.Next = NewPeer;
247 }
248 
249 
250 /*******************************************************************************
251  *
252  * FUNCTION:    TrAmlTransformWalkBegin
253  *
254  * PARAMETERS:  ASL_WALK_CALLBACK
255  *
256  * RETURN:      None
257  *
258  * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
259  *              operands.
260  *
261  ******************************************************************************/
262 
263 ACPI_STATUS
264 TrAmlTransformWalkBegin (
265     ACPI_PARSE_OBJECT       *Op,
266     UINT32                  Level,
267     void                    *Context)
268 {
269 
270     TrTransformSubtree (Op);
271     return (AE_OK);
272 }
273 
274 
275 /*******************************************************************************
276  *
277  * FUNCTION:    TrAmlTransformWalkEnd
278  *
279  * PARAMETERS:  ASL_WALK_CALLBACK
280  *
281  * RETURN:      None
282  *
283  * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
284  *              operands.
285  *
286  ******************************************************************************/
287 
288 ACPI_STATUS
289 TrAmlTransformWalkEnd (
290     ACPI_PARSE_OBJECT       *Op,
291     UINT32                  Level,
292     void                    *Context)
293 {
294 
295     /* Save possible Externals list in the DefintionBlock Op */
296 
297     if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
298     {
299         Op->Asl.Value.Arg = Gbl_ExternalsListHead;
300         Gbl_ExternalsListHead = NULL;
301     }
302 
303     return (AE_OK);
304 }
305 
306 
307 /*******************************************************************************
308  *
309  * FUNCTION:    TrTransformSubtree
310  *
311  * PARAMETERS:  Op        - The parent parse node
312  *
313  * RETURN:      None
314  *
315  * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more
316  *              complex AML opcodes require processing of the child nodes
317  *              (arguments/operands).
318  *
319  ******************************************************************************/
320 
321 static void
322 TrTransformSubtree (
323     ACPI_PARSE_OBJECT           *Op)
324 {
325 
326     if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE)
327     {
328         return;
329     }
330 
331     switch (Op->Asl.ParseOpcode)
332     {
333     case PARSEOP_DEFINITION_BLOCK:
334 
335         TrDoDefinitionBlock (Op);
336         break;
337 
338     case PARSEOP_SWITCH:
339 
340         TrDoSwitch (Op);
341         break;
342 
343     case PARSEOP_METHOD:
344         /*
345          * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global,
346          * however
347          */
348         Gbl_TempCount = 0;
349         break;
350 
351     case PARSEOP_EXTERNAL:
352 
353         ExDoExternal (Op);
354         break;
355 
356     default:
357 
358         /* Nothing to do here for other opcodes */
359 
360         break;
361     }
362 }
363 
364 
365 /*******************************************************************************
366  *
367  * FUNCTION:    TrDoDefinitionBlock
368  *
369  * PARAMETERS:  Op        - Parse node
370  *
371  * RETURN:      None
372  *
373  * DESCRIPTION: Find the end of the definition block and set a global to this
374  *              node. It is used by the compiler to insert compiler-generated
375  *              names at the root level of the namespace.
376  *
377  ******************************************************************************/
378 
379 static void
380 TrDoDefinitionBlock (
381     ACPI_PARSE_OBJECT       *Op)
382 {
383     ACPI_PARSE_OBJECT       *Next;
384     UINT32                  i;
385 
386 
387     /* Reset external list when starting a definition block */
388 
389     Gbl_ExternalsListHead = NULL;
390 
391     Next = Op->Asl.Child;
392     for (i = 0; i < 5; i++)
393     {
394         Next = Next->Asl.Next;
395         if (i == 0)
396         {
397             /*
398              * This is the table signature. Only the DSDT can be assumed
399              * to be at the root of the namespace;  Therefore, namepath
400              * optimization can only be performed on the DSDT.
401              */
402             if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT))
403             {
404                 Gbl_ReferenceOptimizationFlag = FALSE;
405             }
406         }
407     }
408 
409     Gbl_FirstLevelInsertionNode = Next;
410 }
411 
412 
413 /*******************************************************************************
414  *
415  * FUNCTION:    TrDoSwitch
416  *
417  * PARAMETERS:  StartNode        - Parse node for SWITCH
418  *
419  * RETURN:      None
420  *
421  * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is
422  *              no actual AML opcode for SWITCH -- it must be simulated.
423  *
424  ******************************************************************************/
425 
426 static void
427 TrDoSwitch (
428     ACPI_PARSE_OBJECT       *StartNode)
429 {
430     ACPI_PARSE_OBJECT       *Next;
431     ACPI_PARSE_OBJECT       *CaseOp = NULL;
432     ACPI_PARSE_OBJECT       *CaseBlock = NULL;
433     ACPI_PARSE_OBJECT       *DefaultOp = NULL;
434     ACPI_PARSE_OBJECT       *CurrentParentNode;
435     ACPI_PARSE_OBJECT       *Conditional = NULL;
436     ACPI_PARSE_OBJECT       *Predicate;
437     ACPI_PARSE_OBJECT       *Peer;
438     ACPI_PARSE_OBJECT       *NewOp;
439     ACPI_PARSE_OBJECT       *NewOp2;
440     ACPI_PARSE_OBJECT       *MethodOp;
441     ACPI_PARSE_OBJECT       *StoreOp;
442     ACPI_PARSE_OBJECT       *BreakOp;
443     ACPI_PARSE_OBJECT       *BufferOp;
444     char                    *PredicateValueName;
445     UINT16                  Index;
446     UINT32                  Btype;
447 
448 
449     /* Start node is the Switch() node */
450 
451     CurrentParentNode  = StartNode;
452 
453     /* Create a new temp name of the form _T_x */
454 
455     PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount);
456     if (!PredicateValueName)
457     {
458         return;
459     }
460 
461     /* First child is the Switch() predicate */
462 
463     Next = StartNode->Asl.Child;
464 
465     /*
466      * Examine the return type of the Switch Value -
467      * must be Integer/Buffer/String
468      */
469     Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE);
470     Btype = AslKeywordMapping[Index].AcpiBtype;
471     if ((Btype != ACPI_BTYPE_INTEGER) &&
472         (Btype != ACPI_BTYPE_STRING)  &&
473         (Btype != ACPI_BTYPE_BUFFER))
474     {
475         AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL);
476         Btype = ACPI_BTYPE_INTEGER;
477     }
478 
479     /* CASE statements start at next child */
480 
481     Peer = Next->Asl.Next;
482     while (Peer)
483     {
484         Next = Peer;
485         Peer = Next->Asl.Next;
486 
487         if (Next->Asl.ParseOpcode == PARSEOP_CASE)
488         {
489             if (CaseOp)
490             {
491                 /* Add an ELSE to complete the previous CASE */
492 
493                 NewOp = TrCreateLeafNode (PARSEOP_ELSE);
494                 NewOp->Asl.Parent = Conditional->Asl.Parent;
495                 TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent);
496 
497                 /* Link ELSE node as a peer to the previous IF */
498 
499                 TrAmlInsertPeer (Conditional, NewOp);
500                 CurrentParentNode = NewOp;
501             }
502 
503             CaseOp = Next;
504             Conditional = CaseOp;
505             CaseBlock = CaseOp->Asl.Child->Asl.Next;
506             Conditional->Asl.Child->Asl.Next = NULL;
507             Predicate = CaseOp->Asl.Child;
508 
509             if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
510                 (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
511             {
512                 /*
513                  * Convert the package declaration to this form:
514                  *
515                  * If (LNotEqual (Match (Package(<size>){<data>},
516                  *                       MEQ, _T_x, MTR, Zero, Zero), Ones))
517                  */
518                 NewOp2              = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ);
519                 Predicate->Asl.Next = NewOp2;
520                 TrAmlInitLineNumbers (NewOp2, Conditional);
521 
522                 NewOp               = NewOp2;
523                 NewOp2              = TrCreateValuedLeafNode (PARSEOP_NAMESTRING,
524                                         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
525                 NewOp->Asl.Next     = NewOp2;
526                 TrAmlInitLineNumbers (NewOp2, Predicate);
527 
528                 NewOp               = NewOp2;
529                 NewOp2              = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR);
530                 NewOp->Asl.Next     = NewOp2;
531                 TrAmlInitLineNumbers (NewOp2, Predicate);
532 
533                 NewOp               = NewOp2;
534                 NewOp2              = TrCreateLeafNode (PARSEOP_ZERO);
535                 NewOp->Asl.Next     = NewOp2;
536                 TrAmlInitLineNumbers (NewOp2, Predicate);
537 
538                 NewOp               = NewOp2;
539                 NewOp2              = TrCreateLeafNode (PARSEOP_ZERO);
540                 NewOp->Asl.Next     = NewOp2;
541                 TrAmlInitLineNumbers (NewOp2, Predicate);
542 
543                 NewOp2              = TrCreateLeafNode (PARSEOP_MATCH);
544                 NewOp2->Asl.Child   = Predicate;  /* PARSEOP_PACKAGE */
545                 TrAmlInitLineNumbers (NewOp2, Conditional);
546                 TrAmlSetSubtreeParent (Predicate, NewOp2);
547 
548                 NewOp               = NewOp2;
549                 NewOp2              = TrCreateLeafNode (PARSEOP_ONES);
550                 NewOp->Asl.Next     = NewOp2;
551                 TrAmlInitLineNumbers (NewOp2, Conditional);
552 
553                 NewOp2              = TrCreateLeafNode (PARSEOP_LEQUAL);
554                 NewOp2->Asl.Child   = NewOp;
555                 NewOp->Asl.Parent   = NewOp2;
556                 TrAmlInitLineNumbers (NewOp2, Conditional);
557                 TrAmlSetSubtreeParent (NewOp, NewOp2);
558 
559                 NewOp               = NewOp2;
560                 NewOp2              = TrCreateLeafNode (PARSEOP_LNOT);
561                 NewOp2->Asl.Child   = NewOp;
562                 NewOp2->Asl.Parent  = Conditional;
563                 NewOp->Asl.Parent   = NewOp2;
564                 TrAmlInitLineNumbers (NewOp2, Conditional);
565 
566                 Conditional->Asl.Child = NewOp2;
567                 NewOp2->Asl.Next = CaseBlock;
568             }
569             else
570             {
571                 /*
572                  * Integer and Buffer case.
573                  *
574                  * Change CaseOp() to:  If (LEqual (SwitchValue, CaseValue)) {...}
575                  * Note: SwitchValue is first to allow the CaseValue to be implicitly
576                  * converted to the type of SwitchValue if necessary.
577                  *
578                  * CaseOp->Child is the case value
579                  * CaseOp->Child->Peer is the beginning of the case block
580                  */
581                 NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING,
582                     (UINT64) ACPI_TO_INTEGER (PredicateValueName));
583                 NewOp->Asl.Next = Predicate;
584                 TrAmlInitLineNumbers (NewOp, Predicate);
585 
586                 NewOp2              = TrCreateLeafNode (PARSEOP_LEQUAL);
587                 NewOp2->Asl.Parent  = Conditional;
588                 NewOp2->Asl.Child   = NewOp;
589                 TrAmlInitLineNumbers (NewOp2, Conditional);
590 
591                 TrAmlSetSubtreeParent (NewOp, NewOp2);
592 
593                 Predicate           = NewOp2;
594                 Predicate->Asl.Next = CaseBlock;
595 
596                 TrAmlSetSubtreeParent (Predicate, Conditional);
597                 Conditional->Asl.Child = Predicate;
598             }
599 
600             /* Reinitialize the CASE node to an IF node */
601 
602             TrAmlInitNode (Conditional, PARSEOP_IF);
603 
604             /*
605              * The first CASE(IF) is not nested under an ELSE.
606              * All other CASEs are children of a parent ELSE.
607              */
608             if (CurrentParentNode == StartNode)
609             {
610                 Conditional->Asl.Next = NULL;
611             }
612             else
613             {
614                 /*
615                  * The IF is a child of previous IF/ELSE. It
616                  * is therefore without peer.
617                  */
618                 CurrentParentNode->Asl.Child = Conditional;
619                 Conditional->Asl.Parent      = CurrentParentNode;
620                 Conditional->Asl.Next        = NULL;
621             }
622         }
623         else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT)
624         {
625             if (DefaultOp)
626             {
627                 /*
628                  * More than one Default
629                  * (Parser does not catch this, must check here)
630                  */
631                 AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL);
632             }
633             else
634             {
635                 /* Save the DEFAULT node for later, after CASEs */
636 
637                 DefaultOp = Next;
638             }
639         }
640         else
641         {
642             /* Unknown peer opcode */
643 
644             AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n",
645                 Next->Asl.ParseOpName, Next->Asl.ParseOpcode);
646         }
647     }
648 
649     /* Add the default case at the end of the if/else construct */
650 
651     if (DefaultOp)
652     {
653         /* If no CASE statements, this is an error - see below */
654 
655         if (CaseOp)
656         {
657             /* Convert the DEFAULT node to an ELSE */
658 
659             TrAmlInitNode (DefaultOp, PARSEOP_ELSE);
660             DefaultOp->Asl.Parent = Conditional->Asl.Parent;
661 
662             /* Link ELSE node as a peer to the previous IF */
663 
664             TrAmlInsertPeer (Conditional, DefaultOp);
665         }
666     }
667 
668     if (!CaseOp)
669     {
670         AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL);
671     }
672 
673 
674     /*
675      * Create a Name(_T_x, ...) statement. This statement must appear at the
676      * method level, in case a loop surrounds the switch statement and could
677      * cause the name to be created twice (error).
678      */
679 
680     /* Create the Name node */
681 
682     Predicate = StartNode->Asl.Child;
683     NewOp = TrCreateLeafNode (PARSEOP_NAME);
684     TrAmlInitLineNumbers (NewOp, StartNode);
685 
686     /* Find the parent method */
687 
688     Next = StartNode;
689     while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) &&
690            (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK))
691     {
692         Next = Next->Asl.Parent;
693     }
694     MethodOp = Next;
695 
696     NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED;
697     NewOp->Asl.Parent = Next;
698 
699     /* Insert name after the method name and arguments */
700 
701     Next = Next->Asl.Child; /* Name */
702     Next = Next->Asl.Next;  /* NumArgs */
703     Next = Next->Asl.Next;  /* SerializeRule */
704 
705     /*
706      * If method is not Serialized, we must make is so, because of the way
707      * that Switch() must be implemented -- we cannot allow multiple threads
708      * to execute this method concurrently since we need to create local
709      * temporary name(s).
710      */
711     if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL)
712     {
713         AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp,
714             "Due to use of Switch operator");
715         Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL;
716     }
717 
718     Next = Next->Asl.Next;  /* SyncLevel */
719     Next = Next->Asl.Next;  /* ReturnType */
720     Next = Next->Asl.Next;  /* ParameterTypes */
721 
722     TrAmlInsertPeer (Next, NewOp);
723     TrAmlInitLineNumbers (NewOp, Next);
724 
725     /* Create the NameSeg child for the Name node */
726 
727     NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG,
728         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
729     TrAmlInitLineNumbers (NewOp2, NewOp);
730     NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION;
731     NewOp->Asl.Child  = NewOp2;
732 
733     /* Create the initial value for the Name. Btype was already validated above */
734 
735     switch (Btype)
736     {
737     case ACPI_BTYPE_INTEGER:
738 
739         NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO,
740             (UINT64) 0);
741         TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
742         break;
743 
744     case ACPI_BTYPE_STRING:
745 
746         NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL,
747             (UINT64) ACPI_TO_INTEGER (""));
748         TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
749         break;
750 
751     case ACPI_BTYPE_BUFFER:
752 
753         (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER,
754             (UINT64) 0));
755         Next = NewOp2->Asl.Next;
756         TrAmlInitLineNumbers (Next, NewOp2);
757         (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO,
758             (UINT64) 1));
759         TrAmlInitLineNumbers (Next->Asl.Child, Next);
760 
761         BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0);
762         TrAmlInitLineNumbers (BufferOp, Next->Asl.Child);
763         (void) TrLinkPeerNode (Next->Asl.Child, BufferOp);
764 
765         TrAmlSetSubtreeParent (Next->Asl.Child, Next);
766         break;
767 
768     default:
769 
770         break;
771     }
772 
773     TrAmlSetSubtreeParent (NewOp2, NewOp);
774 
775     /*
776      * Transform the Switch() into a While(One)-Break node.
777      * And create a Store() node which will be used to save the
778      * Switch() value. The store is of the form: Store (Value, _T_x)
779      * where _T_x is the temp variable.
780      */
781     TrAmlInitNode (StartNode, PARSEOP_WHILE);
782     NewOp = TrCreateLeafNode (PARSEOP_ONE);
783     TrAmlInitLineNumbers (NewOp, StartNode);
784     NewOp->Asl.Next = Predicate->Asl.Next;
785     NewOp->Asl.Parent = StartNode;
786     StartNode->Asl.Child = NewOp;
787 
788     /* Create a Store() node */
789 
790     StoreOp = TrCreateLeafNode (PARSEOP_STORE);
791     TrAmlInitLineNumbers (StoreOp, NewOp);
792     StoreOp->Asl.Parent = StartNode;
793     TrAmlInsertPeer (NewOp, StoreOp);
794 
795     /* Complete the Store subtree */
796 
797     StoreOp->Asl.Child = Predicate;
798     Predicate->Asl.Parent = StoreOp;
799 
800     NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG,
801         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
802     TrAmlInitLineNumbers (NewOp, StoreOp);
803     NewOp->Asl.Parent    = StoreOp;
804     Predicate->Asl.Next  = NewOp;
805 
806     /* Create a Break() node and insert it into the end of While() */
807 
808     Conditional = StartNode->Asl.Child;
809     while (Conditional->Asl.Next)
810     {
811         Conditional = Conditional->Asl.Next;
812     }
813 
814     BreakOp = TrCreateLeafNode (PARSEOP_BREAK);
815     TrAmlInitLineNumbers (BreakOp, NewOp);
816     BreakOp->Asl.Parent = StartNode;
817     TrAmlInsertPeer (Conditional, BreakOp);
818 }
819