text: /******************************************************************************
   *
   * Module Name: dtutils.c - Utility routines for the data table compiler
   *
   *****************************************************************************/
  
  /*
   * Copyright (C) 2000 - 2016, Intel Corp.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions, and the following disclaimer,
   *    without modification.
   * 2. Redistributions in binary form must reproduce at minimum a disclaimer
   *    substantially similar to the "NO WARRANTY" disclaimer below
   *    ("Disclaimer") and any redistribution must be conditioned upon
   *    including a substantially similar Disclaimer requirement for further
   *    binary redistribution.
   * 3. Neither the names of the above-listed copyright holders nor the names
   *    of any contributors may be used to endorse or promote products derived
   *    from this software without specific prior written permission.
   *
   * Alternatively, this software may be distributed under the terms of the
   * GNU General Public License ("GPL") version 2 as published by the Free
   * Software Foundation.
   *
   * NO WARRANTY
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   * POSSIBILITY OF SUCH DAMAGES.
   */
  
  #include <contrib/dev/acpica/compiler/aslcompiler.h>
  #include <contrib/dev/acpica/compiler/dtcompiler.h>
  #include <contrib/dev/acpica/include/actables.h>
  
  #define _COMPONENT          DT_COMPILER
          ACPI_MODULE_NAME    ("dtutils")
  
  /* Local prototypes */
  
  static void
  DtSum (
      DT_SUBTABLE             *Subtable,
      void                    *Context,
      void                    *ReturnValue);
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtError
   *
   * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
   *              MessageId           - Index into global message buffer
   *              Op                  - Parse node where error happened
   *              ExtraMessage        - additional error message
   *
   * RETURN:      None
   *
   * DESCRIPTION: Common error interface for data table compiler
   *
   *****************************************************************************/
  
  void
  DtError (
      UINT8                   Level,
      UINT16                  MessageId,
      DT_FIELD                *FieldObject,
      char                    *ExtraMessage)
  {
  
      /* Check if user wants to ignore this exception */
  
      if (AslIsExceptionDisabled (Level, MessageId))
      {
          return;
      }
  
      if (FieldObject)
      {
          AslCommonError (Level, MessageId,
              FieldObject->Line,
              FieldObject->Line,
              FieldObject->ByteOffset,
              FieldObject->Column,
              Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
      }
      else
      {
          AslCommonError (Level, MessageId, 0,
              0, 0, 0, 0, ExtraMessage);
      }
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtNameError
   *
   * PARAMETERS:  Level               - Seriousness (Warning/error, etc.)
   *              MessageId           - Index into global message buffer
   *              Op                  - Parse node where error happened
   *              ExtraMessage        - additional error message
   *
   * RETURN:      None
   *
   * DESCRIPTION: Error interface for named objects
   *
   *****************************************************************************/
  
  void
  DtNameError (
      UINT8                   Level,
      UINT16                  MessageId,
      DT_FIELD                *FieldObject,
      char                    *ExtraMessage)
  {
  
      switch (Level)
      {
      case ASL_WARNING2:
      case ASL_WARNING3:
  
          if (Gbl_WarningLevel < Level)
          {
              return;
          }
          break;
  
      default:
  
          break;
      }
  
      if (FieldObject)
      {
          AslCommonError (Level, MessageId,
              FieldObject->Line,
              FieldObject->Line,
              FieldObject->ByteOffset,
              FieldObject->NameColumn,
              Gbl_Files[ASL_FILE_INPUT].Filename, ExtraMessage);
      }
      else
      {
          AslCommonError (Level, MessageId, 0,
              0, 0, 0, 0, ExtraMessage);
      }
  }
  
  
  /*******************************************************************************
   *
   * FUNCTION:    DtFatal
   *
   * PARAMETERS:  None
   *
   * RETURN:      None
   *
   * DESCRIPTION: Dump the error log and abort the compiler. Used for serious
   *              compile or I/O errors
   *
   ******************************************************************************/
  
  void
  DtFatal (
      UINT16                  MessageId,
      DT_FIELD                *FieldObject,
      char                    *ExtraMessage)
  {
  
      DtError (ASL_ERROR, MessageId, FieldObject, ExtraMessage);
  
  /*
   * TBD: remove this entire function, DtFatal
   *
   * We cannot abort the compiler on error, because we may be compiling a
   * list of files. We must move on to the next file.
   */
  #ifdef __OBSOLETE
      CmCleanupAndExit ();
      exit (1);
  #endif
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtStrtoul64
   *
   * PARAMETERS:  String              - Null terminated string
   *              ReturnInteger       - Where the converted integer is returned
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Simple conversion of a string hex integer constant to unsigned
   *              value. Assumes no leading "0x" for the constant.
   *
   * Portability note: The reason this function exists is because a 64-bit
   * sscanf is not available in all environments.
   *
   *****************************************************************************/
  
  ACPI_STATUS
  DtStrtoul64 (
      char                    *String,
      UINT64                  *ReturnInteger)
  {
      char                    *ThisChar = String;
      UINT32                  ThisDigit;
      UINT64                  ReturnValue = 0;
      int                     DigitCount = 0;
  
  
      /* Skip over any white space in the buffer */
  
      while ((*ThisChar == ' ') || (*ThisChar == '\t'))
      {
          ThisChar++;
      }
  
      /* Skip leading zeros */
  
      while ((*ThisChar) == '0')
      {
          ThisChar++;
      }
  
      /* Convert character-by-character */
  
      while (*ThisChar)
      {
          if (isdigit ((int) *ThisChar))
          {
              /* Convert ASCII 0-9 to Decimal value */
  
              ThisDigit = ((UINT8) *ThisChar) - '0';
          }
          else /* Letter */
          {
              ThisDigit = (UINT32) toupper ((int) *ThisChar);
              if (!isxdigit ((int) ThisDigit))
              {
                  /* Not A-F */
  
                  return (AE_BAD_CHARACTER);
              }
  
              /* Convert ASCII Hex char (A-F) to value */
  
              ThisDigit = (ThisDigit - 'A') + 10;
          }
  
          /* Insert the 4-bit hex digit */
  
          ReturnValue <<= 4;
          ReturnValue += ThisDigit;
  
          ThisChar++;
          DigitCount++;
          if (DigitCount > 16)
          {
              /* Value is too large (> 64 bits/8 bytes/16 hex digits) */
  
              return (AE_LIMIT);
          }
      }
  
      *ReturnInteger = ReturnValue;
      return (AE_OK);
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtGetFieldValue
   *
   * PARAMETERS:  Field               - Current field list pointer
   *
   * RETURN:      Field value
   *
   * DESCRIPTION: Get field value
   *
   *****************************************************************************/
  
  char *
  DtGetFieldValue (
      DT_FIELD                *Field)
  {
      if (!Field)
      {
          return (NULL);
      }
  
      return (Field->Value);
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtGetFieldType
   *
   * PARAMETERS:  Info                - Data table info
   *
   * RETURN:      Field type
   *
   * DESCRIPTION: Get field type
   *
   *****************************************************************************/
  
  UINT8
  DtGetFieldType (
      ACPI_DMTABLE_INFO       *Info)
  {
      UINT8                   Type;
  
  
      /* DT_FLAG means that this is the start of a block of flag bits */
      /* TBD - we can make these a separate opcode later */
  
      if (Info->Flags & DT_FLAG)
      {
          return (DT_FIELD_TYPE_FLAGS_INTEGER);
      }
  
      /* Type is based upon the opcode for this field in the info table */
  
      switch (Info->Opcode)
      {
      case ACPI_DMT_FLAG0:
      case ACPI_DMT_FLAG1:
      case ACPI_DMT_FLAG2:
      case ACPI_DMT_FLAG3:
      case ACPI_DMT_FLAG4:
      case ACPI_DMT_FLAG5:
      case ACPI_DMT_FLAG6:
      case ACPI_DMT_FLAG7:
      case ACPI_DMT_FLAGS0:
      case ACPI_DMT_FLAGS1:
      case ACPI_DMT_FLAGS2:
      case ACPI_DMT_FLAGS4:
  
          Type = DT_FIELD_TYPE_FLAG;
          break;
  
      case ACPI_DMT_NAME4:
      case ACPI_DMT_SIG:
      case ACPI_DMT_NAME6:
      case ACPI_DMT_NAME8:
      case ACPI_DMT_STRING:
  
          Type = DT_FIELD_TYPE_STRING;
          break;
  
      case ACPI_DMT_BUFFER:
      case ACPI_DMT_RAW_BUFFER:
      case ACPI_DMT_BUF7:
      case ACPI_DMT_BUF10:
      case ACPI_DMT_BUF16:
      case ACPI_DMT_BUF128:
      case ACPI_DMT_PCI_PATH:
  
          Type = DT_FIELD_TYPE_BUFFER;
          break;
  
      case ACPI_DMT_GAS:
      case ACPI_DMT_HESTNTFY:
      case ACPI_DMT_IORTMEM:
  
          Type = DT_FIELD_TYPE_INLINE_SUBTABLE;
          break;
  
      case ACPI_DMT_UNICODE:
  
          Type = DT_FIELD_TYPE_UNICODE;
          break;
  
      case ACPI_DMT_UUID:
  
          Type = DT_FIELD_TYPE_UUID;
          break;
  
      case ACPI_DMT_DEVICE_PATH:
  
          Type = DT_FIELD_TYPE_DEVICE_PATH;
          break;
  
      case ACPI_DMT_LABEL:
  
          Type = DT_FIELD_TYPE_LABEL;
          break;
  
      default:
  
          Type = DT_FIELD_TYPE_INTEGER;
          break;
      }
  
      return (Type);
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtGetBufferLength
   *
   * PARAMETERS:  Buffer              - List of integers,
   *                                    for example "10 3A 4F 2E"
   *
   * RETURN:      Count of integer
   *
   * DESCRIPTION: Get length of bytes needed to store the integers
   *
   *****************************************************************************/
  
  UINT32
  DtGetBufferLength (
      char                    *Buffer)
  {
      UINT32                  ByteLength = 0;
  
  
      while (*Buffer)
      {
          if (*Buffer == ' ')
          {
              ByteLength++;
  
              while (*Buffer == ' ')
              {
                  Buffer++;
              }
          }
  
          Buffer++;
      }
  
      return (++ByteLength);
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtGetFieldLength
   *
   * PARAMETERS:  Field               - Current field
   *              Info                - Data table info
   *
   * RETURN:      Field length
   *
   * DESCRIPTION: Get length of bytes needed to compile the field
   *
   * Note: This function must remain in sync with AcpiDmDumpTable.
   *
   *****************************************************************************/
  
  UINT32
  DtGetFieldLength (
      DT_FIELD                *Field,
      ACPI_DMTABLE_INFO       *Info)
  {
      UINT32                  ByteLength = 0;
      char                    *Value;
  
  
      /* Length is based upon the opcode for this field in the info table */
  
      switch (Info->Opcode)
      {
      case ACPI_DMT_FLAG0:
      case ACPI_DMT_FLAG1:
      case ACPI_DMT_FLAG2:
      case ACPI_DMT_FLAG3:
      case ACPI_DMT_FLAG4:
      case ACPI_DMT_FLAG5:
      case ACPI_DMT_FLAG6:
      case ACPI_DMT_FLAG7:
      case ACPI_DMT_FLAGS0:
      case ACPI_DMT_FLAGS1:
      case ACPI_DMT_FLAGS2:
      case ACPI_DMT_FLAGS4:
      case ACPI_DMT_LABEL:
      case ACPI_DMT_EXTRA_TEXT:
  
          ByteLength = 0;
          break;
  
      case ACPI_DMT_UINT8:
      case ACPI_DMT_CHKSUM:
      case ACPI_DMT_SPACEID:
      case ACPI_DMT_ACCWIDTH:
      case ACPI_DMT_IVRS:
      case ACPI_DMT_GTDT:
      case ACPI_DMT_MADT:
      case ACPI_DMT_PCCT:
      case ACPI_DMT_PMTT:
      case ACPI_DMT_SRAT:
      case ACPI_DMT_ASF:
      case ACPI_DMT_HESTNTYP:
      case ACPI_DMT_FADTPM:
      case ACPI_DMT_EINJACT:
      case ACPI_DMT_EINJINST:
      case ACPI_DMT_ERSTACT:
      case ACPI_DMT_ERSTINST:
      case ACPI_DMT_DMAR_SCOPE:
  
          ByteLength = 1;
          break;
  
      case ACPI_DMT_UINT16:
      case ACPI_DMT_DMAR:
      case ACPI_DMT_HEST:
      case ACPI_DMT_NFIT:
      case ACPI_DMT_PCI_PATH:
  
          ByteLength = 2;
          break;
  
      case ACPI_DMT_UINT24:
  
          ByteLength = 3;
          break;
  
      case ACPI_DMT_UINT32:
      case ACPI_DMT_NAME4:
      case ACPI_DMT_SIG:
      case ACPI_DMT_LPIT:
  
          ByteLength = 4;
          break;
  
      case ACPI_DMT_UINT40:
  
          ByteLength = 5;
          break;
  
      case ACPI_DMT_UINT48:
      case ACPI_DMT_NAME6:
  
          ByteLength = 6;
          break;
  
      case ACPI_DMT_UINT56:
      case ACPI_DMT_BUF7:
  
          ByteLength = 7;
          break;
  
      case ACPI_DMT_UINT64:
      case ACPI_DMT_NAME8:
  
          ByteLength = 8;
          break;
  
      case ACPI_DMT_STRING:
  
          Value = DtGetFieldValue (Field);
          if (Value)
          {
              ByteLength = strlen (Value) + 1;
          }
          else
          {   /* At this point, this is a fatal error */
  
              sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
              DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
              return (0);
          }
          break;
  
      case ACPI_DMT_GAS:
  
          ByteLength = sizeof (ACPI_GENERIC_ADDRESS);
          break;
  
      case ACPI_DMT_HESTNTFY:
  
          ByteLength = sizeof (ACPI_HEST_NOTIFY);
          break;
  
      case ACPI_DMT_IORTMEM:
  
          ByteLength = sizeof (ACPI_IORT_MEMORY_ACCESS);
          break;
  
      case ACPI_DMT_BUFFER:
      case ACPI_DMT_RAW_BUFFER:
  
          Value = DtGetFieldValue (Field);
          if (Value)
          {
              ByteLength = DtGetBufferLength (Value);
          }
          else
          {   /* At this point, this is a fatal error */
  
              sprintf (MsgBuffer, "Expected \"%s\"", Info->Name);
              DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, MsgBuffer);
              return (0);
          }
          break;
  
      case ACPI_DMT_BUF10:
  
          ByteLength = 10;
          break;
  
      case ACPI_DMT_BUF16:
      case ACPI_DMT_UUID:
  
          ByteLength = 16;
          break;
  
      case ACPI_DMT_BUF128:
  
          ByteLength = 128;
          break;
  
      case ACPI_DMT_UNICODE:
  
          Value = DtGetFieldValue (Field);
  
          /* TBD: error if Value is NULL? (as below?) */
  
          ByteLength = (strlen (Value) + 1) * sizeof(UINT16);
          break;
  
      default:
  
          DtFatal (ASL_MSG_COMPILER_INTERNAL, Field, "Invalid table opcode");
          return (0);
      }
  
      return (ByteLength);
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtSum
   *
   * PARAMETERS:  DT_WALK_CALLBACK:
   *              Subtable            - Subtable
   *              Context             - Unused
   *              ReturnValue         - Store the checksum of subtable
   *
   * RETURN:      Status
   *
   * DESCRIPTION: Get the checksum of subtable
   *
   *****************************************************************************/
  
  static void
  DtSum (
      DT_SUBTABLE             *Subtable,
      void                    *Context,
      void                    *ReturnValue)
  {
      UINT8                   Checksum;
      UINT8                   *Sum = ReturnValue;
  
  
      Checksum = AcpiTbChecksum (Subtable->Buffer, Subtable->Length);
      *Sum = (UINT8) (*Sum + Checksum);
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtSetTableChecksum
   *
   * PARAMETERS:  ChecksumPointer     - Where to return the checksum
   *
   * RETURN:      None
   *
   * DESCRIPTION: Set checksum of the whole data table into the checksum field
   *
   *****************************************************************************/
  
  void
  DtSetTableChecksum (
      UINT8                   *ChecksumPointer)
  {
      UINT8                   Checksum = 0;
      UINT8                   OldSum;
  
  
      DtWalkTableTree (Gbl_RootTable, DtSum, NULL, &Checksum);
  
      OldSum = *ChecksumPointer;
      Checksum = (UINT8) (Checksum - OldSum);
  
      /* Compute the final checksum */
  
      Checksum = (UINT8) (0 - Checksum);
      *ChecksumPointer = Checksum;
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtSetTableLength
   *
   * PARAMETERS:  None
   *
   * RETURN:      None
   *
   * DESCRIPTION: Walk the subtables and set all the length fields
   *
   *****************************************************************************/
  
  void
  DtSetTableLength (
      void)
  {
      DT_SUBTABLE             *ParentTable;
      DT_SUBTABLE             *ChildTable;
  
  
      ParentTable = Gbl_RootTable;
      ChildTable = NULL;
  
      if (!ParentTable)
      {
          return;
      }
  
      DtSetSubtableLength (ParentTable);
  
      while (1)
      {
          ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
          if (ChildTable)
          {
              if (ChildTable->LengthField)
              {
                  DtSetSubtableLength (ChildTable);
              }
  
              if (ChildTable->Child)
              {
                  ParentTable = ChildTable;
                  ChildTable = NULL;
              }
              else
              {
                  ParentTable->TotalLength += ChildTable->TotalLength;
                  if (ParentTable->LengthField)
                  {
                      DtSetSubtableLength (ParentTable);
                  }
              }
          }
          else
          {
              ChildTable = ParentTable;
  
              if (ChildTable == Gbl_RootTable)
              {
                  break;
              }
  
              ParentTable = DtGetParentSubtable (ParentTable);
  
              ParentTable->TotalLength += ChildTable->TotalLength;
              if (ParentTable->LengthField)
              {
                  DtSetSubtableLength (ParentTable);
              }
          }
      }
  }
  
  
  /******************************************************************************
   *
   * FUNCTION:    DtWalkTableTree
   *
   * PARAMETERS:  StartTable          - Subtable in the tree where walking begins
   *              UserFunction        - Called during the walk
   *              Context             - Passed to user function
   *              ReturnValue         - The return value of UserFunction
   *
   * RETURN:      None
   *
   * DESCRIPTION: Performs a depth-first walk of the subtable tree
   *
   *****************************************************************************/
  
  void
  DtWalkTableTree (
      DT_SUBTABLE             *StartTable,
      DT_WALK_CALLBACK        UserFunction,
      void                    *Context,
      void                    *ReturnValue)
  {
      DT_SUBTABLE             *ParentTable;
      DT_SUBTABLE             *ChildTable;
  
  
      ParentTable = StartTable;
      ChildTable = NULL;
  
      if (!ParentTable)
      {
          return;
      }
  
      UserFunction (ParentTable, Context, ReturnValue);
  
      while (1)
      {
          ChildTable = DtGetNextSubtable (ParentTable, ChildTable);
          if (ChildTable)
          {
              UserFunction (ChildTable, Context, ReturnValue);
  
              if (ChildTable->Child)
              {
                  ParentTable = ChildTable;
                  ChildTable = NULL;
              }
          }
          else
          {
              ChildTable = ParentTable;
              if (ChildTable == Gbl_RootTable)
              {
                  break;
              }
  
              ParentTable = DtGetParentSubtable (ParentTable);
  
              if (ChildTable->Peer == StartTable)
              {
                  break;
              }
          }
      }
  }
  
  
  /*******************************************************************************
   *
   * FUNCTION:    UtSubtableCacheCalloc
   *
   * PARAMETERS:  None
   *
   * RETURN:      Pointer to the buffer. Aborts on allocation failure
   *
   * DESCRIPTION: Allocate a subtable object buffer. Bypass the local
   *              dynamic memory manager for performance reasons (This has a
   *              major impact on the speed of the compiler.)
   *
   ******************************************************************************/
  
  DT_SUBTABLE *
  UtSubtableCacheCalloc (
      void)
  {
      ASL_CACHE_INFO          *Cache;
  
  
      if (Gbl_SubtableCacheNext >= Gbl_SubtableCacheLast)
      {
          /* Allocate a new buffer */
  
          Cache = UtLocalCalloc (sizeof (Cache->Next) +
              (sizeof (DT_SUBTABLE) * ASL_SUBTABLE_CACHE_SIZE));
  
          /* Link new cache buffer to head of list */
  
          Cache->Next = Gbl_SubtableCacheList;
          Gbl_SubtableCacheList = Cache;
  
          /* Setup cache management pointers */
  
          Gbl_SubtableCacheNext = ACPI_CAST_PTR (DT_SUBTABLE, Cache->Buffer);
          Gbl_SubtableCacheLast = Gbl_SubtableCacheNext + ASL_SUBTABLE_CACHE_SIZE;
      }
  
      Gbl_SubtableCount++;
      return (Gbl_SubtableCacheNext++);
  }
  
  
  /*******************************************************************************
   *
   * FUNCTION:    UtFieldCacheCalloc
   *
   * PARAMETERS:  None
   *
   * RETURN:      Pointer to the buffer. Aborts on allocation failure
   *
   * DESCRIPTION: Allocate a field object buffer. Bypass the local
   *              dynamic memory manager for performance reasons (This has a
   *              major impact on the speed of the compiler.)
   *
   ******************************************************************************/
  
  DT_FIELD *
  UtFieldCacheCalloc (
      void)
  {
      ASL_CACHE_INFO          *Cache;
  
  
      if (Gbl_FieldCacheNext >= Gbl_FieldCacheLast)
      {
          /* Allocate a new buffer */
  
          Cache = UtLocalCalloc (sizeof (Cache->Next) +
              (sizeof (DT_FIELD) * ASL_FIELD_CACHE_SIZE));
  
          /* Link new cache buffer to head of list */
  
          Cache->Next = Gbl_FieldCacheList;
          Gbl_FieldCacheList = Cache;
  
          /* Setup cache management pointers */
  
          Gbl_FieldCacheNext = ACPI_CAST_PTR (DT_FIELD, Cache->Buffer);
          Gbl_FieldCacheLast = Gbl_FieldCacheNext + ASL_FIELD_CACHE_SIZE;
      }
  
      Gbl_FieldCount++;
      return (Gbl_FieldCacheNext++);
  }
  
  
  /*******************************************************************************
   *
   * FUNCTION:    DtDeleteCaches
   *
   * PARAMETERS:  None
   *
   * RETURN:      None
   *
   * DESCRIPTION: Delete all local cache buffer blocks
   *
   ******************************************************************************/
  
  void
  DtDeleteCaches (
      void)
  {
      UINT32                  BufferCount;
      ASL_CACHE_INFO          *Next;
  
  
      /* Field cache */
  
      BufferCount = 0;
      while (Gbl_FieldCacheList)
      {
          Next = Gbl_FieldCacheList->Next;
          ACPI_FREE (Gbl_FieldCacheList);
          Gbl_FieldCacheList = Next;
          BufferCount++;
      }
  
      DbgPrint (ASL_DEBUG_OUTPUT,
          "%u Fields, Buffer size: %u fields (%u bytes), %u Buffers\n",
          Gbl_FieldCount, ASL_FIELD_CACHE_SIZE,
          (sizeof (DT_FIELD) * ASL_FIELD_CACHE_SIZE), BufferCount);
  
      Gbl_FieldCount = 0;
      Gbl_FieldCacheNext = NULL;
      Gbl_FieldCacheLast = NULL;
  
      /* Subtable cache */
  
      BufferCount = 0;
      while (Gbl_SubtableCacheList)
      {
          Next = Gbl_SubtableCacheList->Next;
          ACPI_FREE (Gbl_SubtableCacheList);
          Gbl_SubtableCacheList = Next;
          BufferCount++;
      }
  
      DbgPrint (ASL_DEBUG_OUTPUT,
          "%u Subtables, Buffer size: %u subtables (%u bytes), %u Buffers\n",
          Gbl_SubtableCount, ASL_SUBTABLE_CACHE_SIZE,
          (sizeof (DT_SUBTABLE) * ASL_SUBTABLE_CACHE_SIZE), BufferCount);
  
      Gbl_SubtableCount = 0;
      Gbl_SubtableCacheNext = NULL;
      Gbl_SubtableCacheLast = NULL;
  }
  