Home | History | Annotate | Line # | Download | only in compiler
dtutils.c revision 1.1.1.3
      1 /******************************************************************************
      2  *
      3  * Module Name: dtutils.c - Utility routines for the data table compiler
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2011, 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 #define __DTUTILS_C__
     45 
     46 #include "aslcompiler.h"
     47 #include "dtcompiler.h"
     48 #include "actables.h"
     49 
     50 #define _COMPONENT          DT_COMPILER
     51         ACPI_MODULE_NAME    ("dtutils")
     52 
     53 /* Local prototypes */
     54 
     55 static void
     56 DtSum (
     57     DT_SUBTABLE             *Subtable,
     58     void                    *Context,
     59     void                    *ReturnValue);
     60 
     61 
     62 /******************************************************************************
     63  *
     64  * FUNCTION:    DtError
     65  *
     66  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
     67  *              MessageId           - Index into global message buffer
     68  *              Op                  - Parse node where error happened
     69  *              ExtraMessage        - additional error message
     70  *
     71  * RETURN:      None
     72  *
     73  * DESCRIPTION: Common error interface for data table compiler
     74  *
     75  *****************************************************************************/
     76 
     77 void
     78 DtError (
     79     UINT8                   Level,
     80     UINT8                   MessageId,
     81     DT_FIELD                *FieldObject,
     82     char                    *ExtraMessage)
     83 {
     84 
     85     switch (Level)
     86     {
     87     case ASL_WARNING2:
     88     case ASL_WARNING3:
     89         if (Gbl_WarningLevel < Level)
     90         {
     91             return;
     92         }
     93         break;
     94 
     95     default:
     96         break;
     97     }
     98 
     99     if (FieldObject)
    100     {
    101         AslCommonError (Level, MessageId,
    102             FieldObject->Line,
    103             FieldObject->Line,
    104             FieldObject->ByteOffset,
    105             FieldObject->Column,
    106             Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
    107     }
    108     else
    109     {
    110         AslCommonError (Level, MessageId, 0,
    111             0, 0, 0, 0, ExtraMessage);
    112     }
    113 }
    114 
    115 
    116 /******************************************************************************
    117  *
    118  * FUNCTION:    DtNameError
    119  *
    120  * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
    121  *              MessageId           - Index into global message buffer
    122  *              Op                  - Parse node where error happened
    123  *              ExtraMessage        - additional error message
    124  *
    125  * RETURN:      None
    126  *
    127  * DESCRIPTION: Error interface for named objects
    128  *
    129  *****************************************************************************/
    130 
    131 void
    132 DtNameError (
    133     UINT8                   Level,
    134     UINT8                   MessageId,
    135     DT_FIELD                *FieldObject,
    136     char                    *ExtraMessage)
    137 {
    138 
    139     switch (Level)
    140     {
    141     case ASL_WARNING2:
    142     case ASL_WARNING3:
    143         if (Gbl_WarningLevel < Level)
    144         {
    145             return;
    146         }
    147         break;
    148 
    149     default:
    150         break;
    151     }
    152 
    153     if (FieldObject)
    154     {
    155         AslCommonError (Level, MessageId,
    156             FieldObject->Line,
    157             FieldObject->Line,
    158             FieldObject->ByteOffset,
    159             FieldObject->NameColumn,
    160             Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
    161     }
    162     else
    163     {
    164         AslCommonError (Level, MessageId, 0,
    165             0, 0, 0, 0, ExtraMessage);
    166     }
    167 }
    168 
    169 
    170 /*******************************************************************************
    171  *
    172  * FUNCTION:    DtFatal
    173  *
    174  * PARAMETERS:  None
    175  *
    176  * RETURN:      None
    177  *
    178  * DESCRIPTION: Dump the error log and abort the compiler. Used for serious
    179  *              compile or I/O errors
    180  *
    181  ******************************************************************************/
    182 
    183 void
    184 DtFatal (
    185     UINT8                   MessageId,
    186     DT_FIELD                *FieldObject,
    187     char                    *ExtraMessage)
    188 {
    189 
    190     DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage);
    191 
    192 /*
    193  * TBD: remove this entire function, DtFatal
    194  *
    195  * We cannot abort the compiler on error, because we may be compiling a
    196  * list of files. We must move on to the next file.
    197  */
    198 #ifdef __OBSOLETE
    199     CmCleanupAndExit ();
    200     exit (1);
    201 #endif
    202 }
    203 
    204 
    205 /******************************************************************************
    206  *
    207  * FUNCTION:    DtStrtoul64
    208  *
    209  * PARAMETERS:  String              - Null terminated string
    210  *              ReturnInteger       - Where the converted integer is returned
    211  *
    212  * RETURN:      Status
    213  *
    214  * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned
    215  *              value. Assumes no leading "0x" for the constant.
    216  *
    217  * Portability note: The reason this function exists is because a 64-bit
    218  * sscanf is not available in all environments.
    219  *
    220  *****************************************************************************/
    221 
    222 ACPI_STATUS
    223 DtStrtoul64 (
    224     char                    *String,
    225     UINT64                  *ReturnInteger)
    226 {
    227     char                    *ThisChar = String;
    228     UINT32                  ThisDigit;
    229     UINT64                  ReturnValue = 0;
    230     int                     DigitCount = 0;
    231 
    232 
    233     /* Skip over any white space in the buffer */
    234 
    235     while ((*ThisChar == ' ') || (*ThisChar == '\t'))
    236     {
    237         ThisChar++;
    238     }
    239 
    240     /* Skip leading zeros */
    241 
    242     while ((*ThisChar) == '0')
    243     {
    244         ThisChar++;
    245     }
    246 
    247     /* Convert character-by-character */
    248 
    249     while (*ThisChar)
    250     {
    251         if (ACPI_IS_DIGIT (*ThisChar))
    252         {
    253             /* Convert ASCII 0-9 to Decimal value */
    254 
    255             ThisDigit = ((UINT8) *ThisChar) - '0';
    256         }
    257         else /* Letter */
    258         {
    259             ThisDigit = (UINT32) ACPI_TOUPPER (*ThisChar);
    260             if (!ACPI_IS_XDIGIT ((char) ThisDigit))
    261             {
    262                 /* Not A-F */
    263 
    264                 return (AE_BAD_CHARACTER);
    265             }
    266 
    267             /* Convert ASCII Hex char (A-F) to value */
    268 
    269             ThisDigit = (ThisDigit - 'A') + 10;
    270         }
    271 
    272         /* Insert the 4-bit hex digit */
    273 
    274         ReturnValue <<= 4;
    275         ReturnValue += ThisDigit;
    276 
    277         ThisChar++;
    278         DigitCount++;
    279         if (DigitCount > 16)
    280         {
    281             /* Value is too large (> 64 bits/8 bytes/16 hex digits) */
    282 
    283             return (AE_LIMIT);
    284         }
    285     }
    286 
    287     *ReturnInteger = ReturnValue;
    288     return (AE_OK);
    289 }
    290 
    291 
    292 /******************************************************************************
    293  *
    294  * FUNCTION:    DtGetFileSize
    295  *
    296  * PARAMETERS:  Handle              - Open file handler
    297  *
    298  * RETURN:      Current file size
    299  *
    300  * DESCRIPTION: Get the current size of a file. Seek to the EOF and get the
    301  *              offset. Seek back to the original location.
    302  *
    303  *****************************************************************************/
    304 
    305 UINT32
    306 DtGetFileSize (
    307     FILE                    *Handle)
    308 {
    309     int                     CurrentOffset;
    310     int                     LastOffset;
    311 
    312 
    313     CurrentOffset = ftell (Handle);
    314     fseek (Handle, 0, SEEK_END);
    315     LastOffset = ftell (Handle);
    316     fseek (Handle, CurrentOffset, SEEK_SET);
    317 
    318     return ((UINT32) LastOffset);
    319 }
    320 
    321 
    322 /******************************************************************************
    323  *
    324  * FUNCTION:    DtGetFieldValue
    325  *
    326  * PARAMETERS:  Field               - Current field list pointer
    327  *
    328  * RETURN:      Field value
    329  *
    330  * DESCRIPTION: Get field value
    331  *
    332  *****************************************************************************/
    333 
    334 char *
    335 DtGetFieldValue (
    336     DT_FIELD                *Field)
    337 {
    338     if (!Field)
    339     {
    340         return (NULL);
    341     }
    342 
    343     return (Field->Value);
    344 }
    345 
    346 
    347 /******************************************************************************
    348  *
    349  * FUNCTION:    DtGetFieldType
    350  *
    351  * PARAMETERS:  Info                - Data table info
    352  *
    353  * RETURN:      Field type
    354  *
    355  * DESCRIPTION: Get field type
    356  *
    357  *****************************************************************************/
    358 
    359 UINT8
    360 DtGetFieldType (
    361     ACPI_DMTABLE_INFO       *Info)
    362 {
    363     UINT8                   Type;
    364 
    365 
    366     /* DT_FLAG means that this is the start of a block of flag bits */
    367     /* TBD - we can make these a separate opcode later */
    368 
    369     if (Info->Flags & DT_FLAG)
    370     {
    371         return (DT_FIELD_TYPE_FLAGS_INTEGER);
    372     }
    373 
    374     /* Type is based upon the opcode for this field in the info table */
    375 
    376     switch (Info->Opcode)
    377     {
    378     case ACPI_DMT_FLAG0:
    379     case ACPI_DMT_FLAG1:
    380     case ACPI_DMT_FLAG2:
    381     case ACPI_DMT_FLAG3:
    382     case ACPI_DMT_FLAG4:
    383     case ACPI_DMT_FLAG5:
    384     case ACPI_DMT_FLAG6:
    385     case ACPI_DMT_FLAG7:
    386     case ACPI_DMT_FLAGS0:
    387     case ACPI_DMT_FLAGS2:
    388         Type = DT_FIELD_TYPE_FLAG;
    389         break;
    390 
    391     case ACPI_DMT_NAME4:
    392     case ACPI_DMT_SIG:
    393     case ACPI_DMT_NAME6:
    394     case ACPI_DMT_NAME8:
    395     case ACPI_DMT_STRING:
    396         Type = DT_FIELD_TYPE_STRING;
    397         break;
    398 
    399     case ACPI_DMT_BUFFER:
    400     case ACPI_DMT_BUF7:
    401     case ACPI_DMT_BUF16:
    402     case ACPI_DMT_BUF128:
    403     case ACPI_DMT_PCI_PATH:
    404         Type = DT_FIELD_TYPE_BUFFER;
    405         break;
    406 
    407     case ACPI_DMT_GAS:
    408     case ACPI_DMT_HESTNTFY:
    409         Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
    410         break;
    411 
    412     case ACPI_DMT_UNICODE:
    413         Type = DT_FIELD_TYPE_UNICODE;
    414         break;
    415 
    416     case ACPI_DMT_UUID:
    417         Type = DT_FIELD_TYPE_UUID;
    418         break;
    419 
    420     case ACPI_DMT_DEVICE_PATH:
    421         Type = DT_FIELD_TYPE_DEVICE_PATH;
    422         break;
    423 
    424     case ACPI_DMT_LABEL:
    425         Type = DT_FIELD_TYPE_LABEL;
    426         break;
    427 
    428     default:
    429         Type = DT_FIELD_TYPE_INTEGER;
    430         break;
    431     }
    432 
    433     return (Type);
    434 }
    435 
    436 
    437 /******************************************************************************
    438  *
    439  * FUNCTION:    DtGetBufferLength
    440  *
    441  * PARAMETERS:  Buffer              - List of integers,
    442  *                                    for example "10 3A 4F 2E"
    443  *
    444  * RETURN:      Count of integer
    445  *
    446  * DESCRIPTION: Get length of bytes needed to store the integers
    447  *
    448  *****************************************************************************/
    449 
    450 UINT32
    451 DtGetBufferLength (
    452     char                    *Buffer)
    453 {
    454     UINT32                  ByteLength = 0;
    455 
    456 
    457     while (*Buffer)
    458     {
    459         if (*Buffer == ' ')
    460         {
    461             ByteLength++;
    462 
    463             while (*Buffer == ' ')
    464             {
    465                 Buffer++;
    466             }
    467         }
    468 
    469         Buffer++;
    470     }
    471 
    472     return (++ByteLength);
    473 }
    474 
    475 
    476 /******************************************************************************
    477  *
    478  * FUNCTION:    DtGetFieldLength
    479  *
    480  * PARAMETERS:  Field               - Current field
    481  *              Info                - Data table info
    482  *
    483  * RETURN:      Field length
    484  *
    485  * DESCRIPTION: Get length of bytes needed to compile the field
    486  *
    487  * Note: This function must remain in sync with AcpiDmDumpTable.
    488  *
    489  *****************************************************************************/
    490 
    491 UINT32
    492 DtGetFieldLength (
    493     DT_FIELD                *Field,
    494     ACPI_DMTABLE_INFO       *Info)
    495 {
    496     UINT32                  ByteLength = 0;
    497     char                    *Value;
    498 
    499 
    500     /* Length is based upon the opcode for this field in the info table */
    501 
    502     switch (Info->Opcode)
    503     {
    504     case ACPI_DMT_FLAG0:
    505     case ACPI_DMT_FLAG1:
    506     case ACPI_DMT_FLAG2:
    507     case ACPI_DMT_FLAG3:
    508     case ACPI_DMT_FLAG4:
    509     case ACPI_DMT_FLAG5:
    510     case ACPI_DMT_FLAG6:
    511     case ACPI_DMT_FLAG7:
    512     case ACPI_DMT_FLAGS0:
    513     case ACPI_DMT_FLAGS2:
    514     case ACPI_DMT_LABEL:
    515         ByteLength = 0;
    516         break;
    517 
    518     case ACPI_DMT_UINT8:
    519     case ACPI_DMT_CHKSUM:
    520     case ACPI_DMT_SPACEID:
    521     case ACPI_DMT_ACCWIDTH:
    522     case ACPI_DMT_IVRS:
    523     case ACPI_DMT_MADT:
    524     case ACPI_DMT_SRAT:
    525     case ACPI_DMT_ASF:
    526     case ACPI_DMT_HESTNTYP:
    527     case ACPI_DMT_FADTPM:
    528     case ACPI_DMT_EINJACT:
    529     case ACPI_DMT_EINJINST:
    530     case ACPI_DMT_ERSTACT:
    531     case ACPI_DMT_ERSTINST:
    532         ByteLength = 1;
    533         break;
    534 
    535     case ACPI_DMT_UINT16:
    536     case ACPI_DMT_DMAR:
    537     case ACPI_DMT_HEST:
    538     case ACPI_DMT_PCI_PATH:
    539         ByteLength = 2;
    540         break;
    541 
    542     case ACPI_DMT_UINT24:
    543         ByteLength = 3;
    544         break;
    545 
    546     case ACPI_DMT_UINT32:
    547     case ACPI_DMT_NAME4:
    548     case ACPI_DMT_SLIC:
    549     case ACPI_DMT_SIG:
    550         ByteLength = 4;
    551         break;
    552 
    553     case ACPI_DMT_NAME6:
    554         ByteLength = 6;
    555         break;
    556 
    557     case ACPI_DMT_UINT56:
    558     case ACPI_DMT_BUF7:
    559         ByteLength = 7;
    560         break;
    561 
    562     case ACPI_DMT_UINT64:
    563     case ACPI_DMT_NAME8:
    564         ByteLength = 8;
    565         break;
    566 
    567     case ACPI_DMT_STRING:
    568         Value = DtGetFieldValue (Field);
    569         if (Value)
    570         {
    571             ByteLength = ACPI_STRLEN (Value) + 1;
    572         }
    573         else
    574         {   /* At this point, this is a fatal error */
    575 
    576             sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
    577             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
    578             return (0);
    579         }
    580         break;
    581 
    582     case ACPI_DMT_GAS:
    583         ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
    584         break;
    585 
    586     case ACPI_DMT_HESTNTFY:
    587         ByteLength = sizeof (ACPI_HEST_NOTIFY);
    588         break;
    589 
    590     case ACPI_DMT_BUFFER:
    591         Value = DtGetFieldValue (Field);
    592         if (Value)
    593         {
    594             ByteLength = DtGetBufferLength (Value);
    595         }
    596         else
    597         {   /* At this point, this is a fatal error */
    598 
    599             sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
    600             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
    601             return (0);
    602         }
    603         break;
    604 
    605     case ACPI_DMT_BUF16:
    606     case ACPI_DMT_UUID:
    607         ByteLength = 16;
    608         break;
    609 
    610     case ACPI_DMT_BUF128:
    611         ByteLength = 128;
    612         break;
    613 
    614     case ACPI_DMT_UNICODE:
    615         Value = DtGetFieldValue (Field);
    616 
    617         /* TBD: error if Value is NULL? (as below?) */
    618 
    619         ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16);
    620         break;
    621 
    622     default:
    623         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
    624         return (0);
    625     }
    626 
    627     return (ByteLength);
    628 }
    629 
    630 
    631 /******************************************************************************
    632  *
    633  * FUNCTION:    DtSum
    634  *
    635  * PARAMETERS:  DT_WALK_CALLBACK:
    636  *              Subtable            - Subtable
    637  *              Context             - Unused
    638  *              ReturnValue         - Store the checksum of subtable
    639  *
    640  * RETURN:      Status
    641  *
    642  * DESCRIPTION: Get the checksum of subtable
    643  *
    644  *****************************************************************************/
    645 
    646 static void
    647 DtSum (
    648     DT_SUBTABLE             *Subtable,
    649     void                    *Context,
    650     void                    *ReturnValue)
    651 {
    652     UINT8                   Checksum;
    653     UINT8                   *Sum = ReturnValue;
    654 
    655 
    656     Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
    657     *Sum = (UINT8) (*Sum + Checksum);
    658 }
    659 
    660 
    661 /******************************************************************************
    662  *
    663  * FUNCTION:    DtSetTableChecksum
    664  *
    665  * PARAMETERS:  ChecksumPointer     - Where to return the checksum
    666  *
    667  * RETURN:      None
    668  *
    669  * DESCRIPTION: Set checksum of the whole data table into the checksum field
    670  *
    671  *****************************************************************************/
    672 
    673 void
    674 DtSetTableChecksum (
    675     UINT8                   *ChecksumPointer)
    676 {
    677     UINT8                   Checksum = 0;
    678     UINT8                   OldSum;
    679 
    680 
    681     DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum);
    682 
    683     OldSum = *ChecksumPointer;
    684     Checksum = (UINT8) (Checksum - OldSum);
    685 
    686     /* Compute the final checksum */
    687 
    688     Checksum = (UINT8) (0 - Checksum);
    689     *ChecksumPointer = Checksum;
    690 }
    691 
    692 
    693 /******************************************************************************
    694  *
    695  * FUNCTION:    DtSetTableLength
    696  *
    697  * PARAMETERS:  None
    698  *
    699  * RETURN:      None
    700  *
    701  * DESCRIPTION: Walk the subtables and set all the length fields
    702  *
    703  *****************************************************************************/
    704 
    705 void
    706 DtSetTableLength (
    707     void)
    708 {
    709     DT_SUBTABLE             *ParentTable;
    710     DT_SUBTABLE             *ChildTable;
    711 
    712 
    713     ParentTable = Gbl_RootTable;
    714     ChildTable = NULL;
    715 
    716     if (!ParentTable)
    717     {
    718         return;
    719     }
    720 
    721     DtSetSubtableLength (ParentTable);
    722 
    723     while (1)
    724     {
    725         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
    726         if (ChildTable)
    727         {
    728             if (ChildTable->LengthField)
    729             {
    730                 DtSetSubtableLength (ChildTable);
    731             }
    732 
    733             if (ChildTable->Child)
    734             {
    735                 ParentTable = ChildTable;
    736                 ChildTable = NULL;
    737             }
    738             else
    739             {
    740                 ParentTable->TotalLength += ChildTable->TotalLength;
    741                 if (ParentTable->LengthField)
    742                 {
    743                     DtSetSubtableLength (ParentTable);
    744                 }
    745             }
    746         }
    747         else
    748         {
    749             ChildTable = ParentTable;
    750 
    751             if (ChildTable == Gbl_RootTable)
    752             {
    753                 break;
    754             }
    755 
    756             ParentTable = DtGetParentSubtable (ParentTable);
    757 
    758             ParentTable->TotalLength += ChildTable->TotalLength;
    759             if (ParentTable->LengthField)
    760             {
    761                 DtSetSubtableLength (ParentTable);
    762             }
    763         }
    764     }
    765 }
    766 
    767 
    768 /******************************************************************************
    769  *
    770  * FUNCTION:    DtWalkTableTree
    771  *
    772  * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
    773  *              UserFunction        - Called during the walk
    774  *              Context             - Passed to user function
    775  *              ReturnValue         - The return value of UserFunction
    776  *
    777  * RETURN:      None
    778  *
    779  * DESCRIPTION: Performs a depth-first walk of the subtable tree
    780  *
    781  *****************************************************************************/
    782 
    783 void
    784 DtWalkTableTree (
    785     DT_SUBTABLE             *StartTable,
    786     DT_WALK_CALLBACK        UserFunction,
    787     void                    *Context,
    788     void                    *ReturnValue)
    789 {
    790     DT_SUBTABLE             *ParentTable;
    791     DT_SUBTABLE             *ChildTable;
    792 
    793 
    794     ParentTable = StartTable;
    795     ChildTable = NULL;
    796 
    797     if (!ParentTable)
    798     {
    799         return;
    800     }
    801 
    802     UserFunction (ParentTable, Context, ReturnValue);
    803 
    804     while (1)
    805     {
    806         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
    807         if (ChildTable)
    808         {
    809             UserFunction (ChildTable, Context, ReturnValue);
    810 
    811             if (ChildTable->Child)
    812             {
    813                 ParentTable = ChildTable;
    814                 ChildTable = NULL;
    815             }
    816         }
    817         else
    818         {
    819             ChildTable = ParentTable;
    820             if (ChildTable == Gbl_RootTable)
    821             {
    822                 break;
    823             }
    824 
    825             ParentTable = DtGetParentSubtable (ParentTable);
    826 
    827             if (ChildTable->Peer == StartTable)
    828             {
    829                 break;
    830             }
    831         }
    832     }
    833 }
    834 
    835 
    836 /******************************************************************************
    837  *
    838  * FUNCTION:    DtFreeFieldList
    839  *
    840  * PARAMETERS:  None
    841  *
    842  * RETURN:      None
    843  *
    844  * DESCRIPTION: Free the field list
    845  *
    846  *****************************************************************************/
    847 
    848 void
    849 DtFreeFieldList (
    850     void)
    851 {
    852     DT_FIELD                *Field = Gbl_FieldList;
    853     DT_FIELD                *NextField;
    854 
    855 
    856     /* Walk and free entire field list */
    857 
    858     while (Field)
    859     {
    860         NextField = Field->Next; /* Save link */
    861 
    862         if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED))
    863         {
    864             ACPI_FREE (Field->Name);
    865             ACPI_FREE (Field->Value);
    866         }
    867 
    868         ACPI_FREE (Field);
    869         Field = NextField;
    870     }
    871 }
    872