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