dmwalk.c revision 228110
12786Ssos/*******************************************************************************
22786Ssos *
32786Ssos * Module Name: dmwalk - AML disassembly tree walk
42786Ssos *
52786Ssos ******************************************************************************/
62786Ssos
72786Ssos/*
82786Ssos * Copyright (C) 2000 - 2011, Intel Corp.
92786Ssos * All rights reserved.
102786Ssos *
112786Ssos * Redistribution and use in source and binary forms, with or without
122786Ssos * modification, are permitted provided that the following conditions
132786Ssos * are met:
142786Ssos * 1. Redistributions of source code must retain the above copyright
152786Ssos *    notice, this list of conditions, and the following disclaimer,
162786Ssos *    without modification.
172786Ssos * 2. Redistributions in binary form must reproduce at minimum a disclaimer
182786Ssos *    substantially similar to the "NO WARRANTY" disclaimer below
192786Ssos *    ("Disclaimer") and any redistribution must be conditioned upon
202786Ssos *    including a substantially similar Disclaimer requirement for further
212786Ssos *    binary redistribution.
222786Ssos * 3. Neither the names of the above-listed copyright holders nor the names
232786Ssos *    of any contributors may be used to endorse or promote products derived
242786Ssos *    from this software without specific prior written permission.
252786Ssos *
262786Ssos * Alternatively, this software may be distributed under the terms of the
272786Ssos * GNU General Public License ("GPL") version 2 as published by the Free
282786Ssos * Software Foundation.
292786Ssos *
302786Ssos * NO WARRANTY
312786Ssos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
322786Ssos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
332786Ssos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
342786Ssos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
352786Ssos * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
362786Ssos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
372786Ssos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
382786Ssos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
392786Ssos * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
402786Ssos * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
412786Ssos * POSSIBILITY OF SUCH DAMAGES.
422786Ssos */
432786Ssos
442786Ssos
452786Ssos#include <contrib/dev/acpica/include/acpi.h>
462786Ssos#include <contrib/dev/acpica/include/accommon.h>
472786Ssos#include <contrib/dev/acpica/include/acparser.h>
482786Ssos#include <contrib/dev/acpica/include/amlcode.h>
492786Ssos#include <contrib/dev/acpica/include/acdisasm.h>
502786Ssos#include <contrib/dev/acpica/include/acdebug.h>
512786Ssos
522786Ssos
532786Ssos#ifdef ACPI_DISASSEMBLER
542786Ssos
552786Ssos#define _COMPONENT          ACPI_CA_DEBUGGER
562786Ssos        ACPI_MODULE_NAME    ("dmwalk")
572786Ssos
582786Ssos
592786Ssos#define DB_FULL_OP_INFO     "[%4.4s] @%5.5X #%4.4X:  "
602786Ssos
612786Ssos/* Stub for non-compiler code */
622786Ssos
632786Ssos#ifndef ACPI_ASL_COMPILER
642786Ssosvoid
652786SsosAcpiDmEmitExternals (
662786Ssos    void)
672786Ssos{
682786Ssos    return;
692786Ssos}
702786Ssos#endif
712786Ssos
722786Ssos/* Local prototypes */
732786Ssos
742786Ssosstatic ACPI_STATUS
752786SsosAcpiDmDescendingOp (
762786Ssos    ACPI_PARSE_OBJECT       *Op,
772786Ssos    UINT32                  Level,
782786Ssos    void                    *Context);
792786Ssos
802786Ssosstatic ACPI_STATUS
812786SsosAcpiDmAscendingOp (
822786Ssos    ACPI_PARSE_OBJECT       *Op,
832786Ssos    UINT32                  Level,
842786Ssos    void                    *Context);
852786Ssos
862786Ssosstatic UINT32
872786SsosAcpiDmBlockType (
882786Ssos    ACPI_PARSE_OBJECT       *Op);
892786Ssos
902786Ssos
912786Ssos/*******************************************************************************
922786Ssos *
932786Ssos * FUNCTION:    AcpiDmDisassemble
942786Ssos *
952786Ssos * PARAMETERS:  WalkState       - Current state
962786Ssos *              Origin          - Starting object
972786Ssos *              NumOpcodes      - Max number of opcodes to be displayed
982786Ssos *
992786Ssos * RETURN:      None
1002786Ssos *
1012786Ssos * DESCRIPTION: Disassemble parser object and its children.  This is the
1022786Ssos *              main entry point of the disassembler.
1032786Ssos *
1042786Ssos ******************************************************************************/
1052786Ssos
1062786Ssosvoid
1072786SsosAcpiDmDisassemble (
1082786Ssos    ACPI_WALK_STATE         *WalkState,
1092786Ssos    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
145void
146AcpiDmWalkParseTree (
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
254static UINT32
255AcpiDmBlockType (
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        {
290            return (BLOCK_NONE);
291        }
292
293        /*lint -fallthrough */
294
295    case AML_PACKAGE_OP:
296    case AML_VAR_PACKAGE_OP:
297
298        return (BLOCK_PAREN | BLOCK_BRACE);
299
300    case AML_EVENT_OP:
301
302        return (BLOCK_PAREN);
303
304    default:
305
306        OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
307        if (OpInfo->Flags & AML_HAS_ARGS)
308        {
309            return (BLOCK_PAREN);
310        }
311
312        return (BLOCK_NONE);
313    }
314}
315
316
317/*******************************************************************************
318 *
319 * FUNCTION:    AcpiDmListType
320 *
321 * PARAMETERS:  Op              - Object to be examined
322 *
323 * RETURN:      ListType - has commas or not.
324 *
325 * DESCRIPTION: Type of block for this op (parens or braces)
326 *
327 ******************************************************************************/
328
329UINT32
330AcpiDmListType (
331    ACPI_PARSE_OBJECT       *Op)
332{
333    const ACPI_OPCODE_INFO  *OpInfo;
334
335
336    if (!Op)
337    {
338        return (BLOCK_NONE);
339    }
340
341    switch (Op->Common.AmlOpcode)
342    {
343
344    case AML_ELSE_OP:
345    case AML_METHOD_OP:
346    case AML_DEVICE_OP:
347    case AML_SCOPE_OP:
348    case AML_POWER_RES_OP:
349    case AML_PROCESSOR_OP:
350    case AML_THERMAL_ZONE_OP:
351    case AML_IF_OP:
352    case AML_WHILE_OP:
353    case AML_FIELD_OP:
354    case AML_INDEX_FIELD_OP:
355    case AML_BANK_FIELD_OP:
356
357        return (BLOCK_NONE);
358
359    case AML_BUFFER_OP:
360    case AML_PACKAGE_OP:
361    case AML_VAR_PACKAGE_OP:
362
363        return (BLOCK_COMMA_LIST);
364
365    default:
366
367        OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
368        if (OpInfo->Flags & AML_HAS_ARGS)
369        {
370            return (BLOCK_COMMA_LIST);
371        }
372
373        return (BLOCK_NONE);
374    }
375}
376
377
378/*******************************************************************************
379 *
380 * FUNCTION:    AcpiDmDescendingOp
381 *
382 * PARAMETERS:  ASL_WALK_CALLBACK
383 *
384 * RETURN:      Status
385 *
386 * DESCRIPTION: First visitation of a parse object during tree descent.
387 *              Decode opcode name and begin parameter list(s), if any.
388 *
389 ******************************************************************************/
390
391static ACPI_STATUS
392AcpiDmDescendingOp (
393    ACPI_PARSE_OBJECT       *Op,
394    UINT32                  Level,
395    void                    *Context)
396{
397    ACPI_OP_WALK_INFO       *Info = Context;
398    const ACPI_OPCODE_INFO  *OpInfo;
399    UINT32                  Name;
400    ACPI_PARSE_OBJECT       *NextOp;
401
402
403    if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
404    {
405        /* Ignore this op -- it was handled elsewhere */
406
407        return (AE_CTRL_DEPTH);
408    }
409
410    /* Level 0 is at the Definition Block level */
411
412    if (Level == 0)
413    {
414        /* In verbose mode, print the AML offset, opcode and depth count */
415
416        if (Info->WalkState)
417        {
418            VERBOSE_PRINT ((DB_FULL_OP_INFO,
419                (Info->WalkState->MethodNode ?
420                    Info->WalkState->MethodNode->Name.Ascii : "   "),
421                Op->Common.AmlOffset, (UINT32) Op->Common.AmlOpcode));
422        }
423
424        if (Op->Common.AmlOpcode == AML_SCOPE_OP)
425        {
426            /* This is the beginning of the Definition Block */
427
428            AcpiOsPrintf ("{\n");
429
430            /* Emit all External() declarations here */
431
432            AcpiDmEmitExternals ();
433            return (AE_OK);
434        }
435    }
436    else if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
437             (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
438             (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
439    {
440            /*
441             * This is a first-level element of a term list,
442             * indent a new line
443             */
444            AcpiDmIndent (Level);
445            Info->LastLevel = Level;
446            Info->Count = 0;
447    }
448
449    /*
450     * This is an inexpensive mechanism to try and keep lines from getting
451     * too long. When the limit is hit, start a new line at the previous
452     * indent plus one. A better but more expensive mechanism would be to
453     * keep track of the current column.
454     */
455    Info->Count++;
456    if (Info->Count /*+Info->LastLevel*/ > 10)
457    {
458        Info->Count = 0;
459        AcpiOsPrintf ("\n");
460        AcpiDmIndent (Info->LastLevel + 1);
461    }
462
463    /* Print the opcode name */
464
465    AcpiDmDisassembleOneOp (NULL, Info, Op);
466
467    if ((Op->Common.DisasmOpcode == ACPI_DASM_LNOT_PREFIX) ||
468        (Op->Common.AmlOpcode == AML_INT_CONNECTION_OP))
469    {
470        return (AE_OK);
471    }
472
473    if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
474        (Op->Common.AmlOpcode == AML_RETURN_OP))
475    {
476        Info->Level--;
477    }
478
479    /* Start the opcode argument list if necessary */
480
481    OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
482
483    if ((OpInfo->Flags & AML_HAS_ARGS) ||
484        (Op->Common.AmlOpcode == AML_EVENT_OP))
485    {
486        /* This opcode has an argument list */
487
488        if (AcpiDmBlockType (Op) & BLOCK_PAREN)
489        {
490            AcpiOsPrintf (" (");
491        }
492
493        /* If this is a named opcode, print the associated name value */
494
495        if (OpInfo->Flags & AML_NAMED)
496        {
497            switch (Op->Common.AmlOpcode)
498            {
499            case AML_ALIAS_OP:
500
501                NextOp = AcpiPsGetDepthNext (NULL, Op);
502                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
503                AcpiDmNamestring (NextOp->Common.Value.Name);
504                AcpiOsPrintf (", ");
505
506                /*lint -fallthrough */
507
508            default:
509
510                Name = AcpiPsGetName (Op);
511                if (Op->Named.Path)
512                {
513                    AcpiDmNamestring ((char *) Op->Named.Path);
514                }
515                else
516                {
517                    AcpiDmDumpName (Name);
518                }
519
520                if (Op->Common.AmlOpcode != AML_INT_NAMEDFIELD_OP)
521                {
522                    if (AcpiGbl_DbOpt_verbose)
523                    {
524                        (void) AcpiPsDisplayObjectPathname (NULL, Op);
525                    }
526                }
527                break;
528            }
529
530            switch (Op->Common.AmlOpcode)
531            {
532            case AML_METHOD_OP:
533
534                AcpiDmMethodFlags (Op);
535                AcpiOsPrintf (")");
536                break;
537
538
539            case AML_NAME_OP:
540
541                /* Check for _HID and related EISAID() */
542
543                AcpiDmIsEisaId (Op);
544                AcpiOsPrintf (", ");
545                break;
546
547
548            case AML_REGION_OP:
549
550                AcpiDmRegionFlags (Op);
551                break;
552
553
554            case AML_POWER_RES_OP:
555
556                /* Mark the next two Ops as part of the parameter list */
557
558                AcpiOsPrintf (", ");
559                NextOp = AcpiPsGetDepthNext (NULL, Op);
560                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
561
562                NextOp = NextOp->Common.Next;
563                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
564                return (AE_OK);
565
566
567            case AML_PROCESSOR_OP:
568
569                /* Mark the next three Ops as part of the parameter list */
570
571                AcpiOsPrintf (", ");
572                NextOp = AcpiPsGetDepthNext (NULL, Op);
573                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
574
575                NextOp = NextOp->Common.Next;
576                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
577
578                NextOp = NextOp->Common.Next;
579                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
580                return (AE_OK);
581
582
583            case AML_MUTEX_OP:
584            case AML_DATA_REGION_OP:
585
586                AcpiOsPrintf (", ");
587                return (AE_OK);
588
589
590            case AML_EVENT_OP:
591            case AML_ALIAS_OP:
592
593                return (AE_OK);
594
595
596            case AML_SCOPE_OP:
597            case AML_DEVICE_OP:
598            case AML_THERMAL_ZONE_OP:
599
600                AcpiOsPrintf (")");
601                break;
602
603
604            default:
605
606                AcpiOsPrintf ("*** Unhandled named opcode %X\n", Op->Common.AmlOpcode);
607                break;
608            }
609        }
610
611        else switch (Op->Common.AmlOpcode)
612        {
613        case AML_FIELD_OP:
614        case AML_BANK_FIELD_OP:
615        case AML_INDEX_FIELD_OP:
616
617            Info->BitOffset = 0;
618
619            /* Name of the parent OperationRegion */
620
621            NextOp = AcpiPsGetDepthNext (NULL, Op);
622            AcpiDmNamestring (NextOp->Common.Value.Name);
623            AcpiOsPrintf (", ");
624            NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
625
626            switch (Op->Common.AmlOpcode)
627            {
628            case AML_BANK_FIELD_OP:
629
630                /* Namestring - Bank Name */
631
632                NextOp = AcpiPsGetDepthNext (NULL, NextOp);
633                AcpiDmNamestring (NextOp->Common.Value.Name);
634                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
635                AcpiOsPrintf (", ");
636
637                /*
638                 * Bank Value. This is a TermArg in the middle of the parameter
639                 * list, must handle it here.
640                 *
641                 * Disassemble the TermArg parse tree. ACPI_PARSEOP_PARAMLIST
642                 * eliminates newline in the output.
643                 */
644                NextOp = NextOp->Common.Next;
645
646                Info->Flags = ACPI_PARSEOP_PARAMLIST;
647                AcpiDmWalkParseTree (NextOp, AcpiDmDescendingOp, AcpiDmAscendingOp, Info);
648                Info->Flags = 0;
649                Info->Level = Level;
650
651                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
652                AcpiOsPrintf (", ");
653                break;
654
655            case AML_INDEX_FIELD_OP:
656
657                /* Namestring - Data Name */
658
659                NextOp = AcpiPsGetDepthNext (NULL, NextOp);
660                AcpiDmNamestring (NextOp->Common.Value.Name);
661                AcpiOsPrintf (", ");
662                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
663                break;
664
665            default:
666
667                break;
668            }
669
670            AcpiDmFieldFlags (NextOp);
671            break;
672
673
674        case AML_BUFFER_OP:
675
676            /* The next op is the size parameter */
677
678            NextOp = AcpiPsGetDepthNext (NULL, Op);
679            if (!NextOp)
680            {
681                /* Single-step support */
682
683                return (AE_OK);
684            }
685
686            if (Op->Common.DisasmOpcode == ACPI_DASM_RESOURCE)
687            {
688                /*
689                 * We have a resource list.  Don't need to output
690                 * the buffer size Op.  Open up a new block
691                 */
692                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
693                NextOp = NextOp->Common.Next;
694                AcpiOsPrintf (")\n");
695                AcpiDmIndent (Info->Level);
696                AcpiOsPrintf ("{\n");
697                return (AE_OK);
698            }
699
700            /* Normal Buffer, mark size as in the parameter list */
701
702            NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
703            return (AE_OK);
704
705
706        case AML_VAR_PACKAGE_OP:
707        case AML_IF_OP:
708        case AML_WHILE_OP:
709
710            /* The next op is the size or predicate parameter */
711
712            NextOp = AcpiPsGetDepthNext (NULL, Op);
713            if (NextOp)
714            {
715                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
716            }
717            return (AE_OK);
718
719
720        case AML_PACKAGE_OP:
721
722            /* The next op is the size or predicate parameter */
723
724            NextOp = AcpiPsGetDepthNext (NULL, Op);
725            if (NextOp)
726            {
727                NextOp->Common.DisasmFlags |= ACPI_PARSEOP_PARAMLIST;
728            }
729            return (AE_OK);
730
731
732        case AML_MATCH_OP:
733
734            AcpiDmMatchOp (Op);
735            break;
736
737
738        default:
739
740            break;
741        }
742
743        if (AcpiDmBlockType (Op) & BLOCK_BRACE)
744        {
745            AcpiOsPrintf ("\n");
746            AcpiDmIndent (Level);
747            AcpiOsPrintf ("{\n");
748        }
749    }
750
751    return (AE_OK);
752}
753
754
755/*******************************************************************************
756 *
757 * FUNCTION:    AcpiDmAscendingOp
758 *
759 * PARAMETERS:  ASL_WALK_CALLBACK
760 *
761 * RETURN:      Status
762 *
763 * DESCRIPTION: Second visitation of a parse object, during ascent of parse
764 *              tree.  Close out any parameter lists and complete the opcode.
765 *
766 ******************************************************************************/
767
768static ACPI_STATUS
769AcpiDmAscendingOp (
770    ACPI_PARSE_OBJECT       *Op,
771    UINT32                  Level,
772    void                    *Context)
773{
774    ACPI_OP_WALK_INFO       *Info = Context;
775
776
777    if (Op->Common.DisasmFlags & ACPI_PARSEOP_IGNORE)
778    {
779        /* Ignore this op -- it was handled elsewhere */
780
781        return (AE_OK);
782    }
783
784    if ((Level == 0) && (Op->Common.AmlOpcode == AML_SCOPE_OP))
785    {
786        /* Indicates the end of the current descriptor block (table) */
787
788        AcpiOsPrintf ("}\n\n");
789        return (AE_OK);
790    }
791
792    switch (AcpiDmBlockType (Op))
793    {
794    case BLOCK_PAREN:
795
796        /* Completed an op that has arguments, add closing paren */
797
798        AcpiOsPrintf (")");
799
800        /* Could be a nested operator, check if comma required */
801
802        if (!AcpiDmCommaIfListMember (Op))
803        {
804            if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
805                     (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
806                     (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
807            {
808                /*
809                 * This is a first-level element of a term list
810                 * start a new line
811                 */
812                if (!(Info->Flags & ACPI_PARSEOP_PARAMLIST))
813                {
814                    AcpiOsPrintf ("\n");
815                }
816            }
817        }
818        break;
819
820
821    case BLOCK_BRACE:
822    case (BLOCK_BRACE | BLOCK_PAREN):
823
824        /* Completed an op that has a term list, add closing brace */
825
826        if (Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST)
827        {
828            AcpiOsPrintf ("}");
829        }
830        else
831        {
832            AcpiDmIndent (Level);
833            AcpiOsPrintf ("}");
834        }
835
836        AcpiDmCommaIfListMember (Op);
837
838        if (AcpiDmBlockType (Op->Common.Parent) != BLOCK_PAREN)
839        {
840            AcpiOsPrintf ("\n");
841            if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_EMPTY_TERMLIST))
842            {
843                if ((Op->Common.AmlOpcode == AML_IF_OP)  &&
844                    (Op->Common.Next) &&
845                    (Op->Common.Next->Common.AmlOpcode == AML_ELSE_OP))
846                {
847                    break;
848                }
849
850                if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
851                    (!Op->Common.Next))
852                {
853                    break;
854                }
855                AcpiOsPrintf ("\n");
856            }
857        }
858        break;
859
860
861    case BLOCK_NONE:
862    default:
863
864        /* Could be a nested operator, check if comma required */
865
866        if (!AcpiDmCommaIfListMember (Op))
867        {
868            if ((AcpiDmBlockType (Op->Common.Parent) & BLOCK_BRACE) &&
869                     (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)) &&
870                     (Op->Common.AmlOpcode != AML_INT_BYTELIST_OP))
871            {
872                /*
873                 * This is a first-level element of a term list
874                 * start a new line
875                 */
876                AcpiOsPrintf ("\n");
877            }
878        }
879        else if (Op->Common.Parent)
880        {
881            switch (Op->Common.Parent->Common.AmlOpcode)
882            {
883            case AML_PACKAGE_OP:
884            case AML_VAR_PACKAGE_OP:
885
886                if (!(Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
887                {
888                    AcpiOsPrintf ("\n");
889                }
890                break;
891
892            default:
893
894                break;
895            }
896        }
897        break;
898    }
899
900    if (Op->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST)
901    {
902        if ((Op->Common.Next) &&
903            (Op->Common.Next->Common.DisasmFlags & ACPI_PARSEOP_PARAMLIST))
904        {
905            return (AE_OK);
906        }
907
908        /*
909         * Just completed a parameter node for something like "Buffer (param)".
910         * Close the paren and open up the term list block with a brace
911         */
912        if (Op->Common.Next)
913        {
914            AcpiOsPrintf (")\n");
915            AcpiDmIndent (Level - 1);
916            AcpiOsPrintf ("{\n");
917        }
918        else
919        {
920            Op->Common.Parent->Common.DisasmFlags |=
921                                    ACPI_PARSEOP_EMPTY_TERMLIST;
922            AcpiOsPrintf (") {");
923        }
924    }
925
926    if ((Op->Common.AmlOpcode == AML_NAME_OP) ||
927        (Op->Common.AmlOpcode == AML_RETURN_OP))
928    {
929        Info->Level++;
930    }
931    return (AE_OK);
932}
933
934
935#endif  /* ACPI_DISASSEMBLER */
936