Home | History | Annotate | Line # | Download | only in compiler
dtutils.c revision 1.1.1.2
      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     CmCleanupAndExit ();
    193     exit (1);
    194 }
    195 
    196 
    197 /******************************************************************************
    198  *
    199  * FUNCTION:    DtStrtoul64
    200  *
    201  * PARAMETERS:  String              - Null terminated string
    202  *              ReturnInteger       - Where the converted integer is returned
    203  *
    204  * RETURN:      Status
    205  *
    206  * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned
    207  *              value. Assumes no leading "0x" for the constant.
    208  *
    209  * Portability note: The reason this function exists is because a 64-bit
    210  * sscanf is not available in all environments.
    211  *
    212  *****************************************************************************/
    213 
    214 ACPI_STATUS
    215 DtStrtoul64 (
    216     char                    *String,
    217     UINT64                  *ReturnInteger)
    218 {
    219     char                    *ThisChar = String;
    220     UINT32                  ThisDigit;
    221     UINT64                  ReturnValue = 0;
    222     int                     DigitCount = 0;
    223 
    224 
    225     /* Skip over any white space in the buffer */
    226 
    227     while ((*ThisChar == ' ') || (*ThisChar == '\t'))
    228     {
    229         ThisChar++;
    230     }
    231 
    232     /* Skip leading zeros */
    233 
    234     while ((*ThisChar) == '0')
    235     {
    236         ThisChar++;
    237     }
    238 
    239     /* Convert character-by-character */
    240 
    241     while (*ThisChar)
    242     {
    243         if (ACPI_IS_DIGIT (*ThisChar))
    244         {
    245             /* Convert ASCII 0-9 to Decimal value */
    246 
    247             ThisDigit = ((UINT8) *ThisChar) - '0';
    248         }
    249         else /* Letter */
    250         {
    251             ThisDigit = (UINT32) ACPI_TOUPPER (*ThisChar);
    252             if (!ACPI_IS_XDIGIT ((char) ThisDigit))
    253             {
    254                 /* Not A-F */
    255 
    256                 return (AE_BAD_CHARACTER);
    257             }
    258 
    259             /* Convert ASCII Hex char (A-F) to value */
    260 
    261             ThisDigit = (ThisDigit - 'A') + 10;
    262         }
    263 
    264         /* Insert the 4-bit hex digit */
    265 
    266         ReturnValue <<= 4;
    267         ReturnValue += ThisDigit;
    268 
    269         ThisChar++;
    270         DigitCount++;
    271         if (DigitCount > 16)
    272         {
    273             /* Value is too large (> 64 bits/8 bytes/16 hex digits) */
    274 
    275             return (AE_LIMIT);
    276         }
    277     }
    278 
    279     *ReturnInteger = ReturnValue;
    280     return (AE_OK);
    281 }
    282 
    283 
    284 /******************************************************************************
    285  *
    286  * FUNCTION:    DtGetFileSize
    287  *
    288  * PARAMETERS:  Handle              - Open file handler
    289  *
    290  * RETURN:      Current file size
    291  *
    292  * DESCRIPTION: Get the current size of a file. Seek to the EOF and get the
    293  *              offset. Seek back to the original location.
    294  *
    295  *****************************************************************************/
    296 
    297 UINT32
    298 DtGetFileSize (
    299     FILE                    *Handle)
    300 {
    301     int                     CurrentOffset;
    302     int                     LastOffset;
    303 
    304 
    305     CurrentOffset = ftell (Handle);
    306     fseek (Handle, 0, SEEK_END);
    307     LastOffset = ftell (Handle);
    308     fseek (Handle, CurrentOffset, SEEK_SET);
    309 
    310     return ((UINT32) LastOffset);
    311 }
    312 
    313 
    314 /******************************************************************************
    315  *
    316  * FUNCTION:    DtGetFieldValue
    317  *
    318  * PARAMETERS:  Field               - Current field list pointer
    319  *              Name                - Field name
    320  *
    321  * RETURN:      Field value
    322  *
    323  * DESCRIPTION: Get field value
    324  *
    325  *****************************************************************************/
    326 
    327 char *
    328 DtGetFieldValue (
    329     DT_FIELD                *Field,
    330     char                    *Name)
    331 {
    332 
    333     /* Search the field list for the name */
    334 
    335     while (Field)
    336     {
    337         if (!ACPI_STRCMP (Name, Field->Name))
    338         {
    339             return (Field->Value);
    340         }
    341 
    342         Field = Field->Next;
    343     }
    344 
    345     return (NULL);
    346 }
    347 
    348 
    349 /******************************************************************************
    350  *
    351  * FUNCTION:    DtGetFieldType
    352  *
    353  * PARAMETERS:  Info                - Data table info
    354  *
    355  * RETURN:      Field type
    356  *
    357  * DESCRIPTION: Get field type
    358  *
    359  *****************************************************************************/
    360 
    361 UINT8
    362 DtGetFieldType (
    363     ACPI_DMTABLE_INFO       *Info)
    364 {
    365     UINT8                   Type;
    366 
    367 
    368     /* DT_FLAG means that this is the start of a block of flag bits */
    369     /* TBD - we can make these a separate opcode later */
    370 
    371     if (Info->Flags & DT_FLAG)
    372     {
    373         return (DT_FIELD_TYPE_FLAGS_INTEGER);
    374     }
    375 
    376     /* Type is based upon the opcode for this field in the info table */
    377 
    378     switch (Info->Opcode)
    379     {
    380     case ACPI_DMT_FLAG0:
    381     case ACPI_DMT_FLAG1:
    382     case ACPI_DMT_FLAG2:
    383     case ACPI_DMT_FLAG3:
    384     case ACPI_DMT_FLAG4:
    385     case ACPI_DMT_FLAG5:
    386     case ACPI_DMT_FLAG6:
    387     case ACPI_DMT_FLAG7:
    388     case ACPI_DMT_FLAGS0:
    389     case ACPI_DMT_FLAGS2:
    390         Type = DT_FIELD_TYPE_FLAG;
    391         break;
    392 
    393     case ACPI_DMT_NAME4:
    394     case ACPI_DMT_SIG:
    395     case ACPI_DMT_NAME6:
    396     case ACPI_DMT_NAME8:
    397     case ACPI_DMT_STRING:
    398         Type = DT_FIELD_TYPE_STRING;
    399         break;
    400 
    401     case ACPI_DMT_BUFFER:
    402     case ACPI_DMT_BUF7:
    403     case ACPI_DMT_BUF16:
    404     case ACPI_DMT_PCI_PATH:
    405         Type = DT_FIELD_TYPE_BUFFER;
    406         break;
    407 
    408     case ACPI_DMT_GAS:
    409     case ACPI_DMT_HESTNTFY:
    410         Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
    411         break;
    412 
    413     case ACPI_DMT_UNICODE:
    414         Type = DT_FIELD_TYPE_UNICODE;
    415         break;
    416 
    417     case ACPI_DMT_UUID:
    418         Type = DT_FIELD_TYPE_UUID;
    419         break;
    420 
    421     case ACPI_DMT_DEVICE_PATH:
    422         Type = DT_FIELD_TYPE_DEVICE_PATH;
    423         break;
    424 
    425     case ACPI_DMT_LABEL:
    426         Type = DT_FIELD_TYPE_LABEL;
    427         break;
    428 
    429     default:
    430         Type = DT_FIELD_TYPE_INTEGER;
    431         break;
    432     }
    433 
    434     return (Type);
    435 }
    436 
    437 
    438 /******************************************************************************
    439  *
    440  * FUNCTION:    DtGetBufferLength
    441  *
    442  * PARAMETERS:  Buffer              - List of integers,
    443  *                                    for example "10 3A 4F 2E"
    444  *
    445  * RETURN:      Count of integer
    446  *
    447  * DESCRIPTION: Get length of bytes needed to store the integers
    448  *
    449  *****************************************************************************/
    450 
    451 UINT32
    452 DtGetBufferLength (
    453     char                    *Buffer)
    454 {
    455     UINT32                  ByteLength = 0;
    456 
    457 
    458     while (*Buffer)
    459     {
    460         if (*Buffer == ' ')
    461         {
    462             ByteLength++;
    463 
    464             while (*Buffer == ' ')
    465             {
    466                 Buffer++;
    467             }
    468         }
    469 
    470         Buffer++;
    471     }
    472 
    473     return (++ByteLength);
    474 }
    475 
    476 
    477 /******************************************************************************
    478  *
    479  * FUNCTION:    DtGetFieldLength
    480  *
    481  * PARAMETERS:  Field               - Current field list pointer
    482  *              Info                - Data table info
    483  *
    484  * RETURN:      Field length
    485  *
    486  * DESCRIPTION: Get length of bytes needed to compile the field
    487  *
    488  * Note: This function must remain in sync with AcpiDmDumpTable.
    489  *
    490  *****************************************************************************/
    491 
    492 UINT32
    493 DtGetFieldLength (
    494     DT_FIELD                *Field,
    495     ACPI_DMTABLE_INFO       *Info)
    496 {
    497     UINT32                  ByteLength = 0;
    498     char                    *Value;
    499 
    500 
    501     /* Length is based upon the opcode for this field in the info table */
    502 
    503     switch (Info->Opcode)
    504     {
    505     case ACPI_DMT_FLAG0:
    506     case ACPI_DMT_FLAG1:
    507     case ACPI_DMT_FLAG2:
    508     case ACPI_DMT_FLAG3:
    509     case ACPI_DMT_FLAG4:
    510     case ACPI_DMT_FLAG5:
    511     case ACPI_DMT_FLAG6:
    512     case ACPI_DMT_FLAG7:
    513     case ACPI_DMT_FLAGS0:
    514     case ACPI_DMT_FLAGS2:
    515     case ACPI_DMT_LABEL:
    516         ByteLength = 0;
    517         break;
    518 
    519     case ACPI_DMT_UINT8:
    520     case ACPI_DMT_CHKSUM:
    521     case ACPI_DMT_SPACEID:
    522     case ACPI_DMT_ACCWIDTH:
    523     case ACPI_DMT_IVRS:
    524     case ACPI_DMT_MADT:
    525     case ACPI_DMT_SRAT:
    526     case ACPI_DMT_ASF:
    527     case ACPI_DMT_HESTNTYP:
    528     case ACPI_DMT_FADTPM:
    529     case ACPI_DMT_EINJACT:
    530     case ACPI_DMT_EINJINST:
    531     case ACPI_DMT_ERSTACT:
    532     case ACPI_DMT_ERSTINST:
    533         ByteLength = 1;
    534         break;
    535 
    536     case ACPI_DMT_UINT16:
    537     case ACPI_DMT_DMAR:
    538     case ACPI_DMT_HEST:
    539     case ACPI_DMT_PCI_PATH:
    540         ByteLength = 2;
    541         break;
    542 
    543     case ACPI_DMT_UINT24:
    544         ByteLength = 3;
    545         break;
    546 
    547     case ACPI_DMT_UINT32:
    548     case ACPI_DMT_NAME4:
    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, Info->Name);
    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         }
    579         break;
    580 
    581     case ACPI_DMT_GAS:
    582         ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
    583         break;
    584 
    585     case ACPI_DMT_HESTNTFY:
    586         ByteLength = sizeof (ACPI_HEST_NOTIFY);
    587         break;
    588 
    589     case ACPI_DMT_BUFFER:
    590         Value = DtGetFieldValue (Field, Info->Name);
    591         if (Value)
    592         {
    593             ByteLength = DtGetBufferLength (Value);
    594         }
    595         else
    596         {   /* At this point, this is a fatal error */
    597 
    598             sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
    599             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
    600         }
    601         break;
    602 
    603     case ACPI_DMT_BUF16:
    604     case ACPI_DMT_UUID:
    605         ByteLength = 16;
    606         break;
    607 
    608     case ACPI_DMT_UNICODE:
    609         Value = DtGetFieldValue (Field, Info->Name);
    610 
    611         /* TBD: error if Value is NULL? (as below?) */
    612 
    613         ByteLength = (ACPI_STRLEN (Value) + 1) * sizeof(UINT16);
    614         break;
    615 
    616     default:
    617         DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
    618         break;
    619     }
    620 
    621     return (ByteLength);
    622 }
    623 
    624 
    625 /******************************************************************************
    626  *
    627  * FUNCTION:    DtSum
    628  *
    629  * PARAMETERS:  DT_WALK_CALLBACK:
    630  *              Subtable            - Subtable
    631  *              Context             - Unused
    632  *              ReturnValue         - Store the checksum of subtable
    633  *
    634  * RETURN:      Status
    635  *
    636  * DESCRIPTION: Get the checksum of subtable
    637  *
    638  *****************************************************************************/
    639 
    640 static void
    641 DtSum (
    642     DT_SUBTABLE             *Subtable,
    643     void                    *Context,
    644     void                    *ReturnValue)
    645 {
    646     UINT8                   Checksum;
    647     UINT8                   *Sum = ReturnValue;
    648 
    649 
    650     Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
    651     *Sum = (UINT8) (*Sum + Checksum);
    652 }
    653 
    654 
    655 /******************************************************************************
    656  *
    657  * FUNCTION:    DtSetTableChecksum
    658  *
    659  * PARAMETERS:  ChecksumPointer     - Where to return the checksum
    660  *
    661  * RETURN:      None
    662  *
    663  * DESCRIPTION: Set checksum of the whole data table into the checksum field
    664  *
    665  *****************************************************************************/
    666 
    667 void
    668 DtSetTableChecksum (
    669     UINT8                   *ChecksumPointer)
    670 {
    671     UINT8                   Checksum = 0;
    672     UINT8                   OldSum;
    673 
    674 
    675     DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum);
    676 
    677     OldSum = *ChecksumPointer;
    678     Checksum = (UINT8) (Checksum - OldSum);
    679 
    680     /* Compute the final checksum */
    681 
    682     Checksum = (UINT8) (0 - Checksum);
    683     *ChecksumPointer = Checksum;
    684 }
    685 
    686 
    687 /******************************************************************************
    688  *
    689  * FUNCTION:    DtSetTableLength
    690  *
    691  * PARAMETERS:  None
    692  *
    693  * RETURN:      None
    694  *
    695  * DESCRIPTION: Walk the subtables and set all the length fields
    696  *
    697  *****************************************************************************/
    698 
    699 void
    700 DtSetTableLength (
    701     void)
    702 {
    703     DT_SUBTABLE             *ParentTable;
    704     DT_SUBTABLE             *ChildTable;
    705 
    706 
    707     ParentTable = Gbl_RootTable;
    708     ChildTable = NULL;
    709 
    710     if (!ParentTable)
    711     {
    712         return;
    713     }
    714 
    715     DtSetSubtableLength (ParentTable);
    716 
    717     while (1)
    718     {
    719         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
    720         if (ChildTable)
    721         {
    722             if (ChildTable->LengthField)
    723             {
    724                 DtSetSubtableLength (ChildTable);
    725             }
    726 
    727             if (ChildTable->Child)
    728             {
    729                 ParentTable = ChildTable;
    730                 ChildTable = NULL;
    731             }
    732             else
    733             {
    734                 ParentTable->TotalLength += ChildTable->TotalLength;
    735                 if (ParentTable->LengthField)
    736                 {
    737                     DtSetSubtableLength (ParentTable);
    738                 }
    739             }
    740         }
    741         else
    742         {
    743             ChildTable = ParentTable;
    744 
    745             if (ChildTable == Gbl_RootTable)
    746             {
    747                 break;
    748             }
    749 
    750             ParentTable = DtGetParentSubtable (ParentTable);
    751 
    752             ParentTable->TotalLength += ChildTable->TotalLength;
    753             if (ParentTable->LengthField)
    754             {
    755                 DtSetSubtableLength (ParentTable);
    756             }
    757         }
    758     }
    759 }
    760 
    761 
    762 /******************************************************************************
    763  *
    764  * FUNCTION:    DtWalkTableTree
    765  *
    766  * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
    767  *              UserFunction        - Called during the walk
    768  *              Context             - Passed to user function
    769  *              ReturnValue         - The return value of UserFunction
    770  *
    771  * RETURN:      None
    772  *
    773  * DESCRIPTION: Performs a depth-first walk of the subtable tree
    774  *
    775  *****************************************************************************/
    776 
    777 void
    778 DtWalkTableTree (
    779     DT_SUBTABLE             *StartTable,
    780     DT_WALK_CALLBACK        UserFunction,
    781     void                    *Context,
    782     void                    *ReturnValue)
    783 {
    784     DT_SUBTABLE             *ParentTable;
    785     DT_SUBTABLE             *ChildTable;
    786 
    787 
    788     ParentTable = StartTable;
    789     ChildTable = NULL;
    790 
    791     if (!ParentTable)
    792     {
    793         return;
    794     }
    795 
    796     UserFunction (ParentTable, Context, ReturnValue);
    797 
    798     while (1)
    799     {
    800         ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
    801         if (ChildTable)
    802         {
    803             UserFunction (ChildTable, Context, ReturnValue);
    804 
    805             if (ChildTable->Child)
    806             {
    807                 ParentTable = ChildTable;
    808                 ChildTable = NULL;
    809             }
    810         }
    811         else
    812         {
    813             ChildTable = ParentTable;
    814             if (ChildTable == Gbl_RootTable)
    815             {
    816                 break;
    817             }
    818 
    819             ParentTable = DtGetParentSubtable (ParentTable);
    820 
    821             if (ChildTable->Peer == StartTable)
    822             {
    823                 break;
    824             }
    825         }
    826     }
    827 }
    828 
    829 
    830 /******************************************************************************
    831  *
    832  * FUNCTION:    DtFreeFieldList
    833  *
    834  * PARAMETERS:  None
    835  *
    836  * RETURN:      None
    837  *
    838  * DESCRIPTION: Free the field list
    839  *
    840  *****************************************************************************/
    841 
    842 void
    843 DtFreeFieldList (
    844     void)
    845 {
    846     DT_FIELD                *Field = Gbl_FieldList;
    847     DT_FIELD                *NextField;
    848 
    849 
    850     /* Walk and free entire field list */
    851 
    852     while (Field)
    853     {
    854         NextField = Field->Next; /* Save link */
    855 
    856         if (!(Field->Flags & DT_FIELD_NOT_ALLOCATED))
    857         {
    858             ACPI_FREE (Field->Name);
    859             ACPI_FREE (Field->Value);
    860         }
    861 
    862         ACPI_FREE (Field);
    863         Field = NextField;
    864     }
    865 }
    866