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