2da52ea98e099d379097f3ccce191f90336e1322
[dragonfly.git] / sys / contrib / dev / acpica / source / components / disassembler / dmwalk.c
1 /*******************************************************************************
2  *
3  * Module Name: dmwalk - AML disassembly tree walk
4  *
5  ******************************************************************************/
6
7 /*
8  * Copyright (C) 2000 - 2014, 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
45 #include "acpi.h"
46 #include "accommon.h"
47 #include "acparser.h"
48 #include "amlcode.h"
49 #include "acdisasm.h"
50 #include "acdebug.h"
51
52
53 #ifdef ACPI_DISASSEMBLER
54
55 #define _COMPONENT          ACPI_CA_DEBUGGER
56         ACPI_MODULE_NAME    ("dmwalk")
57
58
59 #define DB_FULL_OP_INFO     "[%4.4s] @%5.5X #%4.4X:  "
60
61 /* Stub for non-compiler code */
62
63 #ifndef ACPI_ASL_COMPILER
64 void
65 AcpiDmEmitExternals (
66     void)
67 {
68     return;
69 }
70 #endif
71
72 /* Local prototypes */
73
74 static ACPI_STATUS
75 AcpiDmDescendingOp (
76     ACPI_PARSE_OBJECT       *Op,
77     UINT32                  Level,
78     void                    *Context);
79
80 static ACPI_STATUS
81 AcpiDmAscendingOp (
82     ACPI_PARSE_OBJECT       *Op,
83     UINT32                  Level,
84     void                    *Context);
85
86 static UINT32
87 AcpiDmBlockType (
88     ACPI_PARSE_OBJECT       *Op);
89
90
91 /*******************************************************************************
92  *
93  * FUNCTION:    AcpiDmDisassemble
94  *
95  * PARAMETERS:  WalkState       - Current state
96  *              Origin          - Starting object
97  *              NumOpcodes      - Max number of opcodes to be displayed
98  *
99  * RETURN:      None
100  *
101  * DESCRIPTION: Disassemble parser object and its children. This is the
102  *              main entry point of the disassembler.
103  *
104  ******************************************************************************/
105
106 void
107 AcpiDmDisassemble (
108     ACPI_WALK_STATE         *WalkState,
109     ACPI_PARSE_OBJECT       *Origin,
110     UINT32                  NumOpcodes)
111 {
112     ACPI_PARSE_OBJECT       *Op = Origin;
113     ACPI_OP_WALK_INFO       Info;
114
115
116     if (!Op)
117     {
118         return;
119     }
120
121     Info.Flags = 0;
122     Info.Level = 0;
123     Info.Count = 0;
124     Info.WalkState = WalkState;
125     AcpiDmWalkParseTree (Op, AcpiDmDescendingOp, AcpiDmAscendingOp, &Info);
126     return;
127 }
128
129
130 /*******************************************************************************
131  *
132  * FUNCTION:    AcpiDmWalkParseTree
133  *
134  * PARAMETERS:  Op                      - Root Op object
135  *              DescendingCallback      - Called during tree descent
136  *              AscendingCallback       - Called during tree ascent
137  *              Context                 - To be passed to the callbacks
138  *
139  * RETURN:      Status from callback(s)
140  *
141  * DESCRIPTION: Walk the entire parse tree.
142  *
143  ******************************************************************************/
144
145 void
146 AcpiDmWalkParseTree (
147     ACPI_PARSE_OBJECT       *Op,
148     ASL_WALK_CALLBACK       DescendingCallback,
149     ASL_WALK_CALLBACK       AscendingCallback,
150     void                    *Context)
151 {
152     BOOLEAN                 NodePreviouslyVisited;
153     ACPI_PARSE_OBJECT       *StartOp = Op;
154     ACPI_STATUS             Status;
155     ACPI_PARSE_OBJECT       *Next;
156     ACPI_OP_WALK_INFO       *Info = Context;
157
158
159     Info->Level = 0;
160     NodePreviouslyVisited = FALSE;
161
162     while (Op)
163     {
164         if (NodePreviouslyVisited)
165         {
166             if (AscendingCallback)
167             {
168                 Status = AscendingCallback (Op, Info->Level, Context);
169                 if (ACPI_FAILURE (Status))
170                 {
171                     return;
172                 }
173             }
174         }
175         else
176         {
177             /* Let the callback process the node */
178
179             Status = DescendingCallback (Op, Info->Level, Context);
180             if (ACPI_SUCCESS (Status))
181             {
182                 /* Visit children first, once */
183
184                 Next = AcpiPsGetArg (Op, 0);
185                 if (Next)
186                 {
187                     Info->Level++;
188                     Op = Next;
189                     continue;
190                 }
191             }
192             else if (Status != AE_CTRL_DEPTH)
193             {
194                 /* Exit immediately on any error */
195
196                 return;
197             }
198         }
199
200         /* Terminate walk at start op */
201
202         if (Op == StartOp)
203         {
204             break;
205         }
206
207         /* No more children, re-visit this node */
208
209         if (!NodePreviouslyVisited)
210         {
211             NodePreviouslyVisited = TRUE;
212             continue;
213         }
214
215         /* No more children, visit peers */
216
217         if (Op->Common.Next)
218         {
219             Op = Op->Common.Next;
220             NodePreviouslyVisited = FALSE;
221         }
222         else
223         {
224             /* No peers, re-visit parent */
225
226             if (Info->Level != 0 )
227             {
228                 Info->Level--;
229             }
230
231             Op = Op->Common.Parent;
232             NodePreviouslyVisited = TRUE;
233         }
234     }
235
236     /* If we get here, the walk completed with no errors */
237
238     return;
239 }
240
241
242 /*******************************************************************************
243  *
244  * FUNCTION:    AcpiDmBlockType
245  *
246  * PARAMETERS:  Op              - Object to be examined
247  *
248  * RETURN:      BlockType - not a block, parens, braces, or even both.
249  *
250  * DESCRIPTION: Type of block for this op (parens or braces)
251  *
252  ******************************************************************************/
253
254 static UINT32
255 AcpiDmBlockType (
256     ACPI_PARSE_OBJECT       *Op)
257 {
258     const ACPI_OPCODE_INFO  *OpInfo;
259
260
261     if (!Op)
262     {
263         return (BLOCK_NONE);
264     }
265
266     switch (Op->Common.AmlOpcode)
267     {
268     case AML_ELSE_OP:
269
270         return (BLOCK_BRACE);
271
272     case AML_METHOD_OP:
273     case AML_DEVICE_OP:
274     case AML_SCOPE_OP:
275     case AML_PROCESSOR_OP:
276     case AML_POWER_RES_OP:
277     case AML_THERMAL_ZONE_OP:
278     case AML_IF_OP:
279     case AML_WHILE_OP:
280     case AML_FIELD_OP:
281     case AML_INDEX_FIELD_OP:
282     case AML_BANK_FIELD_OP:
283
284         return (BLOCK_PAREN | BLOCK_BRACE);
285
286     case AML_BUFFER_OP:
287
288         if ((Op->Common.DisasmOpcode == ACPI_DASM_UNICODE) ||
289             (Op->Common.DisasmOpcode == ACPI_DASM_UUID))
290         {
291             return (BLOCK_NONE);
292         }
293
294         /*lint -fallthrough */
295
296     case AML_PACKAGE_OP:
297     case AML_VAR_PACKAGE_OP:
298
299         return (BLOCK_PAREN | BLOCK_BRACE);
300
301     case AML_EVENT_OP:
302
303         return (BLOCK_PAREN);
304
305     default:
306
307         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
308         if (OpInfo->Flags & AML_HAS_ARGS)
309         {
310             return (BLOCK_PAREN);
311         }
312
313         return (BLOCK_NONE);
314     }
315 }
316
317
318 /*******************************************************************************
319  *
320  * FUNCTION:    AcpiDmListType
321  *
322  * PARAMETERS:  Op              - Object to be examined
323  *
324  * RETURN:      ListType - has commas or not.
325  *
326  * DESCRIPTION: Type of block for this op (parens or braces)
327  *
328  ******************************************************************************/
329
330 UINT32
331 AcpiDmListType (
332     ACPI_PARSE_OBJECT       *Op)
333 {
334     const ACPI_OPCODE_INFO  *OpInfo;
335
336
337     if (!Op)
338     {
339         return (BLOCK_NONE);
340     }
341
342     switch (Op->Common.AmlOpcode)
343     {
344
345     case AML_ELSE_OP:
346     case AML_METHOD_OP:
347     case AML_DEVICE_OP:
348     case AML_SCOPE_OP:
349     case AML_POWER_RES_OP:
350     case AML_PROCESSOR_OP:
351     case AML_THERMAL_ZONE_OP:
352     case AML_IF_OP:
353     case AML_WHILE_OP:
354     case AML_FIELD_OP:
355     case AML_INDEX_FIELD_OP:
356     case AML_BANK_FIELD_OP:
357
358         return (BLOCK_NONE);
359
360     case AML_BUFFER_OP:
361     case AML_PACKAGE_OP:
362     case AML_VAR_PACKAGE_OP:
363
364         return (BLOCK_COMMA_LIST);
365
366     default:
367
368         OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
369         if (OpInfo->Flags & AML_HAS_ARGS)
370         {
371             return (BLOCK_COMMA_LIST);
372         }
373
374         return (BLOCK_NONE);
375     }
376 }
377
378
379 /*******************************************************************************
380  *
381  * FUNCTION:    AcpiDmDescendingOp
382  *
383  * PARAMETERS:  ASL_WALK_CALLBACK
384  *
385  * RETURN:      Status
386  *
387  * DESCRIPTION: First visitation of a parse object during tree descent.
388  *              Decode opcode name and begin parameter list(s), if any.
389  *
390  ******************************************************************************/
391
392 static ACPI_STATUS
393 AcpiDmDescendingOp (
394     ACPI_PARSE_OBJECT       *Op,
395     UINT32                  Level,
396     void                    *Context)
397 {
398     ACPI_OP_WALK_INFO       *Info = Context;
399     const ACPI_OPCODE_INFO  *OpInfo;
400     UINT32                  Name;
401     ACPI_PARSE_OBJECT       *NextOp;
402
403
404     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
405     {
406         /* Ignore this op -- it was handled elsewhere */
407
408         return (AE_CTRL_DEPTH);
409     }
410
411     /* Level 0 is at the Definition Block level */
412
413     if (Level == 0)
414     {
415         /* In verbose mode, print the AML offset, opcode and depth count */
416
417         if (Info->WalkState)
418         {
419             VERBOSE_PRINT ((DB_FULL_OP_INFO,
420                 (Info->WalkState->MethodNode ?
421                     Info->WalkState->MethodNode->Name.Ascii : "   "),
422                 Op->Common.AmlOffset, (UINT32) Op->Common.AmlOpcode));
423         }
424
425         if (Op->Common.AmlOpcode == AML_SCOPE_OP)
426         {
427             /* This is the beginning of the Definition Block */
428
429             AcpiOsPrintf ("{\n");
430
431             /* Emit all External() declarations here */
432
433             AcpiDmEmitExternals ();
434             return (AE_OK);
435         }
436     }
437     else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
438              (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
439              (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
440     {
441             /*
442              * This is a first-level element of a term list,
443              * indent a new line
444              */
445             switch (Op->Common.AmlOpcode)
446             {
447             case AML_NOOP_OP:
448                 /*
449                  * Optionally just ignore this opcode. Some tables use
450                  * NoOp opcodes for "padding" out packages that the BIOS
451                  * changes dynamically. This can leave hundreds or
452                  * thousands of NoOp opcodes that if disassembled,
453                  * cannot be compiled because they are syntactically
454                  * incorrect.
455                  */
456                 if (AcpiGbl_IgnoreNoopOperator)
457                 {
458                     Op->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
459                     return (AE_OK);
460                 }
461
462                 /* Fallthrough */
463
464             default:
465
466                 AcpiDmIndent (Level);
467                 break;
468             }
469
470             Info->LastLevel = Level;
471             Info->Count = 0;
472     }
473
474     /*
475      * This is an inexpensive mechanism to try and keep lines from getting
476      * too long. When the limit is hit, start a new line at the previous
477      * indent plus one. A better but more expensive mechanism would be to
478      * keep track of the current column.
479      */
480     Info->Count++;
481     if (Info->Count /* +Info->LastLevel */ > 10)
482     {
483         Info->Count = 0;
484         AcpiOsPrintf ("\n");
485         AcpiDmIndent (Info->LastLevel + 1);
486     }
487
488     /* Print the opcode name */
489
490     AcpiDmDisassembleOneOp (NULL, Info, Op);
491
492     if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
493         (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
494     {
495         return (AE_OK);
496     }
497
498     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
499         (Op->Common.AmlOpcode == AML_RETURN_OP))
500     {
501         Info->Level--;
502     }
503
504     /* Start the opcode argument list if necessary */
505
506     OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
507
508     if ((OpInfo->Flags & AML_HAS_ARGS) ||
509         (Op->Common.AmlOpcode == AML_EVENT_OP))
510     {
511         /* This opcode has an argument list */
512
513         if (AcpiDmBlockType (Op) & BLOCK_PAREN)
514         {
515             AcpiOsPrintf (" (");
516         }
517
518         /* If this is a named opcode, print the associated name value */
519
520         if (OpInfo->Flags & AML_NAMED)
521         {
522             switch (Op->Common.AmlOpcode)
523             {
524             case AML_ALIAS_OP:
525
526                 NextOp = AcpiPsGetDepthNext (NULL, Op);
527                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
528                 AcpiDmNamestring (NextOp->Common.Value.Name);
529                 AcpiOsPrintf (", ");
530
531                 /*lint -fallthrough */
532
533             default:
534
535                 Name = AcpiPsGetName (Op);
536                 if (Op->Named.Path)
537                 {
538                     AcpiDmNamestring ((char *) Op->Named.Path);
539                 }
540                 else
541                 {
542                     AcpiDmDumpName (Name);
543                 }
544
545                 if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
546                 {
547                     if (AcpiGbl_DbOpt_verbose)
548                     {
549                         (void) AcpiPsDisplayObjectPathname (NULL, Op);
550                     }
551                 }
552                 break;
553             }
554
555             switch (Op->Common.AmlOpcode)
556             {
557             case AML_METHOD_OP:
558
559                 AcpiDmMethodFlags (Op);
560                 AcpiOsPrintf (")");
561
562                 /* Emit description comment for Method() with a predefined ACPI name */
563
564                 AcpiDmPredefinedDescription (Op);
565                 break;
566
567
568             case AML_NAME_OP:
569
570                 /* Check for _HID and related EISAID() */
571
572                 AcpiDmCheckForHardwareId (Op);
573                 AcpiOsPrintf (", ");
574                 break;
575
576
577             case AML_REGION_OP:
578
579                 AcpiDmRegionFlags (Op);
580                 break;
581
582
583             case AML_POWER_RES_OP:
584
585                 /* Mark the next two Ops as part of the parameter list */
586
587                 AcpiOsPrintf (", ");
588                 NextOp = AcpiPsGetDepthNext (NULL, Op);
589                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
590
591                 NextOp = NextOp->Common.Next;
592                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
593                 return (AE_OK);
594
595
596             case AML_PROCESSOR_OP:
597
598                 /* Mark the next three Ops as part of the parameter list */
599
600                 AcpiOsPrintf (", ");
601                 NextOp = AcpiPsGetDepthNext (NULL, Op);
602                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
603
604                 NextOp = NextOp->Common.Next;
605                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
606
607                 NextOp = NextOp->Common.Next;
608                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
609                 return (AE_OK);
610
611
612             case AML_MUTEX_OP:
613             case AML_DATA_REGION_OP:
614
615                 AcpiOsPrintf (", ");
616                 return (AE_OK);
617
618
619             case AML_EVENT_OP:
620             case AML_ALIAS_OP:
621
622                 return (AE_OK);
623
624
625             case AML_SCOPE_OP:
626             case AML_DEVICE_OP:
627             case AML_THERMAL_ZONE_OP:
628
629                 AcpiOsPrintf (")");
630                 break;
631
632
633             default:
634
635                 AcpiOsPrintf ("*** Unhandled named opcode %X\n",
636                     Op->Common.AmlOpcode);
637                 break;
638             }
639         }
640
641         else switch (Op->Common.AmlOpcode)
642         {
643         case AML_FIELD_OP:
644         case AML_BANK_FIELD_OP:
645         case AML_INDEX_FIELD_OP:
646
647             Info->BitOffset = 0;
648
649             /* Name of the parent OperationRegion */
650
651             NextOp = AcpiPsGetDepthNext (NULL, Op);
652             AcpiDmNamestring (NextOp->Common.Value.Name);
653             AcpiOsPrintf (", ");
654             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
655
656             switch (Op->Common.AmlOpcode)
657             {
658             case AML_BANK_FIELD_OP:
659
660                 /* Namestring - Bank Name */
661
662                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
663                 AcpiDmNamestring (NextOp->Common.Value.Name);
664                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
665                 AcpiOsPrintf (", ");
666
667                 /*
668                  * Bank Value. This is a TermArg in the middle of the parameter
669                  * list, must handle it here.
670                  *
671                  * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMLIST
672                  * eliminates newline in the output.
673                  */
674                 NextOp = NextOp->Common.Next;
675
676                 Info->Flags = ACPI_PARSEOP_PARAMLIST;
677                 AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp,
678                     AcpiDmAscendingOp, Info);
679                 Info->Flags = 0;
680                 Info->Level = Level;
681
682                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
683                 AcpiOsPrintf (", ");
684                 break;
685
686             case AML_INDEX_FIELD_OP:
687
688                 /* Namestring - Data Name */
689
690                 NextOp = AcpiPsGetDepthNext (NULL, NextOp);
691                 AcpiDmNamestring (NextOp->Common.Value.Name);
692                 AcpiOsPrintf (", ");
693                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
694                 break;
695
696             default:
697
698                 break;
699             }
700
701             AcpiDmFieldFlags (NextOp);
702             break;
703
704         case AML_BUFFER_OP:
705
706             /* The next op is the size parameter */
707
708             NextOp = AcpiPsGetDepthNext (NULL, Op);
709             if (!NextOp)
710             {
711                 /* Single-step support */
712
713                 return (AE_OK);
714             }
715
716             if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
717             {
718                 /*
719                  * We have a resource list. Don't need to output
720                  * the buffer size Op. Open up a new block
721                  */
722                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
723                 NextOp = NextOp->Common.Next;
724                 AcpiOsPrintf (")");
725
726                 /* Emit description comment for Name() with a predefined ACPI name */
727
728                 AcpiDmPredefinedDescription (Op->Asl.Parent);
729
730                 AcpiOsPrintf ("\n");
731                 AcpiDmIndent (Info->Level);
732                 AcpiOsPrintf ("{\n");
733                 return (AE_OK);
734             }
735
736             /* Normal Buffer, mark size as in the parameter list */
737
738             NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
739             return (AE_OK);
740
741         case AML_VAR_PACKAGE_OP:
742         case AML_IF_OP:
743         case AML_WHILE_OP:
744
745             /* The next op is the size or predicate parameter */
746
747             NextOp = AcpiPsGetDepthNext (NULL, Op);
748             if (NextOp)
749             {
750                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
751             }
752             return (AE_OK);
753
754         case AML_PACKAGE_OP:
755
756             /* The next op is the size parameter */
757
758             NextOp = AcpiPsGetDepthNext (NULL, Op);
759             if (NextOp)
760             {
761                 NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
762             }
763             return (AE_OK);
764
765         case AML_MATCH_OP:
766
767             AcpiDmMatchOp (Op);
768             break;
769
770         default:
771
772             break;
773         }
774
775         if (AcpiDmBlockType (Op) & BLOCK_BRACE)
776         {
777             AcpiOsPrintf ("\n");
778             AcpiDmIndent (Level);
779             AcpiOsPrintf ("{\n");
780         }
781     }
782
783     return (AE_OK);
784 }
785
786
787 /*******************************************************************************
788  *
789  * FUNCTION:    AcpiDmAscendingOp
790  *
791  * PARAMETERS:  ASL_WALK_CALLBACK
792  *
793  * RETURN:      Status
794  *
795  * DESCRIPTION: Second visitation of a parse object, during ascent of parse
796  *              tree. Close out any parameter lists and complete the opcode.
797  *
798  ******************************************************************************/
799
800 static ACPI_STATUS
801 AcpiDmAscendingOp (
802     ACPI_PARSE_OBJECT       *Op,
803     UINT32                  Level,
804     void                    *Context)
805 {
806     ACPI_OP_WALK_INFO       *Info = Context;
807     ACPI_PARSE_OBJECT       *ParentOp;
808
809
810     if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
811     {
812         /* Ignore this op -- it was handled elsewhere */
813
814         return (AE_OK);
815     }
816
817     if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
818     {
819         /* Indicates the end of the current descriptor block (table) */
820
821         AcpiOsPrintf ("}\n\n");
822         return (AE_OK);
823     }
824
825     switch (AcpiDmBlockType (Op))
826     {
827     case BLOCK_PAREN:
828
829         /* Completed an op that has arguments, add closing paren */
830
831         AcpiOsPrintf (")");
832
833         if (Op->Common.AmlOpcode == AML_NAME_OP)
834         {
835             /* Emit description comment for Name() with a predefined ACPI name */
836
837             AcpiDmPredefinedDescription (Op);
838         }
839         else
840         {
841             /* For Create* operators, attempt to emit resource tag description */
842
843             AcpiDmFieldPredefinedDescription (Op);
844         }
845
846         /* Decode Notify() values */
847
848         if (Op->Common.AmlOpcode == AML_NOTIFY_OP)
849         {
850             AcpiDmNotifyDescription (Op);
851         }
852
853         AcpiDmDisplayTargetPathname (Op);
854
855         /* Could be a nested operator, check if comma required */
856
857         if (!AcpiDmCommaIfListMember (Op))
858         {
859             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
860                      (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
861                      (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
862             {
863                 /*
864                  * This is a first-level element of a term list
865                  * start a new line
866                  */
867                 if (!(Info->Flags & ACPI_PARSEOP_PARAMLIST))
868                 {
869                     AcpiOsPrintf ("\n");
870                 }
871             }
872         }
873         break;
874
875     case BLOCK_BRACE:
876     case (BLOCK_BRACE | BLOCK_PAREN):
877
878         /* Completed an op that has a term list, add closing brace */
879
880         if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
881         {
882             AcpiOsPrintf ("}");
883         }
884         else
885         {
886             AcpiDmIndent (Level);
887             AcpiOsPrintf ("}");
888         }
889
890         AcpiDmCommaIfListMember (Op);
891
892         if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
893         {
894             AcpiOsPrintf ("\n");
895             if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
896             {
897                 if ((Op->Common.AmlOpcode == AML_IF_OP)  &&
898                     (Op->Common.Next) &&
899                     (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
900                 {
901                     break;
902                 }
903
904                 if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
905                     (!Op->Common.Next))
906                 {
907                     break;
908                 }
909                 AcpiOsPrintf ("\n");
910             }
911         }
912         break;
913
914     case BLOCK_NONE:
915     default:
916
917         /* Could be a nested operator, check if comma required */
918
919         if (!AcpiDmCommaIfListMember (Op))
920         {
921             if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
922                      (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
923                      (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
924             {
925                 /*
926                  * This is a first-level element of a term list
927                  * start a new line
928                  */
929                 AcpiOsPrintf ("\n");
930             }
931         }
932         else if (Op->Common.Parent)
933         {
934             switch (Op->Common.Parent->Common.AmlOpcode)
935             {
936             case AML_PACKAGE_OP:
937             case AML_VAR_PACKAGE_OP:
938
939                 if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
940                 {
941                     AcpiOsPrintf ("\n");
942                 }
943                 break;
944
945             default:
946
947                 break;
948             }
949         }
950         break;
951     }
952
953     if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)
954     {
955         if ((Op->Common.Next) &&
956             (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
957         {
958             return (AE_OK);
959         }
960
961         /*
962          * The parent Op is guaranteed to be valid because of the flag
963          * ACPI_PARSEOP_PARAMLIST -- which means that this op is part of
964          * a parameter list and thus has a valid parent.
965          */
966         ParentOp = Op->Common.Parent;
967
968         /*
969          * Just completed a parameter node for something like "Buffer (param)".
970          * Close the paren and open up the term list block with a brace
971          */
972         if (Op->Common.Next)
973         {
974             AcpiOsPrintf (")");
975
976             /*
977              * Emit a description comment for a Name() operator that is a
978              * predefined ACPI name. Must check the grandparent.
979              */
980             ParentOp = ParentOp->Common.Parent;
981             if (ParentOp &&
982                 (ParentOp->Asl.AmlOpcode == AML_NAME_OP))
983             {
984                 AcpiDmPredefinedDescription (ParentOp);
985             }
986
987             AcpiOsPrintf ("\n");
988             AcpiDmIndent (Level - 1);
989             AcpiOsPrintf ("{\n");
990         }
991         else
992         {
993             ParentOp->Common.DisasmFlags |= ACPI_PARSEOP_EMPTY_TERMLIST;
994             AcpiOsPrintf (") {");
995         }
996     }
997
998     if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
999         (Op->Common.AmlOpcode == AML_RETURN_OP))
1000     {
1001         Info->Level++;
1002     }
1003     return (AE_OK);
1004 }
1005
1006
1007 #endif  /* ACPI_DISASSEMBLER */