dmopcode.c revision 1.1.1.10.2.1 1 /*******************************************************************************
2 *
3 * Module Name: dmopcode - AML disassembler, specific AML opcodes
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2017, 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
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 }
1648