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