/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/*********************************************************************
 *
 * SOURCE FILE NAME = SVGAGEN.C
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS
 *
 * NOTES
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

/*
**      Include files
*/
#define PMIDEF_INCL
#include "svga.h"
#include "svgagen.h"

/*
** Prototypes
*/

void ErrorExit(int iErrorCode);

/*
** Externals
*/

extern USHORT far *pusSupportedModes;

/*
**      Local data
*/


USHORT ColNo = 0;
USHORT LineNo = 1;

ULONG CurrValue = 0;
CHAR CurrentToken[LINELEN];         /*            */
CHAR CurrVariable[LINELEN] = { 0 } ;

CHAR ch = 0, upch = 0;

PTOKENLIST ptokSetBank = NULL;
PTOKENLIST ptokUnLock = NULL;
PTOKENLIST ptokLock = NULL;
PTOKENLIST ptokCleanup = NULL;

/***************************************************************************
 *
 * FUNCTION NAME = pmiGetc()
 *
 * DESCRIPTION   =
 *
 *       Return the next character from the file.
 *       Data is read in blocks into an internal buffer and returned
 *       from there. This function will take care of filling the
 *       buffer when it empties or hasn't been read yet.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = FILE * f
 *                 NULL  - if no memory available
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

char pmiGetc(FILE * f)
{
  static char buffer[BUFFSIZE];         /* read buffer */
  static int buffpos = 0,buffcount = 0; /* buff ptrs */
  int bytesread;

  if (buffpos == buffcount)
  {
    if (!(bytesread = fread(&buffer, 1, BUFFSIZE, f)))
    {
      buffpos = buffcount = 0;
      return (EOF);
    }
    buffpos = 0;
    buffcount = bytesread;
  }
  return (buffer[buffpos++]);
}

/***************************************************************************
 *
 * FUNCTION NAME = NextChar()
 *
 * DESCRIPTION   =
 *
 *      Calls pmiGetc() to return the next character and updates the
 *      global variables 'ch' and 'upch' with the character and its
 *      uppercase equivalent, respectively.
 *
 * INPUT         = FILE * f
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void NextChar(FILE * f)
{
  ch = pmiGetc(f);

  if ((ch >= 'a') && (ch <= 'z'))
    upch = ch-(char)('a'-'A');

  else
    upch = ch;

  ColNo++;

  if (ch == '\n')
  {
    LineNo++;
    ColNo = 0;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = GetLongValue()
 *
 * DESCRIPTION   =
 *
 *      This is a bit convoluted because we can't use library functions.
 *      First check to see if string is a hex one and adjust pointer
 *        and radix as necessary. If radix forced, use it
 *      Note: the 'emit' statements make the operands 32-bit.
 *      Then process the string, adding numbers/hex digits.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG GetLongValue(char *s, USHORT ForceRadix)      //          
{
  ULONG v = 0;
  ULONG radix = 10;

  USHORT length= strlen(s);

//  if (!strcmp(s,"00563000"))
//  {
//    _asm int 3;
//    v = 0;
//  }
  if ((length  >= 1) && (s[1] == 'X'))
  {
    radix = 16;                        /* adjust radix to hex */
    s += 2;                            /* skip the '0X' part */
    length -= 2;
  }

  if (ForceRadix)
  {
    radix = ForceRadix;  //VIPER doesn't use 0x.
  }
  while (length--)
  {
    _asm {                      ;
      _emit 0x66                ;
      xor dx, dx                ; Do the multiply this way
      _emit 0x66                ;
      mov ax, word ptr v        ; to prevent library routines
      _emit 0x66                ;
      mul word ptr radix        ; being called in which aren't
      _emit 0x66                ;
      mov word ptr v, ax        ; desirable.
    }

    if (*s <= '9')
      v += (ULONG)(*s++ - '0');          /* handle number between 0-9 */
    else
      v += (ULONG)(*s++ - 'A'+ 10);       /* handle hex letters A-F */
  }
  return (v);
}

/***************************************************************************
 *
 * FUNCTION NAME = NextToken()
 *
 * DESCRIPTION   =
 *
 *      Returns the next token and updates appropriate global
 *      variables such as: the current variable name and the
 *      current numeric value just read.
 *      It returns the token type according to the token table
 *      passed in for searching                  
 *      If no table passed or no token found, it returns TOK_UNKNOWN
 *      and sets CurrentToken.
 *
 *      Comments ('C' style) will be skipped if encountered.
 *
 * INPUT         = FILE * f, TOK *Tokens
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN NextToken(FILE * f, TOK *Tokens)
{
  PMITOKEN tok = TOK_EOF;
  int i;
  USHORT radix;

  while (ch != EOF)
  {

    if (((upch >= 'A') && (upch <= 'Z')) || (upch == '['))
    {                                  /* look for keyword */
      i = 0;

      do
      {
        CurrentToken[i++] = upch;
        NextChar(f);
      }

      while (((upch >= 'A') && (upch <= 'Z')) || ((upch >= '0') && (upch <=
         '9')) || ((upch == ']')));
      CurrentToken[i] = '\0';

      if (Tokens == (TOK *) 0)           //          
         return(TOK_UNKNOWN);

      for (i = 0; Tokens[i].tok_txt; i++)
        if (!strcmp(CurrentToken, Tokens[i].tok_txt))
          return (Tokens[i].tok_val);
                                /* test for variable in range R0 - R255 */
      if ((CurrentToken[0] == 'R') && ((CurrentToken[1] >= '0') && (CurrentToken[1] <= '9')))
      {
        strcpy(CurrVariable, CurrentToken);
        return (TOK_PMIREG);
      }

      else
        return (TOK_ERROR);
    }

    else

      if (((upch >= '0') && (upch <= '9')) ||
         ((upch >=  'A') && (upch <= 'F')))
      {
        i = 0;
        radix = 10;
        do
        {
          CurrentToken[i++] = upch;
          if((upch >=  'A') && (upch <= 'F'))
            radix = 16;
          NextChar(f);
        }

        while ((upch == 'X') || ((upch >= '0') && (upch <= '9')) || ((upch >=
           'A') && (upch <= 'F')));
        CurrentToken[i] = '\0';
        CurrValue = GetLongValue(CurrentToken,radix);
        return (TOK_VALUE);
      }

      else

        switch (upch)
        {

          case ' ' :
          case '\t' :
          case '\n' :
          case ',' :
            NextChar(f);
            break;

          case '(' :
            NextChar(f);
            return (TOK_LPAREN);

          case ')' :
            NextChar(f);
            return (TOK_RPAREN);

          case '=' :
            NextChar(f);
            return (TOK_EQUALS);

          case ';' :
            NextChar(f);
            return (TOK_SEMICOLON);

          case '-' :
            NextChar(f);
            return (TOK_HYPHEN);

          case '|' :                    /* bitwise OR operation  */
            NextChar(f);
            return (TOK_REGOP_OR);

          case '&' :                    /* bitwise AND operation */
            NextChar(f);
            return (TOK_REGOP_AND);

          case '^' :                    /* bitwise XOR operation */
            NextChar(f);
            return (TOK_REGOP_XOR);

          case '<' :                    /* bitwise SHL operation */
            NextChar(f);
            return (TOK_REGOP_SHL);

          case '>' :                    /* bitwise SHR operation */
            NextChar(f);
            return (TOK_REGOP_SHR);

          case '/' :                   /* comment? */
            NextChar(f);

            if ((ch == '/') || (ch == '*'))

            {

              if (ch == '/')
              {                        /* skip to end-of-line */

                while ((ch != '\n') && (ch != EOF))
                  NextChar(f);

                if (ch == '\n')
                  NextChar(f);
              }

              else
              {                        /* skip to comment end */
                NextChar(f);

                do
                {

                  while ((ch != '*') && (ch != EOF))
                    NextChar(f);
                  NextChar(f);
                }

                while ((ch != '/') && (ch != EOF));
                NextChar(f);
              }
            }
            break;

          default  :
            NextChar(f);
            break;

        }

  }

  return (tok);
}

/***************************************************************************
 *
 * FUNCTION NAME = AddTrapRegEntry()
 *
 * DESCRIPTION   = Add entry to VGARegData array.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

BOOL AddTrapRegEntry(ULONG ulPort,
                     ULONG fIndexed,
                     ULONG ulRangeStart,
                     ULONG ulRangeEnd)
{
  PREGDATA pRegData = VGARegData;

  while (pRegData->Command != PMICMD_NONE) pRegData++;

  if (fIndexed)
  {
    pRegData->Command    = PMICMD_BOUTB;
    pRegData->R.PortIO.IndexPort  = (USHORT)ulPort;
    pRegData->R.PortIO.DataPort   = pRegData->R.PortIO.IndexPort + 1;
    pRegData->R.PortIO.NumEntries = (USHORT)(ulRangeEnd - ulRangeStart) + 1;
    pRegData->R.PortIO.StartIndex = (USHORT)ulRangeStart;
    pRegData->R.PortIO.Flags      = READWRITE_DATA;
  }
  else
  {
    pRegData->Command    = PMICMD_OUTB;
    pRegData->R.PortIO.IndexPort  = (USHORT)ulPort;
    pRegData->R.PortIO.NumEntries = NONE;
    pRegData->R.PortIO.StartIndex = NONE;
    pRegData->R.PortIO.Flags      = READWRITE_DATA;
  }

  if (pRegData->R.PortIO.Flags == READWRITE_DATA)
  {
    switch (pRegData->R.PortIO.IndexPort)
    {
      case SEQ_INDEXPORT:
        pRegData->Data = &SEQRegData[ulRangeStart];
        break;

      case CRT_INDEXPORT:
        pRegData->Data = &CRTRegData[ulRangeStart];
        break;

      case ATC_INDEXPORT:
        pRegData->Data = &ATCRegData[ulRangeStart];
        break;

      case GDC_INDEXPORT:
        pRegData->Data = &GDCRegData[ulRangeStart];
        break;

      default:
        if (fIndexed)
          pRegData->Data = &MiscRegData[ulRangeStart];
        else
          pRegData->Data = &MiscRegData[0];
        break;
    }
  }

  pRegData++;
  pRegData->Command = PMICMD_NONE;

  return (TRUE);
}

/*****************************************************************************
 *
 * FUNCTION NAME = ProcessTrapSection()
 *
 * DESCRIPTION   = NEEDS TO BE MODIFIED!!!!!
 *
 *    Trap registers section layout is as follows:
 *
 *     <port>[,<index range>];
 *
 *      0x3cd;
 *      0x3c4, 0x08-0x09, 0x10-0x12;
 *      0x3d4, 0x2b-0x2f;
 *      0x3ce, 0x0a-0x0e;
 *
 * INPUT         =
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PMITOKEN ProcessTrapSection(PMITOKEN tok, FILE * scriptfile)
{
  ULONG ulRangeStart, ulRangeEnd, ulPort, fIndexed;

  tok = NextToken(scriptfile,&Tokens[0]);
  do
  {

    fIndexed = FALSE;
    ulRangeEnd = 0;
    ulRangeStart = 0;

    if (tok != TOK_VALUE)
      return(TOK_ERROR);

    ulPort = CurrValue;
    tok = NextToken(scriptfile,&Tokens[0]);

    while ((tok != TOK_SEMICOLON) && (tok != TOK_EOF))
    {
      if (tok != TOK_VALUE)             /* get range start */
        return(TOK_ERROR);

      ulRangeStart = CurrValue;
      tok = NextToken(scriptfile,&Tokens[0]);   /* get the '-' */

      if (tok != TOK_HYPHEN)
        return(TOK_ERROR);

      tok = NextToken(scriptfile,&Tokens[0]);

      if (tok != TOK_VALUE)             /* get range end */
        return(TOK_ERROR);

      ulRangeEnd = CurrValue;

      if ((ulRangeEnd   > 0xff) ||
          (ulRangeStart > 0xff))
        return(TOK_ERROR);

      tok = NextToken(scriptfile,&Tokens[0]);

      fIndexed = TRUE;

      if (!AddTrapRegEntry(ulPort, fIndexed, ulRangeStart, ulRangeEnd))
//        return(TOK_ERROR_MEMORY);
        return(TOK_ERROR);

    }

    if (tok == TOK_SEMICOLON)
      tok = NextToken(scriptfile,&Tokens[0]);

    if (!fIndexed)
      if (!AddTrapRegEntry(ulPort, fIndexed, ulRangeStart, ulRangeEnd))
//        return(TOK_ERROR_MEMORY);
        return(TOK_ERROR);

  } while ((tok > TOK_SECT_END) && (tok != TOK_EOF));

  return (tok);
}

/***************************************************************************
 *
 * FUNCTION NAME = VARIndex()
 *
 * DESCRIPTION   =
 *
 *      Use current variable name to get its number for use as
 *      an index into the table of registers.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG VARIndex(VOID)
{
  ULONG v = 0;
  char *p;

  p = &CurrVariable[1];
  v = GetLongValue(p,10);
  return (v);
}

/*****************************************************************************
 *
 * FUNCTION NAME = AddToken()
 *
 * DESCRIPTION   = Add token to linked-list.
 *
 * INPUT         =
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void AddToken(PTOKENLIST * pptok, PMITOKEN pmitok, ULONG ulData)
{
  PTOKENLIST    pTmp;
  TOKENLIST     tokData;

  tokData.pmitok = pmitok;
  tokData.ulData = ulData;
  tokData.ptokNext = NULL;
  if (!*pptok)
  {
    *pptok = malloc(sizeof(TOKENLIST));
    **pptok = tokData;
  }
  else
  {
    for (pTmp = *pptok; pTmp->ptokNext; pTmp=pTmp->ptokNext);
    pTmp->ptokNext = malloc(sizeof(TOKENLIST));
    *pTmp->ptokNext = tokData;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = ParseWait()
 *
 * DESCRIPTION   = Parse and return values from a WAIT() command.
 *
 *      WAIT(<status port>, <test mask>, <count>, <timeout>, <0|1>);
 *
 *   Examples:
 *      Wait(0x3da, 0x08, 1, 0, 1); wait until vert retrace starts
 *      Wait(0x3da, 0x08, 1, 0, 0); wait until vert retrace ends
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ParseWait(PMITOKEN tok,
                   FILE * scriptfile,
                   PTOKENLIST * pptok)
{
  AddToken(pptok, TOK_WAIT, 0L);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get LPAREN */
  if (tok != TOK_LPAREN)
    return (TOK_ERROR);  /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);       /* get port value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);       /* get test mask value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get count value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get timeout value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get SET/CLEAR value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  if (CurrValue > 1)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get RPAREN */
  if (tok != TOK_RPAREN)
    return (TOK_ERROR);  /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);  /* get SEMICOLON */
  if (tok != TOK_SEMICOLON)
    return (TOK_ERROR);  /* force an error */

  return (tok);
}

/***************************************************************************
 *
 * FUNCTION NAME = ParseRMWB()
 *
 * DESCRIPTION   = Parse and return values from an RMWB() command.
 *
 *      RMWB(<Index Port>, <Data Port>, <index>, <AND mask>, <OR mask>);
 *      RMWW(<Read Port>, <Write Port>, <AND mask>, <OR mask>);
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ParseRMW(PMITOKEN tok,
                  FILE * scriptfile,
                  PTOKENLIST * pptok)
{
  PMITOKEN      tokBW;

  AddToken(pptok, tok, 0L);

  tokBW = tok;                  /* TOK_RMWBYTE/TOK_RMWWORD */

  tok = NextToken(scriptfile,&Tokens[0]);       /* get LPAREN */
  if (tok != TOK_LPAREN)
    return (TOK_ERROR);  /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);       /* get index port value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get data port value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  if (tokBW == TOK_RMWBI)
  {
    tok = NextToken(scriptfile,&Tokens[0]);/* get index value */
    if (tok != TOK_VALUE)
      return (TOK_ERROR);/* force an error */
    AddToken(pptok, TOK_VALUE, CurrValue);
  }

  tok = NextToken(scriptfile,&Tokens[0]);       /* get AND Mask value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get OR Mask value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);  /* get RPAREN */
  if (tok != TOK_RPAREN)
    return (TOK_ERROR);  /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);  /* get SEMICOLON */

  if (tok != TOK_SEMICOLON)
    return (TOK_ERROR);  /* force an error */

  return (tok);
}

/***************************************************************************
 *
 * FUNCTION NAME = ParseOutCmd()
 *
 * DESCRIPTION   = Parse and return values from an OUTB() or OUTW() command.
 *
 *          OUTB(<IO Port>, <data byte>|<Variable>);
 *          OUTW(<IO Port>, <data word>|<Variable>);
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ParseOutCmd(PMITOKEN tok,
                     FILE * scriptfile,
                     PTOKENLIST * pptok)
{
  AddToken(pptok, tok, 0L);

  tok = NextToken(scriptfile,&Tokens[0]);               /* get LPAREN */
  if (tok != TOK_LPAREN)
    return (TOK_ERROR);          /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);               /* get port value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);          /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);               /* get data/variable value */

  if ( !((tok == TOK_VALUE) || (tok == TOK_PMIREG)) )
    return (TOK_ERROR);          /* force an error */
  AddToken(pptok, tok, 0L);

  if (tok == TOK_VALUE)
    AddToken(pptok, TOK_VALUE, CurrValue);
  else
    AddToken(pptok, TOK_PMIREG, VARIndex());

  tok = NextToken(scriptfile,&Tokens[0]);               /* get RPAREN */

  if (tok != TOK_RPAREN)
    return (TOK_ERROR);          /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);               /* get SEMICOLON */

  if (tok != TOK_SEMICOLON)
    return (TOK_ERROR);          /* force an error */

  return (tok);

}

/***************************************************************************
 *
 * FUNCTION NAME = ParseInCmd()
 *
 * DESCRIPTION   = Parse and return values from an INB() or INW() command.
 *
 *          INB(<Variable>, <IO Port>);
 *          INW(<Variable>, <IO Port>);
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ParseInCmd(PMITOKEN tok,
                    FILE * scriptfile,
                    PTOKENLIST * pptok)
{
  AddToken(pptok, tok, 0L);

  tok = NextToken(scriptfile,&Tokens[0]);               /* get LPAREN */
  if (tok != TOK_LPAREN)
    return (TOK_ERROR);          /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);               /* get VARiable */
  if (tok != TOK_PMIREG)
    return (TOK_ERROR);          /* force an error */
  AddToken(pptok, TOK_PMIREG, VARIndex());

  tok = NextToken(scriptfile,&Tokens[0]);               /* get PORT value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);          /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);               /* get RPAREN */
  if (tok != TOK_RPAREN)
    return (TOK_ERROR);          /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);               /* get SEMICOLON */
  if (tok != TOK_SEMICOLON)
    return (TOK_ERROR);          /* force an error */

  return (tok);

}

/***************************************************************************
 *
 * FUNCTION NAME = ParseBlockCmd()
 *
 * DESCRIPTION   = Parse and return values from an BOUTB() or BINB() command.
 *
 *          BINB(<no of values>, <start index>, <Index Port>, <Data Port>);
 *          BOUTB(<no of values>, <start index>, <Index Port>, <Data Port>);
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ParseBlockCmd(PMITOKEN tok,
                       FILE * scriptfile,
                       PTOKENLIST * pptok)
{
  AddToken(pptok, tok, 0L);

  tok = NextToken(scriptfile,&Tokens[0]);       /* get LPAREN */
  if (tok != TOK_LPAREN)
    return (TOK_ERROR);  /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);       /* get count */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);       /* get start index */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);       /* get Index Port */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);       /* get Data Port */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);  /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);       /* get RPAREN */
  if (tok != TOK_RPAREN)
    return (TOK_ERROR);  /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);       /* get SEMICOLON */
  if (tok != TOK_SEMICOLON)
    return (TOK_ERROR);  /* force an error */

  return (tok);

}

/***************************************************************************
 *
 * FUNCTION NAME = ParseRegOp()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ParseRegOp(PMITOKEN tok,
                    FILE * scriptfile,
                    PTOKENLIST * pptok)
{
  ULONG v;

  v = VARIndex();
  if (v > 255)                          /* in range?      */
//    return(TOK_ERROR_VARIABLE);         /* force an error */
    return(TOK_ERROR);
  AddToken(pptok, tok, v);

  tok = NextToken(scriptfile,&Tokens[0]);               /* get equals or bitwise operator */
  AddToken(pptok, tok, 0L);
  switch (tok)
  {
    case TOK_REGOP_AND:
    case TOK_REGOP_OR:
    case TOK_REGOP_XOR:
    case TOK_REGOP_SHL:
    case TOK_REGOP_SHR:
      tok = NextToken(scriptfile,&Tokens[0]);   /* get equals */

    case TOK_EQUALS:
      break;

    default:
      return (TOK_ERROR);        /* force an error */
  }

  if (tok != TOK_EQUALS)
    return (TOK_ERROR);          /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);               /* get value */
  if (tok != TOK_VALUE)
    return (TOK_ERROR);          /* force an error */
  AddToken(pptok, TOK_VALUE, CurrValue);

  tok = NextToken(scriptfile,&Tokens[0]);               /* get SEMICOLON */
  if (tok != TOK_SEMICOLON)
    return (TOK_ERROR);          /* force an error */

  return (tok);
}

/***************************************************************************
 *
 * FUNCTION NAME = ParseMemOp()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ParseMemOp(PMITOKEN tok,
                    FILE * scriptfile,
                    PTOKENLIST * pptok)
{
  AddToken(pptok, tok, 0L);

  tok = NextToken(scriptfile,&Tokens[0]);               /* get LPAREN */
  if (tok != TOK_LPAREN)
    return (TOK_ERROR);          /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);               /* get destination value */
  //AddToken:  needs to be coded for variable types
  tok = NextToken(scriptfile,&Tokens[0]);               /* get source value */
  //AddToken:  needs to be coded for variable types

  tok = NextToken(scriptfile,&Tokens[0]);               /* get RPAREN */

  if (tok != TOK_RPAREN)
    return (TOK_ERROR);          /* force an error */

  tok = NextToken(scriptfile,&Tokens[0]);               /* get SEMICOLON */

  if (tok != TOK_SEMICOLON)
    return (TOK_ERROR);          /* force an error */

  return (tok);

}
/***************************************************************************
 *
 * FUNCTION NAME = ProcessCmdSection()
 *
 * DESCRIPTION   = Commands in a section are processed here.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

PMITOKEN ProcessCmdSection(PMITOKEN tok,
                           FILE * scriptfile,
                           PTOKENLIST * pptok)
{
  tok = NextToken(scriptfile,&Tokens[0]);
  do
  {

    if ((tok <= TOK_SM_BEGIN) || (tok >= TOK_SM_END))
      return (TOK_ERROR);       /* force an error */

    switch (tok)
    {

      case TOK_INB:
      case TOK_INW:
        tok = ParseInCmd(tok, scriptfile, pptok);
        break;

      case TOK_OUTB:
      case TOK_OUTW:
        tok = ParseOutCmd(tok, scriptfile, pptok);
        break;

      case TOK_BOUTB:
        tok = ParseBlockCmd(tok, scriptfile, pptok);
        break;

      case TOK_BINB:
        tok = ParseBlockCmd(tok, scriptfile, pptok);
        break;

      case TOK_RMWBI:
      case TOK_RMWWN:
        tok = ParseRMW(tok, scriptfile, pptok);
        break;

      case TOK_WAIT:
        tok = ParseWait(tok, scriptfile, pptok);
        break;

      case TOK_PMIREG:
        tok = ParseRegOp(tok, scriptfile, pptok);
        break;

      case TOK_READB:         /*            */
      case TOK_READW:
      case TOK_READDW:

      case TOK_WRITEB:
      case TOK_WRITEW:
      case TOK_WRITEDW:
        tok = ParseMemOp(tok, scriptfile, pptok);
        break;

      default:
        tok = TOK_ERROR;
        break;
    }

    if (tok == TOK_ERROR)
      return TOK_ERROR;

    if (tok != TOK_EOF)
      tok = NextToken(scriptfile,&Tokens[0]);

  }
  while ((tok > TOK_SM_BEGIN) && (tok < TOK_SM_END));

  return (tok);

}

/*****************************************************************************
 *
 * FUNCTION NAME = ParseScriptFile()
 *
 * DESCRIPTION   = Parse script file and load sections for
 *                 use in generating a generic PMI-file.
 *
 *                 Expected sections, as per PMI syntax are:
 *
 *                      [Lock]          - used as is once only.
 *                      [UnLock]        - used as is once only.
 *                      [Cleanup]       - used as is once only.
 *                      [SetBank]       - used as is once for each mode.
 *                      [TrapRegs]      - used to generate added mode data.
 *
 * INPUT         = FILE * scriptfile
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL ParseScriptFile(FILE *scriptfile)
{
  PMITOKEN tok;
  BOOL     fErrors = FALSE;

  tok = NextToken(scriptfile,&Tokens[0]);

  do
  {

    switch (tok)
    {
      case TOK_TRAPREGS:
        tok = ProcessTrapSection(tok, scriptfile);
        break;

      case TOK_SETBANK:
        tok = ProcessCmdSection(tok, scriptfile, &ptokSetBank);
        break;

      case TOK_UNLOCK:
        tok = ProcessCmdSection(tok, scriptfile, &ptokUnLock);
        break;

      case TOK_LOCK:
        tok = ProcessCmdSection(tok, scriptfile, &ptokLock);
        break;

      case TOK_CLEANUP:
        tok = ProcessCmdSection(tok, scriptfile, &ptokCleanup);
        break;

      default:
        tok = TOK_ERROR;
        break;
    }

    if (tok >= TOK_ERROR)
      fErrors = TRUE;

  }
  while (tok != TOK_EOF && !fErrors);

  return (!fErrors);
}

/*****************************************************************************
 *
 * FUNCTION NAME = AddRegData()
 *
 * DESCRIPTION   = Append REGDATA entries to those already in CHIPINFO.
 *                 Data to append must be terminated with PMICMD_NONE.
 *
 * INPUT         =
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void AddRegData(PREGDATA pRegDataSrc, PREGDATA pRegDataDest)
{
  /*
  ** Find end of list.
  */
  while (pRegDataDest->Command != PMICMD_NONE)
    pRegDataDest++;

  /*
  ** Now append stuff.
  */
  while (pRegDataSrc->Command != PMICMD_NONE)
    *pRegDataDest++ = *pRegDataSrc++;

  /*
  ** Make a new last entry
  */
  pRegDataDest->Command = PMICMD_NONE;
}

/*****************************************************************************
 *
 * FUNCTION NAME = BuildChipInfo()
 *
 * DESCRIPTION   = Build a CHIPINFO array entry
 *
 * INPUT         =
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void BuildChipInfo(PCHIPINFO    pChipInfo,
                   USHORT       Int10Mode,
                   PCHIPHEADER  pChipHdr,
                   PREGDATA     pSetBank,
                   PREGDATA     pRegData)
{
  pChipInfo->Int10Mode = Int10Mode;
  pChipInfo->pChipHdr  = pChipHdr;
//            pChipInfo->pSetBank  = pSetBank;
  AddRegData(pRegData, pChipInfo->pRegData);
}

/*****************************************************************************
 *
 * FUNCTION NAME = BuildRegDataArray()
 *
 * DESCRIPTION   = Build an array of REGDATA entries from token list.
 *
 * INPUT         =
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PREGDATA BuildRegDataArray(PTOKENLIST ptok)
{
  PREGDATA      pRegData, pRegTmp;
  PTOKENLIST    ptokTmp;
  USHORT        usTotal = 1;

  /*
  ** Total up how many entries we need.
  */
  for (ptokTmp = ptok; ptokTmp != NULL; ptokTmp = ptokTmp->ptokNext)
  {
    switch (ptokTmp->pmitok)
    {
      case TOK_INB:   case TOK_INW:
      case TOK_OUTB:  case TOK_OUTW:
      case TOK_BOUTB: case TOK_BINB:
      case TOK_RMWBI:  case TOK_RMWWN:
      case TOK_WAIT:     case TOK_PMIREG:
        usTotal++;
        break;
    }
  }

  if (pRegData = malloc(sizeof(REGDATA)*usTotal))
  {

    pRegTmp = pRegData;

    ptokTmp = ptok;

    while (ptokTmp)
    {
      switch (ptokTmp->pmitok)
      {
        case TOK_INB:
             case TOK_INW:
          if (ptokTmp->pmitok == TOK_INB)
            pRegTmp->Command = PMICMD_INB;
          else
            pRegTmp->Command = PMICMD_INW;

          ptokTmp = ptokTmp->ptokNext;  /* variable */
          pRegTmp->R.PortIO.IndexPort = (USHORT)ptokTmp->ulData;
          ptokTmp = ptokTmp->ptokNext;  /* port */
          pRegTmp->R.PortIO.StartIndex = (USHORT)ptokTmp->ulData;
          break;

        case TOK_OUTB:
        case TOK_OUTW:
          if (ptokTmp->pmitok == TOK_OUTB)
            pRegTmp->Command = PMICMD_OUTB;
          else
            pRegTmp->Command = PMICMD_OUTW;

          ptokTmp = ptokTmp->ptokNext;  /* port */
          pRegTmp->R.WPortIO.Port = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* VAR/Value */
          pRegTmp->R.PortIO.Flags = (ptokTmp->pmitok == TOK_PMIREG) ? WRITEREG_DATA : WRITEONLY_DATA;

          ptokTmp = ptokTmp->ptokNext;  /* variable index/data value */

          if (pRegTmp->R.PortIO.Flags == WRITEREG_DATA)
            pRegTmp->R.PortIO.StartIndex = (USHORT)ptokTmp->ulData;
          else
            pRegTmp->Data = (PBYTE)&ptokTmp->ulData;
          break;

        case TOK_BINB:
        case TOK_BOUTB:
          if (ptokTmp->pmitok == TOK_BINB)
            pRegTmp->Command = PMICMD_BINB;
          else
            pRegTmp->Command = PMICMD_BOUTB;

          pRegTmp->R.PortIO.Flags = WRITEREG_DATA;

          ptokTmp = ptokTmp->ptokNext;  /* count       */
          pRegTmp->R.PortIO.NumEntries = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* start index */
          pRegTmp->R.PortIO.StartIndex = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* index port  */
          pRegTmp->R.PortIO.IndexPort = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* data port   */
          pRegTmp->R.PortIO.DataPort = (USHORT)ptokTmp->ulData;
          break;

        case TOK_RMWBI:
          pRegTmp->Command = PMICMD_RMWBI;

          ptokTmp = ptokTmp->ptokNext;  /* index port  */
          pRegTmp->R.RMW.IndPort = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* data port   */
          pRegTmp->R.RMW.DPort = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* index       */
          pRegTmp->R.RMW.Index = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* AND mask    */
          pRegTmp->R.RMW.ANDMask = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* OR mask    */
          pRegTmp->R.RMW.ORMask = (USHORT)ptokTmp->ulData;
          break;

             case TOK_RMWWN:
          pRegTmp->Command = PMICMD_RMWWN;

          ptokTmp = ptokTmp->ptokNext;  /* index port  */
          pRegTmp->R.RMW.IndPort = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* data port   */
          pRegTmp->R.RMW.DPort = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* AND mask    */
          pRegTmp->R.RMW.ANDMask = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* OR mask    */
          pRegTmp->R.RMW.ORMask = (USHORT)ptokTmp->ulData;
          break;

        case TOK_WAIT:
          pRegTmp->Command = PMICMD_WAIT;

          ptokTmp = ptokTmp->ptokNext;  /* index port  */
          pRegTmp->R.Wait.IPort = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* mask value  */
          pRegTmp->R.Wait.Mask = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* count       */
          pRegTmp->R.Wait.Count = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* timeout     */
          pRegTmp->R.Wait.TimeOut = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* set/reset   */
          pRegTmp->R.Wait.WValue = (USHORT)ptokTmp->ulData;

          break;

             case TOK_PMIREG:
          pRegTmp->Command = PMICMD_REGOP;
          pRegTmp->R.RegOp.DstRegIndex = (USHORT)ptokTmp->ulData;

          ptokTmp = ptokTmp->ptokNext;  /* reg op      */

          switch (ptokTmp->pmitok)
          {
            case TOK_REGOP_AND:
              pRegTmp->R.RegOp.Operation = REGISTER_AND;
              break;

            case TOK_REGOP_OR:
              pRegTmp->R.RegOp.Operation = REGISTER_OR;
              break;

            case TOK_REGOP_XOR:
              pRegTmp->R.RegOp.Operation = REGISTER_XOR;
              break;

            case TOK_REGOP_SHL:
              pRegTmp->R.RegOp.Operation = REGISTER_SHL;
              break;

            case TOK_REGOP_SHR:
              pRegTmp->R.RegOp.Operation = REGISTER_SHR;
              break;

            case TOK_EQUALS:
              pRegTmp->R.RegOp.Operation = WRITEONLY_DATA;
              break;

          }
          ptokTmp = ptokTmp->ptokNext;  /* data value  */
          pRegTmp->R.RegOp.RegSize = 1;          /* default size is one byte */
          pRegTmp->Data = (PBYTE)&ptokTmp->ulData;

          break;
      }

      pRegTmp++;
      ptokTmp = ptokTmp->ptokNext;

    }
    pRegTmp->Command = PMICMD_NONE;

  }

  return(pRegData);
}

/*****************************************************************************
 *
 * FUNCTION NAME = LoadScriptFile()
 *
 * DESCRIPTION   = Load a script file, if it exists, from same directory
 *                 as PMI-file (\OS2\SVGADATA.PMI or SVGADATA.DOS).
 *
 *                 Use data in script file and/or local info to dynamically
 *                 build a generic CHIPINFO array.
 *
 * INPUT         = File name (PMI-file)
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void LoadScriptFile(char * pmi_fname)
{
  char          scr_fname[_MAX_PATH];
  USHORT far    *pusModes = pusSupportedModes, i;
  PCHIPINFO     pChipInfo;
  PCHIPHEADER   pChipHdr;
  FILE          *scriptfile;
  BOOL          fFileLoaded, fScriptFileError = FALSE;

  usNumModes = 3;                       /* start with 3 VGA modes */
  while (*pusModes++ != 0xffff) usNumModes++;

  if ( !(VGAChipSet = malloc(sizeof(CHIPINFO) * usNumModes)) )
    ErrorExit(ERROR_NUM_MEMORY);

  memset(VGAChipSet, 0, sizeof(CHIPINFO) * usNumModes);

  strcpy(scr_fname, pmi_fname);
  *strrchr(scr_fname, '.') = '\0';
  strcat(scr_fname, ".scr");

  if (scriptfile = fopen(scr_fname, "r"))
  {
    if (fFileLoaded = ParseScriptFile(scriptfile))
    {
      VGASetBank = BuildRegDataArray(ptokSetBank);
      VGALock    = BuildRegDataArray(ptokLock);
      VGAUnLock  = BuildRegDataArray(ptokUnLock);
      VGACleanup = BuildRegDataArray(ptokCleanup);
    }
    else
    {
      fScriptFileError = TRUE;
      printf("Error in scriptfile at line %d, col %d\n", LineNo, ColNo);
    }

    fclose(scriptfile);
  }

  if (!fScriptFileError)
  {

    pChipInfo = VGAChipSet;

    /*
    ** Do basic VGA modes first
    */
    BuildChipInfo(pChipInfo, 0x12,
                  &ChipInfoHeader[GRAPHICS_640x480x16],
                  VGASetBank, VGARegData);
    pChipInfo++;
    BuildChipInfo(pChipInfo, 0x01,
                  &ChipInfoHeader[TEXT_40x25],
                  VGASetBank, VGARegData);
    pChipInfo++;
    BuildChipInfo(pChipInfo, 0x03,
                  &ChipInfoHeader[TEXT_80x25],
                  VGASetBank, VGARegData);
    pChipInfo++;

    /*
    ** Use VESA information to generate data with
    ** VGARegData as template for register data.
    */
    if (pusModes = pusSupportedModes)
    {
      while (*pusModes != 0xffff)
      {
        pChipHdr = ChipInfoHeader;

        for (i=0; i<usSizeChipInfoHeader; i++, pChipHdr++)

          if (*pusModes == pChipHdr->usVESAModeNumber)
          {
            BuildChipInfo(pChipInfo,
                          *pusModes,
                          pChipHdr,
                          VGASetBank,
                          VGARegData);
            pChipInfo++;
          }

        pusModes++;
      }
    }
  }
}


/*****************************************************************************
 *
 * FUNCTION NAME = SetupChipInfo()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PCHIPINFO SetupChipInfo(INT Adapter, INT Chip, BOOL fGeneric)
{
  PCHIPINFO ChipInfo = NULL;
  INT i;
  static union REGS regs;
  CHAR szCardName[20] = "UNKNOWN";                              /*          */
  CHAR szManufacturerName[128];                                 /*          */

  /*
  ** Setup some basic default values.
  */
  sAdapter.usSizeDeclarations = 0;                              /*          */
  sAdapter.ulMMIOBaseAddress = 0L;                              /*          */
  sAdapter.FormatSectionFlag = CALL_NONE;                       /*          */
  sAdapter.RefreshTable = NULL;                                 /*          */
  sAdapter.ulTotalMemory = sSVGA.Memory;                        /*          */

  if (fGeneric)
  {
    /*
    ** usNumModes set up when script file loaded.
    */
    pszAdapter = GENERIC_ADAPTER;
    pszChipset = GENERIC_CHIPSET;
    strcpy( szManufacturerName, "UNKNOWN" );                    /*          */
    return (VGAChipSet);
  }
  else
  {
    strcpy(sAdapter.DLLName,"IBMGPMI.DLL");                     /*          */
    sAdapter.FormatSectionFlag |= CALL_IDENTIFY;                /*          */
    /*
    ** Find the adapter in our internal names table.
    */
    for(i=0;i<sizeof(Adapters)/sizeof(ADAPTERS);i++)
    {
      if(Adapters[i].ID == Adapter)
      {
        pszAdapter = Adapters [i].Name;
        pszChipset = (Chip                                      /*          */
                      ? ChipsetName [i] [Chip-1]                /*          */
                      : ppszUnknownChipNames [0]);              /*          */
        if (sOEM.Manufacturer != DEFAULT_MANUFACTURER)          /*          */
          strcpy( szManufacturerName,                           /*          */
                  manufacturer[sOEM.Manufacturer] );            /*          */
        else                                                    /*          */
          strcpy( szManufacturerName,                           /*          */
                  Adapters[i].Manufacturer );                   /*          */
        if(sOEM.Manufacturer == LACUNA_MANUFACTURER)            /*          */
        {                                                       /*          */
          sAdapter.usBusType = MCA_BUS;                         /*          */
          strcpy( sAdapter.szRevision, SPECIALCASE );           /*          */
          sAdapter.RefreshTable = &S3_Lacuna_Refresh_Table[0];  /*          */
          strcpy(szCardName, "IBM");                            /*          */
        }                                                       /*          */
/*@V3.0YEE04 removed next 2 lines. MCA bus incorrect */
//      else if (sOEM.Manufacturer == ORCHID_MANUFACTURER)      /*          */
//        sAdapter.usBusType = MCA_BUS;                         /*          */
      }
    }
  }
  /*
  ** Fixup and initialize any table entries, such as refresh...
  ** This depends on the level of support available in the ibmgpmi.dll
  ** for the adapter in question. The rules are as follows:
  ** 1) refresh support for a specific adapter exist in the ibmgpmi.dll
  **    Edit refresh table and set OEMString to "chipname card name, adapter_manufacturer name"
  ** 2) refresh support exists for a set of on-chip clock based adapters for
  **    a particular chip:
  **    Edit refresh table and set OEMString to "chipname GENERIC, chip_manufacturer name"
  **    It is possible to define any other names, like GENERIC_CLASS1 or such to distinguish
  **    between two different clock implementations. Usually, this is not needed.
  ** 3) there is no refresh support.
  **    Don't edit the refresh table and set OEMString to "chipname UNKNOWN, chip_manufacturer name"
  ** 4) Generic chip support: via INT10 or a thru an input script
  **    Don't edit the refresh table and set OEMString to "GENERIC UNKNOWN, UNKNOWN"
  */
  switch (Adapter)
  {
    case  ATI_ADAPTER :
      switch (Chip)
      {
        case  ATI_18800_CHIP :
          ChipInfo = ATIChipSet1;
          usNumModes = usSizeATIChipSet1;
          break;
        case  ATI_28800_CHIP :
          ChipInfo = ATIChipSet2;
          usNumModes = usSizeATIChipSet2;
          break;
        case  ATI_38800_CHIP :                                  /*          */
          MiscRegData [0x20] = 0x0040;  /* A8514_SUBSYSCTRL */  /*          */
          ChipInfo = ATIChipSet3;                               /*          */
          usNumModes = usSizeATIChipSet3;                       /*          */
//        ChipInfoHeader[GRAPHICS_800x600x256].usVESAModeNumber = VESA_OLD_800_600_256; /*          */
          break;                                                /*          */
        case  ATI_68800_CHIP :                                  /*          */
//            sAdapter.RefreshTable = &ATIMach32_GenRefresh_Table[0];/*          */
//                     sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;   /*          */
          strcpy(szCardName, "GENERIC");
          MiscRegData [0x20] = 0x0040;  /* A8514_SUBSYSCTRL */  /*          */
          ChipInfo = ATIChipSet3;                               /*          */
          usNumModes = usSizeATIChipSet3;                       /*          */
//        ChipInfoHeader[GRAPHICS_800x600x256].usVESAModeNumber = VESA_OLD_800_600_256; /*          */
          break;                                                /*          */
        case  ATI_88800_CHIP :                                  /*          */
          MiscRegData [0x20] = 0x0040;  /* A8514_SUBSYSCTRL */  /*          */
          ChipInfo = ATIChipSet4;                               /*          */
          usNumModes = usSizeATIChipSet4;                       /*          */
          strcpy(szCardName, "GENERIC");
          /*
          **            May enable the call to pfnPMISetMode
           sAdapter.FormatSectionFlag |= CALL_SET_MODE;
          */
//        ChipInfoHeader[GRAPHICS_800x600x256].usVESAModeNumber = VESA_OLD_800_600_256; /*          */
          break;                                                /*          */
      }
      break;

    case CIRRUS_ADAPTER:
      if (Chip <= CIRRUS_5424_CHIP)
      {
         ChipInfo = CirrusChipSet1;
         usNumModes = usSizeCirrusChipSet1;
      }
      else
      {
         ChipInfo = CirrusChipSet2;
         usNumModes = usSizeCirrusChipSet2;
         if ((Chip >= CIRRUS_543X_CHIP) &&                       /*          */
             (sOEM.Manufacturer != STB_MANUFACTURER))            /*          */
         {                                                       /*          */
            sOEM.Manufacturer = CIRRUS_MANUFACTURER;             /*          */
            sAdapter.RefreshTable = &Cirrus543x_Refresh_Table[0];/*          */
            sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;  /*          */
            strcpy(szCardName, "GENERIC");                       /*          */
         }                                                       /*          */
      } /* endif */
      break;

    case  IBM_ADAPTER :
      GetXGAInstance();
      ChipInfo = IBMChipSet1;
      usNumModes = usSizeIBMChipSet1;
      break;

    case  S3_ADAPTER :
      if (Chip <= S3_86C928_CHIP)
      {
        ChipInfo = S3ChipSet1;
        usNumModes = usSizeS3ChipSet1;
        if (sOEM.Manufacturer == NUMBER9_MANUFACTURER)          /*          */
        {                                                       /*          */
          sAdapter.RefreshTable = &S3_N9_Refresh_Table[0];      /*          */
          sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;   /*          */
          strcpy(szCardName, "9GXE");                           /*          */
        }                                                       /*          */
        else if (sOEM.Manufacturer == STB_MANUFACTURER)         /*          */
        {                                                       /*          */
          sAdapter.RefreshTable = &STB_Refresh_Table[0];        /*          */
          sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;   /*          */
          strcpy(szCardName, "STB_CARD");                       /*          */
        }                                                       /*          */
        /*
        **            Diamond Stealth clock code is too dirty to
        ** execute as 32bit. Several attempts to link and call it as
        ** 16 bit in ibmgpmi.dll failed. An attempt to convert it to 32
        ** bit failed (eeprom read as junk).So for the time being,
        ** SetDiamondClk is executed by bvhsvga, not by IBMGPMI.
        */
//      else  if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)    /*          */
//      {                                                       /*          */
//        sAdapter.RefreshTable = NULL;                         /*          */
//        /*no refresh entries. Need DOS utility*/              /*          */
//        strcpy(szCardName, "STEALTH");                        /*          */
//      }                                                       /*          */
        else if (!(sOEM.Manufacturer == DIAMOND_MANUFACTURER) &&/*          */
                 !(sOEM.Manufacturer == LACUNA_MANUFACTURER))   /*          */
        {                                                       /*          */
          if (Chip == S3_86C805_CHIP)                           /*           */
            sAdapter.RefreshTable = &S3_805GenRefresh_Table[0]; /*          */
          else
            sAdapter.RefreshTable = &S3_928GenRefresh_Table[0]; /*          */
          sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;   /*          */
          strcpy(szCardName, "GENERIC");                        /*          */
        }                                                       /*          */
      }
      else
      {
        ChipInfo = S3ChipSet2;
        usNumModes = usSizeS3ChipSet2;
        if (sOEM.Manufacturer == NUMBER9_MANUFACTURER)          /*@V3.0YEE01*/
        {
          if (sDACINFO.DACFamily == ATT498_DAC)
          {
            strcpy(szCardName, "ICD2061");
            sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;
          }
          else if (sDACINFO.DACFamily == TI3025_DAC)            /*@V3.0YEE02*/
            strcpy(szCardName, "TI3025");

          sAdapter.RefreshTable = &S3_N9x64_Refresh_Table[0];
          sAdapter.RefreshDynamic = &S3N9x64Refresh[0];
        }
        else
        {
          if (sDACINFO.DACFamily == S3SDAC_DAC)                 /*          */
          {
             strcpy(szCardName, "SDAC");                        /*          */
             sAdapter.RefreshTable = &S3_SDAC_Refresh_Table[0]; /*          */
             sAdapter.RefreshDynamic = &S3SDACRefresh[0];       /*@V3.0YEE01*/
          }

          else if (sDACINFO.DACFamily == ATT498_DAC)            /*@V3.0YEE01*/
          {                                                     /*          */
             strcpy(szCardName, "ICD2061");                     /*          */
             sAdapter.RefreshTable = &S3_ICD2061_Refresh_Table[0]; /*          */
             sAdapter.RefreshDynamic = &S3ICD2061Refresh[0];    /*@V3.0YEE01*/
             sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;   /*          */
          }                                                     /*          */

          /** use same refresh information as SDAC for SGS1703 **/
          else if (sDACINFO.DACFamily == SGS1703_DAC)           /*@V3.0YEE05*/
          {
             if (sOEM.ManufacturerData == DELL)                 /*@V3.0YEE06*/
             {                                                  /*@V3.0YEE06*/
                sAdapter.RefreshTable = &S3_N9x64_Refresh_Table[0]; /*@V3.0YEE06*/
                sAdapter.RefreshDynamic = &S3DELLRefresh[0];    /*@V3.0YEE06*/
             }                                                  /*@V3.0YEE06*/
             else
             {
                sAdapter.RefreshTable = &S3_SDAC_Refresh_Table[0]; /*@V3.0YEE06*/
                sAdapter.RefreshDynamic = &S3SDACRefresh[0];    /*@V3.0YEE06*/
             }
          }

          else if (sDACINFO.DACFamily == BT485_DAC)             /*@V3.0YEE02*/
          {
             strcpy(szCardName, "ICD2061");                     /*@V3.0YEE03*/
             if (sOEM.Manufacturer == ORCHID_MANUFACTURER)
             {
               strcpy(szCardName, "ORCHID");                    /*@V3.0YEE04*/
               sAdapter.RefreshTable = &S3_964ORCHID_Refresh_Table[0]; /*@V3.0YEE04*/
               sAdapter.RefreshDynamic = &S3964ORCHIDRefresh[0];       /*@V3.0YEE03*/
             }
             else                                               /*@V3.0YEE03*/
             {
               sAdapter.RefreshTable = &S3_964DIAMOND_Refresh_Table[0];
               sAdapter.RefreshDynamic = &S3964DIAMONDRefresh[0];
             }
             sAdapter.FormatSectionFlag |= CALL_MONITOR_TIMINGS;
          }

          else            /* ATT409 or ICS5342 used by VP S3864   @V3.0YEE07*/
          {
             /*  use these tables since standard on VP systems    @V3.0YEE07*/
             sAdapter.RefreshTable = &S3_SDAC_Refresh_Table[0]; /*@V3.0YEE07*/
             sAdapter.RefreshDynamic = &S3SDACRefresh[0];       /*@V3.0YEE07*/
          }
        }                                                       /*          */
      }
      break;


    case  TSENG_ADAPTER :

      /* first see if the Extended BIOS supports the Monitor Freq functions */
      /* if it does, flag true and use it later */

      regs.x.ax = 0x1201;
      regs.x.bx = 0x00f1;
      int86(VBIOS, &regs, &regs);
      if (regs.h.al == 0x12)
      {
         TSENGBIOSMonitorSupport = TRUE;
      }
      else
      {
         TSENGBIOSMonitorSupport = FALSE;
      }

//                /* see if Diamond with W32 */
//                /* if it is, flag true and use it later */
//          
//                if (IsDiamondW32())                           /*JWK10*/
//                {                                             /*JWK10*/
//                    TSENGDiamondW32 = TRUE;                   /*JWK10*/
//                    strcpy(szCardName, "STEALTH");            /*          */
//                }                                             /*JWK10*/
//                else                                          /*JWK10*/
//                {                                             /*JWK10*/
//                    TSENGDiamondW32 = FALSE;                  /*JWK10*/
//                }                                             /*JWK10*/
                                                                /*JWK10*/
      /* now set up the chipinfo and fixup instances if required */

      switch (Chip)
      {
        case TSENG_ET3000_CHIP :
          ChipInfo = TsengChipSetET3000;
          usNumModes = usSizeTsengChipSetET3000;
          pMonitorTable = &TsengMonitorTableET4000[0];        /*JWK10 use ET4000 */
          usSizeMonitorTable = usSizeTsengMonitorTableET4000; /*JWK10 use ET4000 */
          strcpy(szCardName, "GENERIC");                /*          */
          sAdapter.RefreshTable =                       /*          */
             &Tseng_Refresh_TableET4000[0];             /*          */
          break;

        case TSENG_ET4000_CHIP :
          ChipInfo = TsengChipSetET4000;
          usNumModes = usSizeTsengChipSetET4000;
          pMonitorTable = &TsengMonitorTableET4000[0];                   /*JWK10*/
          usSizeMonitorTable= usSizeTsengMonitorTableET4000;            /*JWK10*/

          strcpy(szCardName, "GENERIC");                /*          */
          sAdapter.RefreshTable =                       /*          */
             &Tseng_Refresh_TableET4000[0];                     /*          */
          if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)        /*          */
          {                                                     /*          */
            strcpy(szCardName, "SPEEDSTAR");                    /*          */
            sAdapter.RefreshTable =                             /*          */
              &Diamond_24_Refresh_Table[0];                     /*          */
            sAdapter.FormatSectionFlag |=                       /*          */
              CALL_MONITOR_TIMINGS;                             /*          */
          }                                                     /*          */
          break;

        case TSENG_ET4000W32_CHIP :                             /*          */
          ChipInfo = TsengChipSetW32;                           /*          */
          usNumModes = usSizeTsengChipSetW32;                   /*          */
          if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)        /*          */
          {
            sAdapter.RefreshTable =                       /*          */
               &Tseng_Refresh_TableW32x[0];               /*          */
            sAdapter.FormatSectionFlag |=                 /*          */
               CALL_MONITOR_TIMINGS;                      /*          */
            pMonitorTable = &DiaMonTableW32[0];           /*JWK10*/
            usSizeMonitorTable = usSizeDiaMonTableW32;    /*JWK10*/
            strcpy(szCardName, "STEALTH");
          }
          else                                            /*            */
          {
            strcpy(szCardName, "GENERIC");
            pMonitorTable = &TsengMonitorTableW32[0];             /*JWK10*/
            usSizeMonitorTable = usSizeTsengMonitorTableW32;      /*JWK10*/
            sAdapter.RefreshTable =                       /*          */
              &Tseng_Refresh_TableW32[0];                /*          */
          }
          GetTSENGBaseIO();                                     /*          */
          GetTSENGBaseMMIO();                                   /*          */
          break;                                                /*          */

          default:                                              /*          */
        case TSENG_ET4000W32I_CHIP :                            /*          */
        case TSENG_ET4000W32IB_CHIP :                           /*          */
        case TSENG_ET4000W32IC_CHIP :                           /*          */
        case TSENG_ET4000W32ID_CHIP :                           /*          */
          ChipInfo = TsengChipSetW32i;                          /*          */
          usNumModes = usSizeTsengChipSetW32i;                  /*          */
          if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)        /*          */
          {
            sAdapter.RefreshTable =                       /*          */
               &Tseng_Refresh_TableW32x[0];               /*          */
            sAdapter.FormatSectionFlag |=                 /*          */
               CALL_MONITOR_TIMINGS;                      /*          */
            pMonitorTable = &DiaMonTableW32[0];           /*JWK10*/
            usSizeMonitorTable = usSizeDiaMonTableW32;    /*JWK10*/
            strcpy(szCardName, "STEALTH");
          }
          else                                            /*            */
          {
            strcpy(szCardName, "GENERIC");
            pMonitorTable = &TsengMonitorTableW32x[0];            /*JWK10*/
            usSizeMonitorTable = usSizeTsengMonitorTableW32x;          /*JWK10*/
            sAdapter.RefreshTable =                       /*          */
               &Tseng_Refresh_TableW32x[0];                   /*          */
          }
          GetTSENGBaseIO();                                     /*          */
          GetTSENGBaseMMIO();                                   /*          */
          break;                                                /*          */

        case TSENG_ET4000W32PA_CHIP :                           /*          */
        case TSENG_ET4000W32PB_CHIP :                           /*          */
        case TSENG_ET4000W32PC_CHIP :                           /*          */
        case TSENG_ET4000W32PD_CHIP :                           /*          */
        case TSENG_ET4000W32PX_CHIP :                           /*          */
          ChipInfo = TsengChipSetW32p;                          /*          */
          usNumModes = usSizeTsengChipSetW32p;                  /*          */
          if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)        /*          */
          {
            sAdapter.RefreshTable =                       /*          */
               &Tseng_Refresh_TableW32x[0];               /*          */
            sAdapter.FormatSectionFlag |=                 /*          */
               CALL_MONITOR_TIMINGS;                      /*          */
            pMonitorTable = &DiaMonTableW32[0];           /*JWK10*/
            usSizeMonitorTable = usSizeDiaMonTableW32;    /*JWK10*/
            strcpy(szCardName, "STEALTH");
          }
          else                                            /*            */
          {
            strcpy(szCardName, "GENERIC");
            pMonitorTable = &TsengMonitorTableW32x[0];            /*JWK10*/
            usSizeMonitorTable = usSizeTsengMonitorTableW32x;          /*JWK10*/
            sAdapter.RefreshTable =                       /*          */
               &Tseng_Refresh_TableW32x[0];                   /*          */
          }
          GetTSENGBaseIO();                                     /*          */
          GetTSENGBaseMMIO();                                   /*          */
          break;                                                /*          */
      }                                                         /*          */
                                                                /*          */
                                                                /*          */
      for (i=0; i<(INT)usNumModes; i++)                         /*          */
      {
         FixInstance(sSVGA.AdapterType, sSVGA.ChipType, &ChipInfo[i]);
      }

      if (TSENGEMRBase)                                         /*          */
      { /* setup declarations */                                /*          */
        sAdapter.ulMMIOBaseAddress = TSENGEMRBase;              /*          */
        sAdapter.pDecSection = &TSENGDeclarations[0];           /*          */
        sAdapter.usSizeDeclarations =  usSizeTSENGDeclaration;
      }


//                if (TSENGDiamondW32)                              /*          */
//                {                                                 /*          */
//                    strcpy(szCardName, "STEALTH");                /*          */
//                    sAdapter.RefreshTable =                       /*          */
//                       &Tseng_Refresh_TableW32x[0];               /*          */
//                    sAdapter.FormatSectionFlag |=                 /*          */
//                       CALL_MONITOR_TIMINGS;                      /*          */
//                    pMonitorTable = &DiaMonTableW32[0];           /*JWK10*/
//                    usSizeMonitorTable = usSizeDiaMonTableW32;    /*JWK10*/
//                }                                                 /*          */

      break;

    case  TRIDENT_ADAPTER :
      switch (Chip)
      {
        case  TRIDENT_8800_CHIP :
          ChipInfo = TridentChipSet1;
          usNumModes = usSizeTridentChipSet1;
          break;
        case  TRIDENT_8900_CHIP :
          ChipInfo = TridentChipSet2;
          usNumModes = usSizeTridentChipSet2;
          break;
      }
      break;
    case  VIDEO7_ADAPTER :
      switch (Chip)
      {
        case  VIDEO7_HT205_CHIP :
          ChipInfo = HeadlandChipSet1;
          usNumModes = usSizeHeadlandChipSet1;
          break;
        case  VIDEO7_HT208_CHIP :
          ChipInfo = HeadlandChipSet2;
          usNumModes = usSizeHeadlandChipSet2;
          break;
        case  VIDEO7_HT209_CHIP :
          ChipInfo = HeadlandChipSet3;
          usNumModes = usSizeHeadlandChipSet3;
          break;
      }
      break;
    case  WEITEK_ADAPTER :
      if (Chip == WEITEK_P9000_CHIP)
      {
        ChipInfo = WeitekChipSet1;
        usNumModes = usSizeWeitekChipSet1;
      }
      if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)            /*          */
      {                                                         /*          */
        strcpy(szCardName, "VIPER");                            /*          */
        sAdapter.usBusType = VLB_BUS;                           /*          */
        sAdapter.ulMMIOBaseAddress = VIPER_MMIO_ADDRESS;        /*          */
        sAdapter.pDecSection = &WeitekDeclarations[0];          /*          */
        sAdapter.usSizeDeclarations = usSizeWeitekDeclaration;  /*          */
        sAdapter.RefreshTable = &Diamond_Viper_Refresh_Table[0];/*          */
        sAdapter.usLinearAperture =                             /*          */
          WEITEK_LINEAR_APERTURE_INDEX;                         /*          */
        sAdapter.FormatSectionFlag |=                           /*          */
          LINEAR_APERTURE_DECLARED | CALL_MONITOR_TIMINGS;      /*          */
      }                                                         /*          */
      break;

    case  WESTERNDIG_ADAPTER :
      ChipInfo = ParadiseChipSet3;                              /*          */
      usNumModes = usSizeParadiseChipSet3;
      switch (Chip)
      {
        case  WESTERNDIG_PVGA1A_CHIP :
          ChipInfo = ParadiseChipSet1;
          usNumModes = usSizeParadiseChipSet1;
          break;
        case  WESTERNDIG_WD9000_CHIP :
          ChipInfo = ParadiseChipSet2;                          /*          */
          usNumModes = usSizeParadiseChipSet2;
          break;                                                /*          */
        case  WESTERNDIG_WD9011_CHIP :
        case  WESTERNDIG_WD9030_CHIP :
        case  WESTERNDIG_WD9026_CHIP :                          /*          */
        case  WESTERNDIG_WD9027_CHIP :                          /*          */
          ChipInfo = ParadiseChipSet3;                          /*          */
          usNumModes = usSizeParadiseChipSet3;
          break;
        case  WESTERNDIG_WD9024_CHIP :                          /*          */
          ChipInfo = ParadiseChipSet4;                          /*          */
          usNumModes = usSizeParadiseChipSet4;                  /*          */
          break;                                                /*          */
        case  WESTERNDIG_WD9031_CHIP :                          /*          */
          ChipInfo = ParadiseChipSet5;                          /*          */
          usNumModes = usSizeParadiseChipSet5;                  /*          */
          if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)        /*          */
          {                                                     /*          */
            strcpy(szCardName, "SPEEDSTAR");                    /*          */
            sAdapter.RefreshTable =                             /*          */
              &Diamond_24_Refresh_Table[0];                     /*          */
            sAdapter.FormatSectionFlag |=                       /*          */
              CALL_MONITOR_TIMINGS;                             /*          */
          }                                                     /*          */
          break;                                                /*          */
        case  WESTERNDIG_WD9033_CHIP :                          /*          */
          ChipInfo = ParadiseChipSet6;                          /*          */
          usNumModes = usSizeParadiseChipSet6;                  /*          */
          break;                                                /*          */
      }
      /*!!What does this xlat into?*/                           /*          */
      for (i = 0;                                               /*          */
           (i < MAX_MODES)                                      /*          */
           && (ChipInfo[i].pChipHdr != NULL);                   /*          */
           i++)                                                 /*          */
      {                                /*            */
        if ((Chip >= WESTERNDIG_WD9030_CHIP) &&    /*            ,          */
                                                                /*          */
           (ChipInfo[i].pChipHdr->usTextRows == 43) &&          /*          */
           (ChipInfo[i].pChipHdr->usBytesPerScanLine == 132))
        {                                                       /*          */
          ChipInfo[i].pChipHdr->usTextRows = 44;                /*          */
          ChipInfo[i].pChipHdr->ulPageLength = 11616;           /*          */
          ChipInfo[i].pChipHdr->ulSaveSize = 11616;             /*          */
          ChipInfo[i].pChipHdr->usYResolution = 396;            /*          */
        }

      }
      break;
  }

  sprintf( sAdapter.szOEMString,                                /*          */
           "%s %s, %s",                                         /*          */
           pszChipset,                                          /*          */
           szCardName,                                          /*          */
           szManufacturerName );                                /*          */
  return (ChipInfo);
}





