1 /*******************************************************************************
2  *
3  * Module Name: dmopcode - AML disassembler, specific AML opcodes
4  *
5  ******************************************************************************/
6 
7 /******************************************************************************
8  *
9  * 1. Copyright Notice
10  *
11  * Some or all of this work - Copyright (c) 1999 - 2017, Intel Corp.
12  * All rights reserved.
13  *
14  * 2. License
15  *
16  * 2.1. This is your license from Intel Corp. under its intellectual property
17  * rights. You may have additional license terms from the party that provided
18  * you this software, covering your right to use that party's intellectual
19  * property rights.
20  *
21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22  * copy of the source code appearing in this file ("Covered Code") an
23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24  * base code distributed originally by Intel ("Original Intel Code") to copy,
25  * make derivatives, distribute, use and display any portion of the Covered
26  * Code in any form, with the right to sublicense such rights; and
27  *
28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29  * license (with the right to sublicense), under only those claims of Intel
30  * patents that are infringed by the Original Intel Code, to make, use, sell,
31  * offer to sell, and import the Covered Code and derivative works thereof
32  * solely to the minimum extent necessary to exercise the above copyright
33  * license, and in no event shall the patent license extend to any additions
34  * to or modifications of the Original Intel Code. No other license or right
35  * is granted directly or by implication, estoppel or otherwise;
36  *
37  * The above copyright and patent license is granted only if the following
38  * conditions are met:
39  *
40  * 3. Conditions
41  *
42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43  * Redistribution of source code of any substantial portion of the Covered
44  * Code or modification with rights to further distribute source must include
45  * the above Copyright Notice, the above License, this list of Conditions,
46  * and the following Disclaimer and Export Compliance provision. In addition,
47  * Licensee must cause all Covered Code to which Licensee contributes to
48  * contain a file documenting the changes Licensee made to create that Covered
49  * Code and the date of any change. Licensee must include in that file the
50  * documentation of any changes made by any predecessor Licensee. Licensee
51  * must include a prominent statement that the modification is derived,
52  * directly or indirectly, from Original Intel Code.
53  *
54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55  * Redistribution of source code of any substantial portion of the Covered
56  * Code or modification without rights to further distribute source must
57  * include the following Disclaimer and Export Compliance provision in the
58  * documentation and/or other materials provided with distribution. In
59  * addition, Licensee may not authorize further sublicense of source of any
60  * portion of the Covered Code, and must include terms to the effect that the
61  * license from Licensee to its licensee is limited to the intellectual
62  * property embodied in the software Licensee provides to its licensee, and
63  * not to intellectual property embodied in modifications its licensee may
64  * make.
65  *
66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
67  * substantial portion of the Covered Code or modification must reproduce the
68  * above Copyright Notice, and the following Disclaimer and Export Compliance
69  * provision in the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3.4. Intel retains all right, title, and interest in and to the Original
73  * Intel Code.
74  *
75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76  * Intel shall be used in advertising or otherwise to promote the sale, use or
77  * other dealings in products derived from or relating to the Covered Code
78  * without prior written authorization from Intel.
79  *
80  * 4. Disclaimer and Export Compliance
81  *
82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88  * PARTICULAR PURPOSE.
89  *
90  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97  * LIMITED REMEDY.
98  *
99  * 4.3. Licensee shall not export, either directly or indirectly, any of this
100  * software or system incorporating such software without first obtaining any
101  * required license or other approval from the U. S. Department of Commerce or
102  * any other agency or department of the United States Government. In the
103  * event Licensee exports any such software from the United States or
104  * re-exports any such software from a foreign destination, Licensee shall
105  * ensure that the distribution and export/re-export of the software is in
106  * compliance with all laws, regulations, orders, or other restrictions of the
107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108  * any of its subsidiaries will export/re-export any technical data, process,
109  * software, or service, directly or indirectly, to any country for which the
110  * United States government or any agency thereof requires an export license,
111  * other governmental approval, or letter of assurance, without first obtaining
112  * such license, approval or letter.
113  *
114  *****************************************************************************
115  *
116  * Alternatively, you may choose to be licensed under the terms of the
117  * following license:
118  *
119  * Redistribution and use in source and binary forms, with or without
120  * modification, are permitted provided that the following conditions
121  * are met:
122  * 1. Redistributions of source code must retain the above copyright
123  *    notice, this list of conditions, and the following disclaimer,
124  *    without modification.
125  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
126  *    substantially similar to the "NO WARRANTY" disclaimer below
127  *    ("Disclaimer") and any redistribution must be conditioned upon
128  *    including a substantially similar Disclaimer requirement for further
129  *    binary redistribution.
130  * 3. Neither the names of the above-listed copyright holders nor the names
131  *    of any contributors may be used to endorse or promote products derived
132  *    from this software without specific prior written permission.
133  *
134  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
135  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
136  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
137  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
138  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
139  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
140  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
141  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
142  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
143  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
144  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
145  *
146  * Alternatively, you may choose to be licensed under the terms of the
147  * GNU General Public License ("GPL") version 2 as published by the Free
148  * Software Foundation.
149  *
150  *****************************************************************************/
151 
152 #include "acpi.h"
153 #include "accommon.h"
154 #include "acparser.h"
155 #include "amlcode.h"
156 #include "acinterp.h"
157 #include "acnamesp.h"
158 #include "acdebug.h"
159 #include "acconvert.h"
160 
161 #ifdef ACPI_DISASSEMBLER
162 
163 #define _COMPONENT          ACPI_CA_DEBUGGER
164         ACPI_MODULE_NAME    ("dmopcode")
165 
166 
167 /* Local prototypes */
168 
169 static void
170 AcpiDmMatchKeyword (
171     ACPI_PARSE_OBJECT       *Op);
172 
173 static void
174 AcpiDmConvertToElseIf (
175     ACPI_PARSE_OBJECT       *Op);
176 
177 static void
178 AcpiDmPromoteSubtree (
179     ACPI_PARSE_OBJECT       *StartOp);
180 
181 static BOOLEAN
182 AcpiDmIsSwitchBlock (
183     ACPI_PARSE_OBJECT       *Op,
184     char                    *Temp);
185 
186 static BOOLEAN
187 AcpiDmIsCaseBlock (
188     ACPI_PARSE_OBJECT       *Op);
189 
190 /*******************************************************************************
191  *
192  * FUNCTION:    AcpiDmDisplayTargetPathname
193  *
194  * PARAMETERS:  Op              - Parse object
195  *
196  * RETURN:      None
197  *
198  * DESCRIPTION: For AML opcodes that have a target operand, display the full
199  *              pathname for the target, in a comment field. Handles Return()
200  *              statements also.
201  *
202  ******************************************************************************/
203 
204 void
205 AcpiDmDisplayTargetPathname (
206     ACPI_PARSE_OBJECT       *Op)
207 {
208     ACPI_PARSE_OBJECT       *NextOp;
209     ACPI_PARSE_OBJECT       *PrevOp = NULL;
210     char                    *Pathname;
211     const ACPI_OPCODE_INFO  *OpInfo;
212 
213 
214     if (Op->Common.AmlOpcode == AML_RETURN_OP)
215     {
216         PrevOp = Op->Asl.Value.Arg;
217     }
218     else
219     {
220         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
221         if (!(OpInfo->Flags & AML_HAS_TARGET))
222         {
223             return;
224         }
225 
226         /* Target is the last Op in the arg list */
227 
228         NextOp = Op->Asl.Value.Arg;
229         while (NextOp)
230         {
231             PrevOp = NextOp;
232             NextOp = PrevOp->Asl.Next;
233         }
234     }
235 
236     if (!PrevOp)
237     {
238         return;
239     }
240 
241     /* We must have a namepath AML opcode */
242 
243     if (PrevOp->Asl.AmlOpcode != AML_INT_NAMEPATH_OP)
244     {
245         return;
246     }
247 
248     /* A null string is the "no target specified" case */
249 
250     if (!PrevOp->Asl.Value.String)
251     {
252         return;
253     }
254 
255     /* No node means "unresolved external reference" */
256 
257     if (!PrevOp->Asl.Node)
258     {
259         AcpiOsPrintf (" /* External reference */");
260         return;
261     }
262 
263     /* Ignore if path is already from the root */
264 
265     if (*PrevOp->Asl.Value.String == '\\')
266     {
267         return;
268     }
269 
270     /* Now: we can get the full pathname */
271 
272     Pathname = AcpiNsGetExternalPathname (PrevOp->Asl.Node);
273     if (!Pathname)
274     {
275         return;
276     }
277 
278     AcpiOsPrintf (" /* %s */", Pathname);
279     ACPI_FREE (Pathname);
280 }
281 
282 
283 /*******************************************************************************
284  *
285  * FUNCTION:    AcpiDmNotifyDescription
286  *
287  * PARAMETERS:  Op              - Name() parse object
288  *
289  * RETURN:      None
290  *
291  * DESCRIPTION: Emit a description comment for the value associated with a
292  *              Notify() operator.
293  *
294  ******************************************************************************/
295 
296 void
297 AcpiDmNotifyDescription (
298     ACPI_PARSE_OBJECT       *Op)
299 {
300     ACPI_PARSE_OBJECT       *NextOp;
301     ACPI_NAMESPACE_NODE     *Node;
302     UINT8                   NotifyValue;
303     UINT8                   Type = ACPI_TYPE_ANY;
304 
305 
306     /* The notify value is the second argument */
307 
308     NextOp = Op->Asl.Value.Arg;
309     NextOp = NextOp->Asl.Next;
310 
311     switch (NextOp->Common.AmlOpcode)
312     {
313     case AML_ZERO_OP:
314     case AML_ONE_OP:
315 
316         NotifyValue = (UINT8) NextOp->Common.AmlOpcode;
317         break;
318 
319     case AML_BYTE_OP:
320 
321         NotifyValue = (UINT8) NextOp->Asl.Value.Integer;
322         break;
323 
324     default:
325         return;
326     }
327 
328     /*
329      * Attempt to get the namespace node so we can determine the object type.
330      * Some notify values are dependent on the object type (Device, Thermal,
331      * or Processor).
332      */
333     Node = Op->Asl.Node;
334     if (Node)
335     {
336         Type = Node->Type;
337     }
338 
339     AcpiOsPrintf (" // %s", AcpiUtGetNotifyName (NotifyValue, Type));
340 }
341 
342 
343 /*******************************************************************************
344  *
345  * FUNCTION:    AcpiDmPredefinedDescription
346  *
347  * PARAMETERS:  Op              - Name() parse object
348  *
349  * RETURN:      None
350  *
351  * DESCRIPTION: Emit a description comment for a predefined ACPI name.
352  *              Used for iASL compiler only.
353  *
354  ******************************************************************************/
355 
356 void
357 AcpiDmPredefinedDescription (
358     ACPI_PARSE_OBJECT       *Op)
359 {
360 #ifdef ACPI_ASL_COMPILER
361     const AH_PREDEFINED_NAME    *Info;
362     char                        *NameString;
363     int                         LastCharIsDigit;
364     int                         LastCharsAreHex;
365 
366 
367     if (!Op)
368     {
369         return;
370     }
371 
372     /* Ensure that the comment field is emitted only once */
373 
374     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED)
375     {
376         return;
377     }
378     Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED;
379 
380     /* Predefined name must start with an underscore */
381 
382     NameString = ACPI_CAST_PTR (char, &Op->Named.Name);
383     if (NameString[0] != '_')
384     {
385         return;
386     }
387 
388     /*
389      * Check for the special ACPI names:
390      * _ACd, _ALd, _EJd, _Exx, _Lxx, _Qxx, _Wxx, _T_a
391      * (where d=decimal_digit, x=hex_digit, a=anything)
392      *
393      * Convert these to the generic name for table lookup.
394      * Note: NameString is guaranteed to be upper case here.
395      */
396     LastCharIsDigit =
397         (isdigit ((int) NameString[3]));    /* d */
398     LastCharsAreHex =
399         (isxdigit ((int) NameString[2]) &&  /* xx */
400          isxdigit ((int) NameString[3]));
401 
402     switch (NameString[1])
403     {
404     case 'A':
405 
406         if ((NameString[2] == 'C') && (LastCharIsDigit))
407         {
408             NameString = "_ACx";
409         }
410         else if ((NameString[2] == 'L') && (LastCharIsDigit))
411         {
412             NameString = "_ALx";
413         }
414         break;
415 
416     case 'E':
417 
418         if ((NameString[2] == 'J') && (LastCharIsDigit))
419         {
420             NameString = "_EJx";
421         }
422         else if (LastCharsAreHex)
423         {
424             NameString = "_Exx";
425         }
426         break;
427 
428     case 'L':
429 
430         if (LastCharsAreHex)
431         {
432             NameString = "_Lxx";
433         }
434         break;
435 
436     case 'Q':
437 
438         if (LastCharsAreHex)
439         {
440             NameString = "_Qxx";
441         }
442         break;
443 
444     case 'T':
445 
446         if (NameString[2] == '_')
447         {
448             NameString = "_T_x";
449         }
450         break;
451 
452     case 'W':
453 
454         if (LastCharsAreHex)
455         {
456             NameString = "_Wxx";
457         }
458         break;
459 
460     default:
461 
462         break;
463     }
464 
465     /* Match the name in the info table */
466 
467     Info = AcpiAhMatchPredefinedName (NameString);
468     if (Info)
469     {
470         AcpiOsPrintf ("  // %4.4s: %s",
471             NameString, ACPI_CAST_PTR (char, Info->Description));
472     }
473 
474 #endif
475     return;
476 }
477 
478 
479 /*******************************************************************************
480  *
481  * FUNCTION:    AcpiDmFieldPredefinedDescription
482  *
483  * PARAMETERS:  Op              - Parse object
484  *
485  * RETURN:      None
486  *
487  * DESCRIPTION: Emit a description comment for a resource descriptor tag
488  *              (which is a predefined ACPI name.) Used for iASL compiler only.
489  *
490  ******************************************************************************/
491 
492 void
493 AcpiDmFieldPredefinedDescription (
494     ACPI_PARSE_OBJECT       *Op)
495 {
496 #ifdef ACPI_ASL_COMPILER
497     ACPI_PARSE_OBJECT       *IndexOp;
498     char                    *Tag;
499     const ACPI_OPCODE_INFO  *OpInfo;
500     const AH_PREDEFINED_NAME *Info;
501 
502 
503     if (!Op)
504     {
505         return;
506     }
507 
508     /* Ensure that the comment field is emitted only once */
509 
510     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PREDEFINED_CHECKED)
511     {
512         return;
513     }
514     Op->Common.DisasmFlags |= ACPI_PARSEOP_PREDEFINED_CHECKED;
515 
516     /*
517      * Op must be one of the Create* operators: CreateField, CreateBitField,
518      * CreateByteField, CreateWordField, CreateDwordField, CreateQwordField
519      */
520     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
521     if (!(OpInfo->Flags & AML_CREATE))
522     {
523         return;
524     }
525 
526     /* Second argument is the Index argument */
527 
528     IndexOp = Op->Common.Value.Arg;
529     IndexOp = IndexOp->Common.Next;
530 
531     /* Index argument must be a namepath */
532 
533     if (IndexOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP)
534     {
535         return;
536     }
537 
538     /* Major cheat: We previously put the Tag ptr in the Node field */
539 
540     Tag = ACPI_CAST_PTR (char, IndexOp->Common.Node);
541     if (!Tag)
542     {
543         return;
544     }
545 
546     /* Match the name in the info table */
547 
548     Info = AcpiAhMatchPredefinedName (Tag);
549     if (Info)
550     {
551         AcpiOsPrintf ("  // %4.4s: %s", Tag,
552             ACPI_CAST_PTR (char, Info->Description));
553     }
554 
555     /* AML buffer (String) was allocated in AcpiGetTagPathname */
556 
557     ACPI_FREE (IndexOp->Common.Value.String);
558 
559 #endif
560     return;
561 }
562 
563 
564 /*******************************************************************************
565  *
566  * FUNCTION:    AcpiDmMethodFlags
567  *
568  * PARAMETERS:  Op              - Method Object to be examined
569  *
570  * RETURN:      None
571  *
572  * DESCRIPTION: Decode control method flags
573  *
574  ******************************************************************************/
575 
576 void
577 AcpiDmMethodFlags (
578     ACPI_PARSE_OBJECT       *Op)
579 {
580     UINT32                  Flags;
581     UINT32                  Args;
582 
583 
584     /* The next Op contains the flags */
585 
586     Op = AcpiPsGetDepthNext (NULL, Op);
587     Flags = (UINT8) Op->Common.Value.Integer;
588     Args = Flags & 0x07;
589 
590     /* Mark the Op as completed */
591 
592     Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
593 
594     /* 1) Method argument count */
595 
596     AcpiOsPrintf (", %u, ", Args);
597 
598     /* 2) Serialize rule */
599 
600     if (!(Flags & 0x08))
601     {
602         AcpiOsPrintf ("Not");
603     }
604 
605     AcpiOsPrintf ("Serialized");
606 
607     /* 3) SyncLevel */
608 
609     if (Flags & 0xF0)
610     {
611         AcpiOsPrintf (", %u", Flags >> 4);
612     }
613 }
614 
615 
616 /*******************************************************************************
617  *
618  * FUNCTION:    AcpiDmFieldFlags
619  *
620  * PARAMETERS:  Op              - Field Object to be examined
621  *
622  * RETURN:      None
623  *
624  * DESCRIPTION: Decode Field definition flags
625  *
626  ******************************************************************************/
627 
628 void
629 AcpiDmFieldFlags (
630     ACPI_PARSE_OBJECT       *Op)
631 {
632     UINT32                  Flags;
633 
634 
635     Op = Op->Common.Next;
636     Flags = (UINT8) Op->Common.Value.Integer;
637 
638     /* Mark the Op as completed */
639 
640     Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
641 
642     AcpiOsPrintf ("%s, ", AcpiGbl_AccessTypes [Flags & 0x07]);
643     AcpiOsPrintf ("%s, ", AcpiGbl_LockRule [(Flags & 0x10) >> 4]);
644     AcpiOsPrintf ("%s)",  AcpiGbl_UpdateRules [(Flags & 0x60) >> 5]);
645 }
646 
647 
648 /*******************************************************************************
649  *
650  * FUNCTION:    AcpiDmAddressSpace
651  *
652  * PARAMETERS:  SpaceId         - ID to be translated
653  *
654  * RETURN:      None
655  *
656  * DESCRIPTION: Decode a SpaceId to an AddressSpaceKeyword
657  *
658  ******************************************************************************/
659 
660 void
661 AcpiDmAddressSpace (
662     UINT8                   SpaceId)
663 {
664 
665     if (SpaceId >= ACPI_NUM_PREDEFINED_REGIONS)
666     {
667         if (SpaceId == 0x7F)
668         {
669             AcpiOsPrintf ("FFixedHW, ");
670         }
671         else
672         {
673             AcpiOsPrintf ("0x%.2X, ", SpaceId);
674         }
675     }
676     else
677     {
678         AcpiOsPrintf ("%s, ", AcpiGbl_RegionTypes [SpaceId]);
679     }
680 }
681 
682 
683 /*******************************************************************************
684  *
685  * FUNCTION:    AcpiDmRegionFlags
686  *
687  * PARAMETERS:  Op              - Object to be examined
688  *
689  * RETURN:      None
690  *
691  * DESCRIPTION: Decode OperationRegion flags
692  *
693  ******************************************************************************/
694 
695 void
696 AcpiDmRegionFlags (
697     ACPI_PARSE_OBJECT       *Op)
698 {
699 
700     /* The next Op contains the SpaceId */
701 
702     Op = AcpiPsGetDepthNext (NULL, Op);
703 
704     /* Mark the Op as completed */
705 
706     Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
707 
708     AcpiOsPrintf (", ");
709     AcpiDmAddressSpace ((UINT8) Op->Common.Value.Integer);
710 }
711 
712 
713 /*******************************************************************************
714  *
715  * FUNCTION:    AcpiDmMatchOp
716  *
717  * PARAMETERS:  Op              - Match Object to be examined
718  *
719  * RETURN:      None
720  *
721  * DESCRIPTION: Decode Match opcode operands
722  *
723  ******************************************************************************/
724 
725 void
726 AcpiDmMatchOp (
727     ACPI_PARSE_OBJECT       *Op)
728 {
729     ACPI_PARSE_OBJECT       *NextOp;
730 
731 
732     NextOp = AcpiPsGetDepthNext (NULL, Op);
733     NextOp = NextOp->Common.Next;
734 
735     if (!NextOp)
736     {
737         /* Handle partial tree during single-step */
738 
739         return;
740     }
741 
742     /* Mark the two nodes that contain the encoding for the match keywords */
743 
744     NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP;
745 
746     NextOp = NextOp->Common.Next;
747     NextOp = NextOp->Common.Next;
748     NextOp->Common.DisasmOpcode = ACPI_DASM_MATCHOP;
749 }
750 
751 
752 /*******************************************************************************
753  *
754  * FUNCTION:    AcpiDmMatchKeyword
755  *
756  * PARAMETERS:  Op              - Match Object to be examined
757  *
758  * RETURN:      None
759  *
760  * DESCRIPTION: Decode Match opcode operands
761  *
762  ******************************************************************************/
763 
764 static void
765 AcpiDmMatchKeyword (
766     ACPI_PARSE_OBJECT       *Op)
767 {
768 
769     if (((UINT32) Op->Common.Value.Integer) > ACPI_MAX_MATCH_OPCODE)
770     {
771         AcpiOsPrintf ("/* Unknown Match Keyword encoding */");
772     }
773     else
774     {
775         AcpiOsPrintf ("%s",
776             AcpiGbl_MatchOps[(ACPI_SIZE) Op->Common.Value.Integer]);
777     }
778 }
779 
780 
781 /*******************************************************************************
782  *
783  * FUNCTION:    AcpiDmDisassembleOneOp
784  *
785  * PARAMETERS:  WalkState           - Current walk info
786  *              Info                - Parse tree walk info
787  *              Op                  - Op that is to be printed
788  *
789  * RETURN:      None
790  *
791  * DESCRIPTION: Disassemble a single AML opcode
792  *
793  ******************************************************************************/
794 
795 void
796 AcpiDmDisassembleOneOp (
797     ACPI_WALK_STATE         *WalkState,
798     ACPI_OP_WALK_INFO       *Info,
799     ACPI_PARSE_OBJECT       *Op)
800 {
801     const ACPI_OPCODE_INFO  *OpInfo = NULL;
802     UINT32                  Offset;
803     UINT32                  Length;
804     ACPI_PARSE_OBJECT       *Child;
805     ACPI_STATUS             Status;
806     UINT8                   *Aml;
807     const AH_DEVICE_ID      *IdInfo;
808 
809 
810     if (!Op)
811     {
812         AcpiOsPrintf ("<NULL OP PTR>");
813         return;
814     }
815 
816     if (Op->Common.DisasmFlags & ACPI_PARSEOP_ELSEIF)
817     {
818         return; /* ElseIf macro was already emitted */
819     }
820 
821     switch (Op->Common.DisasmOpcode)
822     {
823     case ACPI_DASM_MATCHOP:
824 
825         AcpiDmMatchKeyword (Op);
826         return;
827 
828     case ACPI_DASM_LNOT_SUFFIX:
829 
830         if (!AcpiGbl_CstyleDisassembly)
831         {
832             switch (Op->Common.AmlOpcode)
833             {
834             case AML_LOGICAL_EQUAL_OP:
835                 AcpiOsPrintf ("LNotEqual");
836                 break;
837 
838             case AML_LOGICAL_GREATER_OP:
839                 AcpiOsPrintf ("LLessEqual");
840                 break;
841 
842             case AML_LOGICAL_LESS_OP:
843                 AcpiOsPrintf ("LGreaterEqual");
844                 break;
845 
846             default:
847                 break;
848             }
849         }
850 
851         Op->Common.DisasmOpcode = 0;
852         Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
853         return;
854 
855     default:
856         break;
857     }
858 
859     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
860 
861     /* The op and arguments */
862 
863     switch (Op->Common.AmlOpcode)
864     {
865     case AML_LOGICAL_NOT_OP:
866 
867         Child = Op->Common.Value.Arg;
868         if ((Child->Common.AmlOpcode == AML_LOGICAL_EQUAL_OP) ||
869             (Child->Common.AmlOpcode == AML_LOGICAL_GREATER_OP) ||
870             (Child->Common.AmlOpcode == AML_LOGICAL_LESS_OP))
871         {
872             Child->Common.DisasmOpcode = ACPI_DASM_LNOT_SUFFIX;
873             Op->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
874         }
875         else
876         {
877             AcpiOsPrintf ("%s", OpInfo->Name);
878         }
879         break;
880 
881     case AML_BYTE_OP:
882 
883         AcpiOsPrintf ("0x%2.2X", (UINT32) Op->Common.Value.Integer);
884         break;
885 
886     case AML_WORD_OP:
887 
888         if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID)
889         {
890             AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer);
891         }
892         else
893         {
894             AcpiOsPrintf ("0x%4.4X", (UINT32) Op->Common.Value.Integer);
895         }
896         break;
897 
898     case AML_DWORD_OP:
899 
900         if (Op->Common.DisasmOpcode == ACPI_DASM_EISAID)
901         {
902             AcpiDmDecompressEisaId ((UINT32) Op->Common.Value.Integer);
903         }
904         else
905         {
906             AcpiOsPrintf ("0x%8.8X", (UINT32) Op->Common.Value.Integer);
907         }
908         break;
909 
910     case AML_QWORD_OP:
911 
912         AcpiOsPrintf ("0x%8.8X%8.8X",
913             ACPI_FORMAT_UINT64 (Op->Common.Value.Integer));
914         break;
915 
916     case AML_STRING_OP:
917 
918         AcpiUtPrintString (Op->Common.Value.String, ACPI_UINT16_MAX);
919 
920         /* For _HID/_CID strings, attempt to output a descriptive comment */
921 
922         if (Op->Common.DisasmOpcode == ACPI_DASM_HID_STRING)
923         {
924             /* If we know about the ID, emit the description */
925 
926             IdInfo = AcpiAhMatchHardwareId (Op->Common.Value.String);
927             if (IdInfo)
928             {
929                 AcpiOsPrintf (" /* %s */", IdInfo->Description);
930             }
931         }
932         break;
933 
934     case AML_BUFFER_OP:
935         /*
936          * Determine the type of buffer. We can have one of the following:
937          *
938          * 1) ResourceTemplate containing Resource Descriptors.
939          * 2) Unicode String buffer
940          * 3) ASCII String buffer
941          * 4) Raw data buffer (if none of the above)
942          *
943          * Since there are no special AML opcodes to differentiate these
944          * types of buffers, we have to closely look at the data in the
945          * buffer to determine the type.
946          */
947         if (!AcpiGbl_NoResourceDisassembly)
948         {
949             Status = AcpiDmIsResourceTemplate (WalkState, Op);
950             if (ACPI_SUCCESS (Status))
951             {
952                 Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE;
953                 AcpiOsPrintf ("ResourceTemplate");
954                 break;
955             }
956             else if (Status == AE_AML_NO_RESOURCE_END_TAG)
957             {
958                 AcpiOsPrintf (
959                     "/**** Is ResourceTemplate, "
960                     "but EndTag not at buffer end ****/ ");
961             }
962         }
963 
964         if (AcpiDmIsUuidBuffer (Op))
965         {
966             Op->Common.DisasmOpcode = ACPI_DASM_UUID;
967             AcpiOsPrintf ("ToUUID (");
968         }
969         else if (AcpiDmIsUnicodeBuffer (Op))
970         {
971             Op->Common.DisasmOpcode = ACPI_DASM_UNICODE;
972             AcpiOsPrintf ("Unicode (");
973         }
974         else if (AcpiDmIsStringBuffer (Op))
975         {
976             Op->Common.DisasmOpcode = ACPI_DASM_STRING;
977             AcpiOsPrintf ("Buffer");
978         }
979         else if (AcpiDmIsPldBuffer (Op))
980         {
981             Op->Common.DisasmOpcode = ACPI_DASM_PLD_METHOD;
982             AcpiOsPrintf ("ToPLD (");
983         }
984         else
985         {
986             Op->Common.DisasmOpcode = ACPI_DASM_BUFFER;
987             AcpiOsPrintf ("Buffer");
988         }
989         break;
990 
991     case AML_INT_NAMEPATH_OP:
992 
993         AcpiDmNamestring (Op->Common.Value.Name);
994         break;
995 
996     case AML_INT_NAMEDFIELD_OP:
997 
998         Length = AcpiDmDumpName (Op->Named.Name);
999 
1000         AcpiOsPrintf (",");
1001         ASL_CV_PRINT_ONE_COMMENT (Op, AML_NAMECOMMENT, NULL, 0);
1002         AcpiOsPrintf ("%*.s  %u", (unsigned) (5 - Length), " ",
1003             (UINT32) Op->Common.Value.Integer);
1004 
1005         AcpiDmCommaIfFieldMember (Op);
1006 
1007         Info->BitOffset += (UINT32) Op->Common.Value.Integer;
1008         break;
1009 
1010     case AML_INT_RESERVEDFIELD_OP:
1011 
1012         /* Offset() -- Must account for previous offsets */
1013 
1014         Offset = (UINT32) Op->Common.Value.Integer;
1015         Info->BitOffset += Offset;
1016 
1017         if (Info->BitOffset % 8 == 0)
1018         {
1019             AcpiOsPrintf ("Offset (0x%.2X)", ACPI_DIV_8 (Info->BitOffset));
1020         }
1021         else
1022         {
1023             AcpiOsPrintf ("    ,   %u", Offset);
1024         }
1025 
1026         AcpiDmCommaIfFieldMember (Op);
1027         break;
1028 
1029     case AML_INT_ACCESSFIELD_OP:
1030     case AML_INT_EXTACCESSFIELD_OP:
1031 
1032         AcpiOsPrintf ("AccessAs (%s, ",
1033             AcpiGbl_AccessTypes [(UINT32) (Op->Common.Value.Integer & 0x7)]);
1034 
1035         AcpiDmDecodeAttribute ((UINT8) (Op->Common.Value.Integer >> 8));
1036 
1037         if (Op->Common.AmlOpcode == AML_INT_EXTACCESSFIELD_OP)
1038         {
1039             AcpiOsPrintf (" (0x%2.2X)", (unsigned)
1040                 ((Op->Common.Value.Integer >> 16) & 0xFF));
1041         }
1042 
1043         AcpiOsPrintf (")");
1044         AcpiDmCommaIfFieldMember (Op);
1045         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
1046         break;
1047 
1048     case AML_INT_CONNECTION_OP:
1049         /*
1050          * Two types of Connection() - one with a buffer object, the
1051          * other with a namestring that points to a buffer object.
1052          */
1053         AcpiOsPrintf ("Connection (");
1054         Child = Op->Common.Value.Arg;
1055 
1056         if (Child->Common.AmlOpcode == AML_INT_BYTELIST_OP)
1057         {
1058             AcpiOsPrintf ("\n");
1059 
1060             Aml = Child->Named.Data;
1061             Length = (UINT32) Child->Common.Value.Integer;
1062 
1063             Info->Level += 1;
1064             Info->MappingOp = Op;
1065             Op->Common.DisasmOpcode = ACPI_DASM_RESOURCE;
1066 
1067             AcpiDmResourceTemplate (Info, Op->Common.Parent, Aml, Length);
1068 
1069             Info->Level -= 1;
1070             AcpiDmIndent (Info->Level);
1071         }
1072         else
1073         {
1074             AcpiDmNamestring (Child->Common.Value.Name);
1075         }
1076 
1077         AcpiOsPrintf (")");
1078         AcpiDmCommaIfFieldMember (Op);
1079         ASL_CV_PRINT_ONE_COMMENT (Op, AML_COMMENT_END_NODE, NULL, 0);
1080         ASL_CV_PRINT_ONE_COMMENT (Op, AMLCOMMENT_INLINE, NULL, 0);
1081         AcpiOsPrintf ("\n");
1082 
1083         Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE; /* for now, ignore in AcpiDmAscendingOp */
1084         Child->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1085         break;
1086 
1087     case AML_INT_BYTELIST_OP:
1088 
1089         AcpiDmByteList (Info, Op);
1090         break;
1091 
1092     case AML_INT_METHODCALL_OP:
1093 
1094         Op = AcpiPsGetDepthNext (NULL, Op);
1095         Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1096 
1097         AcpiDmNamestring (Op->Common.Value.Name);
1098         break;
1099 
1100     case AML_WHILE_OP:
1101 
1102         if (Op->Common.DisasmOpcode == ACPI_DASM_SWITCH)
1103         {
1104             AcpiOsPrintf ("%s", "Switch");
1105             break;
1106         }
1107 
1108         AcpiOsPrintf ("%s", OpInfo->Name);
1109         break;
1110 
1111     case AML_IF_OP:
1112 
1113         if (Op->Common.DisasmOpcode == ACPI_DASM_CASE)
1114         {
1115             AcpiOsPrintf ("%s", "Case");
1116             break;
1117         }
1118 
1119         AcpiOsPrintf ("%s", OpInfo->Name);
1120         break;
1121 
1122     case AML_ELSE_OP:
1123 
1124         AcpiDmConvertToElseIf (Op);
1125         break;
1126 
1127     case AML_EXTERNAL_OP:
1128 
1129         if (AcpiGbl_DmEmitExternalOpcodes)
1130         {
1131             AcpiDmEmitExternal (AcpiPsGetArg(Op, 0),
1132                 AcpiPsGetArg(Op, 1));
1133             break;
1134         }
1135 
1136         break;
1137 
1138     default:
1139 
1140         /* Just get the opcode name and print it */
1141 
1142         AcpiOsPrintf ("%s", OpInfo->Name);
1143 
1144 
1145 #ifdef ACPI_DEBUGGER
1146 
1147         if ((Op->Common.AmlOpcode == AML_INT_RETURN_VALUE_OP) &&
1148             (WalkState) &&
1149             (WalkState->Results) &&
1150             (WalkState->ResultCount))
1151         {
1152             AcpiDbDecodeInternalObject (
1153                 WalkState->Results->Results.ObjDesc [
1154                     (WalkState->ResultCount - 1) %
1155                         ACPI_RESULTS_FRAME_OBJ_NUM]);
1156         }
1157 #endif
1158 
1159         break;
1160     }
1161 }
1162 
1163 
1164 /*******************************************************************************
1165  *
1166  * FUNCTION:    AcpiDmConvertToElseIf
1167  *
1168  * PARAMETERS:  OriginalElseOp          - ELSE Object to be examined
1169  *
1170  * RETURN:      None. Emits either an "Else" or an "ElseIf" ASL operator.
1171  *
1172  * DESCRIPTION: Detect and convert an If..Else..If sequence to If..ElseIf
1173  *
1174  * EXAMPLE:
1175  *
1176  * This If..Else..If nested sequence:
1177  *
1178  *        If (Arg0 == 1)
1179  *        {
1180  *            Local0 = 4
1181  *        }
1182  *        Else
1183  *        {
1184  *            If (Arg0 == 2)
1185  *            {
1186  *                Local0 = 5
1187  *            }
1188  *        }
1189  *
1190  * Is converted to this simpler If..ElseIf sequence:
1191  *
1192  *        If (Arg0 == 1)
1193  *        {
1194  *            Local0 = 4
1195  *        }
1196  *        ElseIf (Arg0 == 2)
1197  *        {
1198  *            Local0 = 5
1199  *        }
1200  *
1201  * NOTE: There is no actual ElseIf AML opcode. ElseIf is essentially an ASL
1202  * macro that emits an Else opcode followed by an If opcode. This function
1203  * reverses these AML sequences back to an ElseIf macro where possible. This
1204  * can make the disassembled ASL code simpler and more like the original code.
1205  *
1206  ******************************************************************************/
1207 
1208 static void
1209 AcpiDmConvertToElseIf (
1210     ACPI_PARSE_OBJECT       *OriginalElseOp)
1211 {
1212     ACPI_PARSE_OBJECT       *IfOp;
1213     ACPI_PARSE_OBJECT       *ElseOp;
1214 
1215 
1216     /*
1217      * To be able to perform the conversion, two conditions must be satisfied:
1218      * 1) The first child of the Else must be an If statement.
1219      * 2) The If block can only be followed by an Else block and these must
1220      *    be the only blocks under the original Else.
1221      */
1222     IfOp = OriginalElseOp->Common.Value.Arg;
1223 
1224     if (!IfOp ||
1225         (IfOp->Common.AmlOpcode != AML_IF_OP) ||
1226         (IfOp->Asl.Next && (IfOp->Asl.Next->Common.AmlOpcode != AML_ELSE_OP)))
1227     {
1228         /* Not a proper Else..If sequence, cannot convert to ElseIf */
1229 
1230         if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT)
1231         {
1232             AcpiOsPrintf ("%s", "Default");
1233             return;
1234         }
1235 
1236         AcpiOsPrintf ("%s", "Else");
1237         return;
1238     }
1239 
1240     /* Cannot have anything following the If...Else block */
1241 
1242     ElseOp = IfOp->Common.Next;
1243     if (ElseOp && ElseOp->Common.Next)
1244     {
1245         if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT)
1246         {
1247             AcpiOsPrintf ("%s", "Default");
1248             return;
1249         }
1250 
1251         AcpiOsPrintf ("%s", "Else");
1252         return;
1253     }
1254 
1255     if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_DEFAULT)
1256     {
1257         /*
1258          * There is an ElseIf but in this case the Else is actually
1259          * a Default block for a Switch/Case statement. No conversion.
1260          */
1261         AcpiOsPrintf ("%s", "Default");
1262         return;
1263     }
1264 
1265     if (OriginalElseOp->Common.DisasmOpcode == ACPI_DASM_CASE)
1266     {
1267         /*
1268          * This ElseIf is actually a Case block for a Switch/Case
1269          * statement. Print Case but do not return so that we can
1270          * promote the subtree and keep the indentation level.
1271          */
1272         AcpiOsPrintf ("%s", "Case");
1273     }
1274     else
1275     {
1276        /* Emit ElseIf, mark the IF as now an ELSEIF */
1277 
1278         AcpiOsPrintf ("%s", "ElseIf");
1279     }
1280 
1281     IfOp->Common.DisasmFlags |= ACPI_PARSEOP_ELSEIF;
1282 
1283     /* The IF parent will now be the same as the original ELSE parent */
1284 
1285     IfOp->Common.Parent = OriginalElseOp->Common.Parent;
1286 
1287     /*
1288      * Update the NEXT pointers to restructure the parse tree, essentially
1289      * promoting an If..Else block up to the same level as the original
1290      * Else.
1291      *
1292      * Check if the IF has a corresponding ELSE peer
1293      */
1294     ElseOp = IfOp->Common.Next;
1295     if (ElseOp &&
1296         (ElseOp->Common.AmlOpcode == AML_ELSE_OP))
1297     {
1298         /* If an ELSE matches the IF, promote it also */
1299 
1300         ElseOp->Common.Parent = OriginalElseOp->Common.Parent;
1301 
1302         /* Promote the entire block under the ElseIf (All Next OPs) */
1303 
1304         AcpiDmPromoteSubtree (OriginalElseOp);
1305     }
1306     else
1307     {
1308         /* Otherwise, set the IF NEXT to the original ELSE NEXT */
1309 
1310         IfOp->Common.Next = OriginalElseOp->Common.Next;
1311     }
1312 
1313     /* Detach the child IF block from the original ELSE */
1314 
1315     OriginalElseOp->Common.Value.Arg = NULL;
1316 
1317     /* Ignore the original ELSE from now on */
1318 
1319     OriginalElseOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1320     OriginalElseOp->Common.DisasmOpcode = ACPI_DASM_LNOT_PREFIX;
1321 
1322     /* Insert IF (now ELSEIF) as next peer of the original ELSE */
1323 
1324     OriginalElseOp->Common.Next = IfOp;
1325 }
1326 
1327 
1328 /*******************************************************************************
1329  *
1330  * FUNCTION:    AcpiDmPromoteSubtree
1331  *
1332  * PARAMETERS:  StartOpOp           - Original parent of the entire subtree
1333  *
1334  * RETURN:      None
1335  *
1336  * DESCRIPTION: Promote an entire parse subtree up one level.
1337  *
1338  ******************************************************************************/
1339 
1340 static void
1341 AcpiDmPromoteSubtree (
1342     ACPI_PARSE_OBJECT       *StartOp)
1343 {
1344     ACPI_PARSE_OBJECT       *Op;
1345     ACPI_PARSE_OBJECT       *ParentOp;
1346 
1347 
1348     /* New parent for subtree elements */
1349 
1350     ParentOp = StartOp->Common.Parent;
1351 
1352     /* First child starts the subtree */
1353 
1354     Op = StartOp->Common.Value.Arg;
1355 
1356     /* Walk the top-level elements of the subtree */
1357 
1358     while (Op)
1359     {
1360         Op->Common.Parent = ParentOp;
1361         if (!Op->Common.Next)
1362         {
1363             /* Last Op in list, update its next field */
1364 
1365             Op->Common.Next = StartOp->Common.Next;
1366             break;
1367         }
1368         Op = Op->Common.Next;
1369     }
1370 }
1371 
1372 /*******************************************************************************
1373  *
1374  * FUNCTION:    AcpiDmIsTempName
1375  *
1376  * PARAMETERS:  Op              - Object to be examined
1377  *
1378  * RETURN:      TRUE if object is a temporary (_T_x) name for a matching While
1379  *              loop that can be converted to a Switch.
1380  *
1381  * DESCRIPTION: _T_X objects are only used for Switch statements. If a temporary
1382  *              name exists, search the siblings for a matching While (One) loop
1383  *              that can be converted to a Switch. Return TRUE if a match was
1384  *              found, FALSE otherwise.
1385  *
1386  ******************************************************************************/
1387 
1388 BOOLEAN
1389 AcpiDmIsTempName (
1390     ACPI_PARSE_OBJECT       *Op)
1391 {
1392     ACPI_PARSE_OBJECT       *CurrentOp;
1393     char                    *Temp;
1394 
1395     if (Op->Common.AmlOpcode != AML_NAME_OP)
1396     {
1397         return (FALSE);
1398     }
1399 
1400     Temp = (char *)(Op->Common.Aml);
1401     ++Temp;
1402 
1403     if (strncmp(Temp, "_T_", 3))
1404     {
1405         return (FALSE);
1406     }
1407 
1408     CurrentOp = Op->Common.Next;
1409     while (CurrentOp)
1410     {
1411         if (CurrentOp->Common.AmlOpcode == AML_WHILE_OP &&
1412             AcpiDmIsSwitchBlock(CurrentOp, Temp))
1413         {
1414             Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1415             CurrentOp->Common.DisasmOpcode = ACPI_DASM_SWITCH;
1416 
1417             return (TRUE);
1418         }
1419         CurrentOp = CurrentOp->Common.Next;
1420     }
1421 
1422     return (FALSE);
1423 }
1424 
1425 /*******************************************************************************
1426  *
1427  * FUNCTION:    AcpiDmIsSwitchBlock
1428  *
1429  * PARAMETERS:  Op              - While Object
1430  *
1431  * RETURN:      TRUE if While block can be converted to a Switch/Case block
1432  *
1433  * DESCRIPTION: Determines if While block is a Switch/Case statement. Modifies
1434  *              parse tree to allow for Switch/Case disassembly during walk.
1435  *
1436  * EXAMPLE: Example of parse tree to be converted
1437  *
1438  *    While
1439  *        One
1440  *        Store
1441  *            ByteConst
1442  *             -NamePath-
1443  *        If
1444  *            LEqual
1445  *                -NamePath-
1446  *                Zero
1447  *            Return
1448  *                One
1449  *        Else
1450  *            Return
1451  *                WordConst
1452  *        Break
1453  *
1454  ******************************************************************************/
1455 
1456 static BOOLEAN
1457 AcpiDmIsSwitchBlock (
1458     ACPI_PARSE_OBJECT       *Op,
1459     char                    *Temp)
1460 {
1461     ACPI_PARSE_OBJECT       *OneOp;
1462     ACPI_PARSE_OBJECT       *StoreOp;
1463     ACPI_PARSE_OBJECT       *NamePathOp;
1464     ACPI_PARSE_OBJECT       *PredicateOp;
1465     ACPI_PARSE_OBJECT       *CurrentOp;
1466     ACPI_PARSE_OBJECT       *TempOp;
1467 
1468     /* Check for One Op Predicate */
1469 
1470     OneOp = AcpiPsGetArg (Op, 0);
1471     if (!OneOp || (OneOp->Common.AmlOpcode != AML_ONE_OP))
1472     {
1473         return (FALSE);
1474     }
1475 
1476     /* Check for Store Op */
1477 
1478     StoreOp = OneOp->Common.Next;
1479     if (!StoreOp || (StoreOp->Common.AmlOpcode != AML_STORE_OP))
1480     {
1481         return (FALSE);
1482     }
1483 
1484     /* Check for Name Op with _T_ string */
1485 
1486     NamePathOp = AcpiPsGetArg (StoreOp, 1);
1487     if (!NamePathOp || (NamePathOp->Common.AmlOpcode != AML_INT_NAMEPATH_OP))
1488     {
1489         return (FALSE);
1490     }
1491 
1492     if (strncmp((char *)(NamePathOp->Common.Aml), Temp, 4))
1493     {
1494         return (FALSE);
1495     }
1496 
1497     /* This is a Switch/Case control block */
1498 
1499     /* Ignore the One Op Predicate */
1500 
1501     OneOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1502 
1503     /* Ignore the Store Op, but not the children */
1504 
1505     StoreOp->Common.DisasmOpcode = ACPI_DASM_IGNORE_SINGLE;
1506 
1507     /*
1508      * First arg of Store Op is the Switch condition.
1509      * Mark it as a Switch predicate and as a parameter list for paren
1510      * closing and correct indentation.
1511      */
1512     PredicateOp = AcpiPsGetArg (StoreOp, 0);
1513     PredicateOp->Common.DisasmOpcode = ACPI_DASM_SWITCH_PREDICATE;
1514     PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
1515 
1516     /* Ignore the Name Op */
1517 
1518     NamePathOp->Common.DisasmFlags = ACPI_PARSEOP_IGNORE;
1519 
1520     /* Remaining opcodes are the Case statements (If/ElseIf's) */
1521 
1522     CurrentOp = StoreOp->Common.Next;
1523     while (AcpiDmIsCaseBlock (CurrentOp))
1524     {
1525         /* Block is a Case structure */
1526 
1527         if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1528         {
1529             /* ElseIf */
1530 
1531             CurrentOp->Common.DisasmOpcode = ACPI_DASM_CASE;
1532             CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1533         }
1534 
1535         /* If */
1536 
1537         CurrentOp->Common.DisasmOpcode = ACPI_DASM_CASE;
1538 
1539         /*
1540          * Mark the parse tree for Case disassembly. There are two
1541          * types of Case statements. The first type of statement begins with
1542          * an LEqual. The second starts with an LNot and uses a Match statement
1543          * on a Package of constants.
1544          */
1545         TempOp = AcpiPsGetArg (CurrentOp, 0);
1546         switch (TempOp->Common.AmlOpcode)
1547         {
1548             case (AML_LOGICAL_EQUAL_OP):
1549 
1550                 /* Ignore just the LEqual Op */
1551 
1552                 TempOp->Common.DisasmOpcode = ACPI_DASM_IGNORE_SINGLE;
1553 
1554                 /* Ignore the NamePath Op */
1555 
1556                 TempOp = AcpiPsGetArg (TempOp, 0);
1557                 TempOp->Common.DisasmFlags = ACPI_PARSEOP_IGNORE;
1558 
1559                 /*
1560                  * Second arg of LEqual will be the Case predicate.
1561                  * Mark it as a predicate and also as a parameter list for paren
1562                  * closing and correct indentation.
1563                  */
1564                 PredicateOp = TempOp->Common.Next;
1565                 PredicateOp->Common.DisasmOpcode = ACPI_DASM_SWITCH_PREDICATE;
1566                 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
1567 
1568                 break;
1569 
1570             case (AML_LOGICAL_NOT_OP):
1571 
1572                 /*
1573                  * The Package will be the predicate of the Case statement.
1574                  * It's under:
1575                  *            LNOT
1576                  *                LEQUAL
1577                  *                    MATCH
1578                  *                        PACKAGE
1579                  */
1580 
1581                 /* Get the LEqual Op from LNot */
1582 
1583                 TempOp = AcpiPsGetArg (TempOp, 0);
1584 
1585                 /* Get the Match Op from LEqual */
1586 
1587                 TempOp = AcpiPsGetArg (TempOp, 0);
1588 
1589                 /* Get the Package Op from Match */
1590 
1591                 PredicateOp = AcpiPsGetArg (TempOp, 0);
1592 
1593                 /* Mark as parameter list for paren closing */
1594 
1595                 PredicateOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMETER_LIST;
1596 
1597                 /*
1598                  * The Package list would be too deeply indented if we
1599                  * chose to simply ignore the all the parent opcodes, so
1600                  * we rearrange the parse tree instead.
1601                  */
1602 
1603                 /*
1604                  * Save the second arg of the If/Else Op which is the
1605                  * block code of code for this Case statement.
1606                  */
1607                 TempOp = AcpiPsGetArg (CurrentOp, 1);
1608 
1609                 /*
1610                  * Move the Package Op to the child (predicate) of the
1611                  * Case statement.
1612                  */
1613                 CurrentOp->Common.Value.Arg = PredicateOp;
1614                 PredicateOp->Common.Parent = CurrentOp;
1615 
1616                 /* Add the block code */
1617 
1618                 PredicateOp->Common.Next = TempOp;
1619 
1620                 break;
1621 
1622             default:
1623 
1624                 /* Should never get here */
1625 
1626                 break;
1627         }
1628 
1629         /* Advance to next Case block */
1630 
1631         CurrentOp = CurrentOp->Common.Next;
1632     }
1633 
1634     /* If CurrentOp is now an Else, then this is a Default block */
1635 
1636     if (CurrentOp && CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1637     {
1638         CurrentOp->Common.DisasmOpcode = ACPI_DASM_DEFAULT;
1639     }
1640 
1641     /*
1642      * From the first If advance to the Break op. It's possible to
1643      * have an Else (Default) op here when there is only one Case
1644      * statement, so check for it.
1645      */
1646     CurrentOp = StoreOp->Common.Next->Common.Next;
1647     if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1648     {
1649         CurrentOp = CurrentOp->Common.Next;
1650     }
1651 
1652     /* Ignore the Break Op */
1653 
1654     CurrentOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
1655 
1656     return (TRUE);
1657 }
1658 
1659 /*******************************************************************************
1660  *
1661  * FUNCTION:    AcpiDmIsCaseBlock
1662  *
1663  * PARAMETERS:  Op              - Object to test
1664  *
1665  * RETURN:      TRUE if Object is beginning of a Case block.
1666  *
1667  * DESCRIPTION: Determines if an Object is the beginning of a Case block for a
1668  *              Switch/Case statement. Parse tree must be one of the following
1669  *              forms:
1670  *
1671  *              Else (Optional)
1672  *                  If
1673  *                      LEqual
1674  *                          -NamePath- _T_x
1675  *
1676  *              Else (Optional)
1677  *                  If
1678  *                      LNot
1679  *                          LEqual
1680  *                              Match
1681  *                                  Package
1682  *                                      ByteConst
1683  *                                      -NamePath- _T_x
1684  *
1685  ******************************************************************************/
1686 
1687 static BOOLEAN
1688 AcpiDmIsCaseBlock (
1689     ACPI_PARSE_OBJECT       *Op)
1690 {
1691     ACPI_PARSE_OBJECT       *CurrentOp;
1692 
1693     if (!Op)
1694     {
1695         return (FALSE);
1696     }
1697 
1698     /* Look for an If or ElseIf */
1699 
1700     CurrentOp = Op;
1701     if (CurrentOp->Common.AmlOpcode == AML_ELSE_OP)
1702     {
1703         CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1704         if (!CurrentOp)
1705         {
1706             return (FALSE);
1707         }
1708     }
1709 
1710     if (!CurrentOp || CurrentOp->Common.AmlOpcode != AML_IF_OP)
1711     {
1712         return (FALSE);
1713     }
1714 
1715     /* Child must be LEqual or LNot */
1716 
1717     CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1718     if (!CurrentOp)
1719     {
1720         return (FALSE);
1721     }
1722 
1723     switch (CurrentOp->Common.AmlOpcode)
1724     {
1725         case (AML_LOGICAL_EQUAL_OP):
1726 
1727             /* Next child must be NamePath with string _T_ */
1728 
1729             CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1730             if (!CurrentOp || !CurrentOp->Common.Value.Name ||
1731                 strncmp(CurrentOp->Common.Value.Name, "_T_", 3))
1732             {
1733                 return (FALSE);
1734             }
1735 
1736             break;
1737 
1738         case (AML_LOGICAL_NOT_OP):
1739 
1740             /* Child of LNot must be LEqual op */
1741 
1742             CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1743             if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_LOGICAL_EQUAL_OP))
1744             {
1745                 return (FALSE);
1746             }
1747 
1748             /* Child of LNot must be Match op */
1749 
1750             CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1751             if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_MATCH_OP))
1752             {
1753                 return (FALSE);
1754             }
1755 
1756             /* First child of Match must be Package op */
1757 
1758             CurrentOp = AcpiPsGetArg (CurrentOp, 0);
1759             if (!CurrentOp || (CurrentOp->Common.AmlOpcode != AML_PACKAGE_OP))
1760             {
1761                 return (FALSE);
1762             }
1763 
1764             /* Third child of Match must be NamePath with string _T_ */
1765 
1766             CurrentOp = AcpiPsGetArg (CurrentOp->Common.Parent, 2);
1767             if (!CurrentOp || !CurrentOp->Common.Value.Name ||
1768                 strncmp(CurrentOp->Common.Value.Name, "_T_", 3))
1769             {
1770                 return (FALSE);
1771             }
1772 
1773             break;
1774 
1775         default:
1776 
1777             return (FALSE);
1778     }
1779 
1780     return (TRUE);
1781 }
1782 
1783 #endif  /* ACPI_DISASSEMBLER */
1784