xref: /freebsd/sys/contrib/dev/acpica/compiler/asltransform.c (revision 3fc36ee018bb836bd1796067cf4ef8683f166ebc)
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 <contrib/dev/acpica/compiler/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         if (Gbl_DoExternals == TRUE)
354         {
355             ExDoExternal (Op);
356         }
357 
358         break;
359 
360     default:
361 
362         /* Nothing to do here for other opcodes */
363 
364         break;
365     }
366 }
367 
368 
369 /*******************************************************************************
370  *
371  * FUNCTION:    TrDoDefinitionBlock
372  *
373  * PARAMETERS:  Op        - Parse node
374  *
375  * RETURN:      None
376  *
377  * DESCRIPTION: Find the end of the definition block and set a global to this
378  *              node. It is used by the compiler to insert compiler-generated
379  *              names at the root level of the namespace.
380  *
381  ******************************************************************************/
382 
383 static void
384 TrDoDefinitionBlock (
385     ACPI_PARSE_OBJECT       *Op)
386 {
387     ACPI_PARSE_OBJECT       *Next;
388     UINT32                  i;
389 
390 
391     /* Reset external list when starting a definition block */
392 
393     Gbl_ExternalsListHead = NULL;
394 
395     Next = Op->Asl.Child;
396     for (i = 0; i < 5; i++)
397     {
398         Next = Next->Asl.Next;
399         if (i == 0)
400         {
401             /*
402              * This is the table signature. Only the DSDT can be assumed
403              * to be at the root of the namespace;  Therefore, namepath
404              * optimization can only be performed on the DSDT.
405              */
406             if (!ACPI_COMPARE_NAME (Next->Asl.Value.String, ACPI_SIG_DSDT))
407             {
408                 Gbl_ReferenceOptimizationFlag = FALSE;
409             }
410         }
411     }
412 
413     Gbl_FirstLevelInsertionNode = Next;
414 }
415 
416 
417 /*******************************************************************************
418  *
419  * FUNCTION:    TrDoSwitch
420  *
421  * PARAMETERS:  StartNode        - Parse node for SWITCH
422  *
423  * RETURN:      None
424  *
425  * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is
426  *              no actual AML opcode for SWITCH -- it must be simulated.
427  *
428  ******************************************************************************/
429 
430 static void
431 TrDoSwitch (
432     ACPI_PARSE_OBJECT       *StartNode)
433 {
434     ACPI_PARSE_OBJECT       *Next;
435     ACPI_PARSE_OBJECT       *CaseOp = NULL;
436     ACPI_PARSE_OBJECT       *CaseBlock = NULL;
437     ACPI_PARSE_OBJECT       *DefaultOp = NULL;
438     ACPI_PARSE_OBJECT       *CurrentParentNode;
439     ACPI_PARSE_OBJECT       *Conditional = NULL;
440     ACPI_PARSE_OBJECT       *Predicate;
441     ACPI_PARSE_OBJECT       *Peer;
442     ACPI_PARSE_OBJECT       *NewOp;
443     ACPI_PARSE_OBJECT       *NewOp2;
444     ACPI_PARSE_OBJECT       *MethodOp;
445     ACPI_PARSE_OBJECT       *StoreOp;
446     ACPI_PARSE_OBJECT       *BreakOp;
447     ACPI_PARSE_OBJECT       *BufferOp;
448     char                    *PredicateValueName;
449     UINT16                  Index;
450     UINT32                  Btype;
451 
452 
453     /* Start node is the Switch() node */
454 
455     CurrentParentNode  = StartNode;
456 
457     /* Create a new temp name of the form _T_x */
458 
459     PredicateValueName = TrAmlGetNextTempName (StartNode, &Gbl_TempCount);
460     if (!PredicateValueName)
461     {
462         return;
463     }
464 
465     /* First child is the Switch() predicate */
466 
467     Next = StartNode->Asl.Child;
468 
469     /*
470      * Examine the return type of the Switch Value -
471      * must be Integer/Buffer/String
472      */
473     Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE);
474     Btype = AslKeywordMapping[Index].AcpiBtype;
475     if ((Btype != ACPI_BTYPE_INTEGER) &&
476         (Btype != ACPI_BTYPE_STRING)  &&
477         (Btype != ACPI_BTYPE_BUFFER))
478     {
479         AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL);
480         Btype = ACPI_BTYPE_INTEGER;
481     }
482 
483     /* CASE statements start at next child */
484 
485     Peer = Next->Asl.Next;
486     while (Peer)
487     {
488         Next = Peer;
489         Peer = Next->Asl.Next;
490 
491         if (Next->Asl.ParseOpcode == PARSEOP_CASE)
492         {
493             if (CaseOp)
494             {
495                 /* Add an ELSE to complete the previous CASE */
496 
497                 NewOp = TrCreateLeafNode (PARSEOP_ELSE);
498                 NewOp->Asl.Parent = Conditional->Asl.Parent;
499                 TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent);
500 
501                 /* Link ELSE node as a peer to the previous IF */
502 
503                 TrAmlInsertPeer (Conditional, NewOp);
504                 CurrentParentNode = NewOp;
505             }
506 
507             CaseOp = Next;
508             Conditional = CaseOp;
509             CaseBlock = CaseOp->Asl.Child->Asl.Next;
510             Conditional->Asl.Child->Asl.Next = NULL;
511             Predicate = CaseOp->Asl.Child;
512 
513             if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
514                 (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
515             {
516                 /*
517                  * Convert the package declaration to this form:
518                  *
519                  * If (LNotEqual (Match (Package(<size>){<data>},
520                  *                       MEQ, _T_x, MTR, Zero, Zero), Ones))
521                  */
522                 NewOp2              = TrCreateLeafNode (PARSEOP_MATCHTYPE_MEQ);
523                 Predicate->Asl.Next = NewOp2;
524                 TrAmlInitLineNumbers (NewOp2, Conditional);
525 
526                 NewOp               = NewOp2;
527                 NewOp2              = TrCreateValuedLeafNode (PARSEOP_NAMESTRING,
528                                         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
529                 NewOp->Asl.Next     = NewOp2;
530                 TrAmlInitLineNumbers (NewOp2, Predicate);
531 
532                 NewOp               = NewOp2;
533                 NewOp2              = TrCreateLeafNode (PARSEOP_MATCHTYPE_MTR);
534                 NewOp->Asl.Next     = NewOp2;
535                 TrAmlInitLineNumbers (NewOp2, Predicate);
536 
537                 NewOp               = NewOp2;
538                 NewOp2              = TrCreateLeafNode (PARSEOP_ZERO);
539                 NewOp->Asl.Next     = NewOp2;
540                 TrAmlInitLineNumbers (NewOp2, Predicate);
541 
542                 NewOp               = NewOp2;
543                 NewOp2              = TrCreateLeafNode (PARSEOP_ZERO);
544                 NewOp->Asl.Next     = NewOp2;
545                 TrAmlInitLineNumbers (NewOp2, Predicate);
546 
547                 NewOp2              = TrCreateLeafNode (PARSEOP_MATCH);
548                 NewOp2->Asl.Child   = Predicate;  /* PARSEOP_PACKAGE */
549                 TrAmlInitLineNumbers (NewOp2, Conditional);
550                 TrAmlSetSubtreeParent (Predicate, NewOp2);
551 
552                 NewOp               = NewOp2;
553                 NewOp2              = TrCreateLeafNode (PARSEOP_ONES);
554                 NewOp->Asl.Next     = NewOp2;
555                 TrAmlInitLineNumbers (NewOp2, Conditional);
556 
557                 NewOp2              = TrCreateLeafNode (PARSEOP_LEQUAL);
558                 NewOp2->Asl.Child   = NewOp;
559                 NewOp->Asl.Parent   = NewOp2;
560                 TrAmlInitLineNumbers (NewOp2, Conditional);
561                 TrAmlSetSubtreeParent (NewOp, NewOp2);
562 
563                 NewOp               = NewOp2;
564                 NewOp2              = TrCreateLeafNode (PARSEOP_LNOT);
565                 NewOp2->Asl.Child   = NewOp;
566                 NewOp2->Asl.Parent  = Conditional;
567                 NewOp->Asl.Parent   = NewOp2;
568                 TrAmlInitLineNumbers (NewOp2, Conditional);
569 
570                 Conditional->Asl.Child = NewOp2;
571                 NewOp2->Asl.Next = CaseBlock;
572             }
573             else
574             {
575                 /*
576                  * Integer and Buffer case.
577                  *
578                  * Change CaseOp() to:  If (LEqual (SwitchValue, CaseValue)) {...}
579                  * Note: SwitchValue is first to allow the CaseValue to be implicitly
580                  * converted to the type of SwitchValue if necessary.
581                  *
582                  * CaseOp->Child is the case value
583                  * CaseOp->Child->Peer is the beginning of the case block
584                  */
585                 NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESTRING,
586                     (UINT64) ACPI_TO_INTEGER (PredicateValueName));
587                 NewOp->Asl.Next = Predicate;
588                 TrAmlInitLineNumbers (NewOp, Predicate);
589 
590                 NewOp2              = TrCreateLeafNode (PARSEOP_LEQUAL);
591                 NewOp2->Asl.Parent  = Conditional;
592                 NewOp2->Asl.Child   = NewOp;
593                 TrAmlInitLineNumbers (NewOp2, Conditional);
594 
595                 TrAmlSetSubtreeParent (NewOp, NewOp2);
596 
597                 Predicate           = NewOp2;
598                 Predicate->Asl.Next = CaseBlock;
599 
600                 TrAmlSetSubtreeParent (Predicate, Conditional);
601                 Conditional->Asl.Child = Predicate;
602             }
603 
604             /* Reinitialize the CASE node to an IF node */
605 
606             TrAmlInitNode (Conditional, PARSEOP_IF);
607 
608             /*
609              * The first CASE(IF) is not nested under an ELSE.
610              * All other CASEs are children of a parent ELSE.
611              */
612             if (CurrentParentNode == StartNode)
613             {
614                 Conditional->Asl.Next = NULL;
615             }
616             else
617             {
618                 /*
619                  * The IF is a child of previous IF/ELSE. It
620                  * is therefore without peer.
621                  */
622                 CurrentParentNode->Asl.Child = Conditional;
623                 Conditional->Asl.Parent      = CurrentParentNode;
624                 Conditional->Asl.Next        = NULL;
625             }
626         }
627         else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT)
628         {
629             if (DefaultOp)
630             {
631                 /*
632                  * More than one Default
633                  * (Parser does not catch this, must check here)
634                  */
635                 AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL);
636             }
637             else
638             {
639                 /* Save the DEFAULT node for later, after CASEs */
640 
641                 DefaultOp = Next;
642             }
643         }
644         else
645         {
646             /* Unknown peer opcode */
647 
648             AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n",
649                 Next->Asl.ParseOpName, Next->Asl.ParseOpcode);
650         }
651     }
652 
653     /* Add the default case at the end of the if/else construct */
654 
655     if (DefaultOp)
656     {
657         /* If no CASE statements, this is an error - see below */
658 
659         if (CaseOp)
660         {
661             /* Convert the DEFAULT node to an ELSE */
662 
663             TrAmlInitNode (DefaultOp, PARSEOP_ELSE);
664             DefaultOp->Asl.Parent = Conditional->Asl.Parent;
665 
666             /* Link ELSE node as a peer to the previous IF */
667 
668             TrAmlInsertPeer (Conditional, DefaultOp);
669         }
670     }
671 
672     if (!CaseOp)
673     {
674         AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL);
675     }
676 
677 
678     /*
679      * Create a Name(_T_x, ...) statement. This statement must appear at the
680      * method level, in case a loop surrounds the switch statement and could
681      * cause the name to be created twice (error).
682      */
683 
684     /* Create the Name node */
685 
686     Predicate = StartNode->Asl.Child;
687     NewOp = TrCreateLeafNode (PARSEOP_NAME);
688     TrAmlInitLineNumbers (NewOp, StartNode);
689 
690     /* Find the parent method */
691 
692     Next = StartNode;
693     while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) &&
694            (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK))
695     {
696         Next = Next->Asl.Parent;
697     }
698     MethodOp = Next;
699 
700     NewOp->Asl.CompileFlags |= NODE_COMPILER_EMITTED;
701     NewOp->Asl.Parent = Next;
702 
703     /* Insert name after the method name and arguments */
704 
705     Next = Next->Asl.Child; /* Name */
706     Next = Next->Asl.Next;  /* NumArgs */
707     Next = Next->Asl.Next;  /* SerializeRule */
708 
709     /*
710      * If method is not Serialized, we must make is so, because of the way
711      * that Switch() must be implemented -- we cannot allow multiple threads
712      * to execute this method concurrently since we need to create local
713      * temporary name(s).
714      */
715     if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL)
716     {
717         AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp,
718             "Due to use of Switch operator");
719         Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL;
720     }
721 
722     Next = Next->Asl.Next;  /* SyncLevel */
723     Next = Next->Asl.Next;  /* ReturnType */
724     Next = Next->Asl.Next;  /* ParameterTypes */
725 
726     TrAmlInsertPeer (Next, NewOp);
727     TrAmlInitLineNumbers (NewOp, Next);
728 
729     /* Create the NameSeg child for the Name node */
730 
731     NewOp2 = TrCreateValuedLeafNode (PARSEOP_NAMESEG,
732         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
733     TrAmlInitLineNumbers (NewOp2, NewOp);
734     NewOp2->Asl.CompileFlags |= NODE_IS_NAME_DECLARATION;
735     NewOp->Asl.Child  = NewOp2;
736 
737     /* Create the initial value for the Name. Btype was already validated above */
738 
739     switch (Btype)
740     {
741     case ACPI_BTYPE_INTEGER:
742 
743         NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_ZERO,
744             (UINT64) 0);
745         TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
746         break;
747 
748     case ACPI_BTYPE_STRING:
749 
750         NewOp2->Asl.Next = TrCreateValuedLeafNode (PARSEOP_STRING_LITERAL,
751             (UINT64) ACPI_TO_INTEGER (""));
752         TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
753         break;
754 
755     case ACPI_BTYPE_BUFFER:
756 
757         (void) TrLinkPeerNode (NewOp2, TrCreateValuedLeafNode (PARSEOP_BUFFER,
758             (UINT64) 0));
759         Next = NewOp2->Asl.Next;
760         TrAmlInitLineNumbers (Next, NewOp2);
761         (void) TrLinkChildren (Next, 1, TrCreateValuedLeafNode (PARSEOP_ZERO,
762             (UINT64) 1));
763         TrAmlInitLineNumbers (Next->Asl.Child, Next);
764 
765         BufferOp = TrCreateValuedLeafNode (PARSEOP_DEFAULT_ARG, (UINT64) 0);
766         TrAmlInitLineNumbers (BufferOp, Next->Asl.Child);
767         (void) TrLinkPeerNode (Next->Asl.Child, BufferOp);
768 
769         TrAmlSetSubtreeParent (Next->Asl.Child, Next);
770         break;
771 
772     default:
773 
774         break;
775     }
776 
777     TrAmlSetSubtreeParent (NewOp2, NewOp);
778 
779     /*
780      * Transform the Switch() into a While(One)-Break node.
781      * And create a Store() node which will be used to save the
782      * Switch() value. The store is of the form: Store (Value, _T_x)
783      * where _T_x is the temp variable.
784      */
785     TrAmlInitNode (StartNode, PARSEOP_WHILE);
786     NewOp = TrCreateLeafNode (PARSEOP_ONE);
787     TrAmlInitLineNumbers (NewOp, StartNode);
788     NewOp->Asl.Next = Predicate->Asl.Next;
789     NewOp->Asl.Parent = StartNode;
790     StartNode->Asl.Child = NewOp;
791 
792     /* Create a Store() node */
793 
794     StoreOp = TrCreateLeafNode (PARSEOP_STORE);
795     TrAmlInitLineNumbers (StoreOp, NewOp);
796     StoreOp->Asl.Parent = StartNode;
797     TrAmlInsertPeer (NewOp, StoreOp);
798 
799     /* Complete the Store subtree */
800 
801     StoreOp->Asl.Child = Predicate;
802     Predicate->Asl.Parent = StoreOp;
803 
804     NewOp = TrCreateValuedLeafNode (PARSEOP_NAMESEG,
805         (UINT64) ACPI_TO_INTEGER (PredicateValueName));
806     TrAmlInitLineNumbers (NewOp, StoreOp);
807     NewOp->Asl.Parent    = StoreOp;
808     Predicate->Asl.Next  = NewOp;
809 
810     /* Create a Break() node and insert it into the end of While() */
811 
812     Conditional = StartNode->Asl.Child;
813     while (Conditional->Asl.Next)
814     {
815         Conditional = Conditional->Asl.Next;
816     }
817 
818     BreakOp = TrCreateLeafNode (PARSEOP_BREAK);
819     TrAmlInitLineNumbers (BreakOp, NewOp);
820     BreakOp->Asl.Parent = StartNode;
821     TrAmlInsertPeer (Conditional, BreakOp);
822 }
823