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