/*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 = SVGA.C
 *
 * DESCRIPTIVE NAME = Utility to create SVGA.PMI file.
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION
 *
 *   This program determines which SVGA chip set is installed and creates a
 *   file containing chip set specific register information used by the base
 *   video handlers in setting video modes.  This utility creates the OS/2
 *   Version 2.11 SVGADATA.PMI file.
 *
 *        Dependencies: None
 *        Restrictions: Runs in Real Mode
 *        Patch Label: N/A
 *
 *      Entry Points: main()
 *
 * FUNCTIONS
 *
 * NOTES
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

/*
**      Include files
*/

#define CHIPS_INCL
#define PMIDEF_INCL
#define PMI_TOKEN_ARRAY
#include "svga.h"
#include <io.h>

/*
**              Global variables
*/

CHAR    PMIFName [_MAX_PATH];
CHAR    VIDEOCFGFName [_MAX_PATH];                              /*          */

/* Must define a value for sSVGA, sOEM, and XGAInstance */      /*          */
/* or else it will not be in DGROUP */                          /*          */
/* where IdentifySVGA expects them to be! */                    /*          */
OEMSVGAINFO sSVGA = {0};                          /*          *//*          */
OURADAPTERINFO sAdapter = {0};                                  /*          */
OEMINFO sOEM = {0};                                             /*          */
USHORT  XGAInstance = 0;                          /*          *//*          */

/* bus types used as indices into this table */                 /*          */
CHAR *BusName[BUS_MAX+1] =                                      /*          */
{"ISA",   "VLB",   "PCI",   "EISA",  "PCMCIA", "MCA"};          /*          */

/*
** Variable declaration section. Used by memory mapped adapters
** to define registers. Format: register name, register offset.
** Specify all the registers which need to be programmed for a
** successful mode set and restore. This includes drawing and
** parameter registers.
*/

UCHAR   DisplayMonitorTable = 0;
UCHAR   SetDefaultMonitor = 0;
UCHAR   DosParm = 0;
USHORT  TSENGDiamondW32EntryMonitorData = 0;                    /*JWK26*/
BOOL fInstall = FALSE;                                          /*          */
BOOL fDebug   = FALSE;


#define DEFAULT_CIRRUS_MONITOR  3

CHAR    * CirrusMessage[] =
{
"\t\tMonitors supported by Cirrus Logic GD542X SVGA chipset\n",
" Monitor description       Key    Horiz Frequency*",
"--------------------------------------------------",
" VGA                      0        31.5KHz",
" 8514 compatible          1        31.5KHz - 35.5KHz(interlaced)",
" SVGA compatible          2        31.5KHz - 35.1KHz",
" Extended SVGA            3        31.5KHz - 35.5KHz",
" Multifrequency           4        31.5KHz - 37.8KHz",
" Extended multifrequency  5        31.5KHz - 48.0KHz",
" Super multifrequency     6        31.5KHz - 56.0KHz",
" Ext super multifrequency 7        31.5KHz - 64.0KHz\n",
"*Horizontal frequency: This information should be available in the",
" monitor manual.",
" Enter the desired monitor key (0,1,2,3,4,5,6,7):",
};

DACINFO sDACINFO= {DEFAULT_DAC,0};

/*
** Pointer to VESA modes, if supported by BIOS.
*/
BOOL            fVesaBIOS = FALSE;
USHORT far      *pusSupportedModes = NULL;

FILE *textfile;
CHAR *comments[] =
{
  COMMENT_MSG_SETMISCOUTPUT,
  COMMENT_MSG_SETSEQUENCER,
  COMMENT_MSG_LOCKREGS,
  COMMENT_MSG_UNLOCKREGS,
  COMMENT_MSG_SETEXTSEQ,
  COMMENT_MSG_SETCRT,
  COMMENT_MSG_SETATC,
  COMMENT_MSG_SETGDC,
  COMMENT_MSG_SETPOS,
  COMMENT_MSG_SETENHANCED,                      /*            *//*          */
  COMMENT_MSG_HICOLOR,                          /*            */
  COMMENT_MSG_SETMEMORYREGS,                    /*            */
  COMMENT_MSG_CLOCK_CHIP,                       /*            */
  COMMENT_MSG_SETOTHER,                                         /*          */
} ;

CHAR *errors[] =
{
  ERROR_MSG_UNSUPPORTED,
  ERROR_MSG_NEEDVESA,
  ERROR_MSG_FULLSCREEN,
  ERROR_MSG_DELETE,
  ERROR_MSG_PARM,
  ERROR_MSG_MEMORY,
  ERROR_MSG_ADAP_NOT_CONFIGURED,
} ;

CHAR * fileheader[] =
{
  FILE_HEADER,
};

char * lockheader[] =                                           /*          */
{                                                               /*          */
  LOCK_HEADER1,                                                 /*          */
  LOCK_HEADER2,                                                 /*          */
  LOCK_HEADER3,                                                 /*          */
};                                                              /*          */


CHAR * manufacturer [MANUFACTURER_MAX+1] =                      /*          */
{
  "UNKNOWN",                                                    /*          */
  "Diamond Computer Systems Inc.",                              /*          */
  "Orchid Technology, Inc.",                                    /*          */
  "Number Nine Computer Corp.",                                 /*          */
  "Artist Graphics",                                            /*          */
  "IBM Corporation",                                            /*          */
  "STB Corporation",                                            /*          */
  "S3 Incorporated",                                            /*          */
  "Cirrus Logic, Inc.",                                         /*          */
  "miro Computer Products AG",                                  /*          */
  "VideoLogic Limited",                                         /*          */
  "IBM Corporation",                                            /*@V3.0YEE07*/
};

CHAR * szAdapterSpecific = " (Adapter Specific)";               /*JWK10*/

/*
**           
*/
typedef struct _DIAM_MONITORS
{
  CHAR name[10];
  BYTE VRefr[3]; //index 0 640x480, 1 800x600, 2 1024x768
}DIAM_MONITORS;

DIAM_MONITORS DiamondMonitorTableET[] =                 /*            ET4000 version*/
{
  {"NEC2A",{60,56,43}},
  {"IBM8514",{60,0,43}},
  {"NEX3FGX",{72,72,60}},
  {"NEC3FG",{72,72,60}},
  {"NEC4FG",{72,72,70}},
  {"NEC5FG",{72,72,72}},
  {"CS1572FS",{60,72,60}},
  {"CS1024NI",{60,72,60}},
};

DIAM_MONITORS DiamondMonitorTableWD[] =                 /*            WD version*/
{
  {"NEC2A",{60,56,43}},
  {"NEC3FG",{72,72,60}},
  {"NEX3FGX",{72,72,60}},
  {"NEC4FG",{72,72,70}},
  {"NEC5FG",{72,72,72}},
  {"SONY1304",{72,72,70}},
  {"CS1024NI",{60,72,60}},
};

PSZ pszAdapter = NULL;
PSZ pszChipset = NULL;

ULONG aulRelockInfo [MAX_LOCKUNLOCKCMD];                        /*          */
ULONG aulScratchRegs [0x100];                                   /*          */
PORTS PortList[MAX_PORTS] = {0};
USHORT PortCount;

USHORT  usInterlaceMode;

USHORT  usNumModes;

PTSENG_MONITORS pMonitorTable;                                  /*JWK10*/
USHORT  usSizeMonitorTable;                                     /*JWK10*/
char    Refresh[5] = {-1};                                      /*@V3.0YEE02*/
UCHAR   GenerateRefresh = 0;                                    /*@V3.0YEE02*/
char    MaxRefresh = -1;                                        /*@V3.0YEE02*/

UCHAR far * pBiosData = (UCHAR far *)0x400000;
UCHAR EntryBIOSData88;
UCHAR EntryBIOSData89;
CHAR  **lastcomment = NULL;                                     /*          */

PSADAPTERINFO psCurAdapterInfo;                                 /*          */

/*
**              Prototypes
*/

VOID LoadScriptFile(CHAR *);
extern VOID _far TextDelay (VOID);                              /*          */
extern VOID _far IdentifySVGA (VOID);                           /*          */
extern VOID _far GetXGAInstance (VOID);                         /*          */
extern USHORT TsengGetVerticalRefreshRate(USHORT nHorz, USHORT Flags); /*          *//*JWK08*/
extern USHORT TsengSetVerticalRefreshRate(USHORT nHorz, USHORT nRate, USHORT nBPP, USHORT Flags); /*          */
extern USHORT TsengGetVerticalPolarity(USHORT nHorz);           /*          */
extern USHORT TsengGetHorizontalPolarity(USHORT nHorz);         /*          */
extern USHORT TsengGetMonitorCableType(VOID);                   /*JWK10*/
extern USHORT MonitorCableData;                                 /*JWK10*/
extern VOID ShowYourStuff( PCHIPINFO ChipInfo,  INT Adapter,  INT Chip );

/*****************************************************************************
 *
 * FUNCTION NAME = SaveEntryRefreshRates(INT Adapter, INT Chip)  // JWK26
 * DESCRIPTION   = Determine and store refresh rates in Entry_Refresh_Table
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID SaveEntryRefreshRates(INT Adapter, INT Chip)
{
    register INT i = 0;

    EntryBIOSData88 = pBiosData[0x88];    /*jwk */
    EntryBIOSData89 = pBiosData[0x89];

    while(i < MAX_REFRESH_MODES && Entry_Refresh_Table[i].usYResolution)
    {
        switch(Adapter)
        {

           case TSENG_ADAPTER:

               Entry_Refresh_Table[i].DefaultVRefresh = (BYTE)TsengGetVerticalRefreshRate(Entry_Refresh_Table[i].usXResolution, 0);
               break;



           default:
               break;

        }
        i++;
    }

    if (TSENGDiamondW32)
    {
        outp(0x3bf, 0x03);  /* unlock */
        outp(0x3b8, 0xa0);
        outp(0x3d8, 0xa0);

        outp(CRT_INDEXPORT,0x31);
        TSENGDiamondW32EntryMonitorData = inp(CRT_DATAPORT);
    }




}

/*****************************************************************************
 *
 * FUNCTION NAME = RestoreEntryRefreshRates(Adapter, Chip) // JWK26
 *
 * DESCRIPTION   = Set refresh rates to values stored in Entry_Refresh_Table
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID RestoreEntryRefreshRates(INT Adapter, INT Chip)
{
    register INT i = 0;
    USHORT bTemp;

    pBiosData[0x88] = EntryBIOSData88;    /*jwk */
    pBiosData[0x89] = EntryBIOSData89;


    while(i < MAX_REFRESH_MODES && Entry_Refresh_Table[i].usYResolution)
    {
        if (  (Entry_Refresh_Table[i].DefaultVRefresh != NO_REFRESH)
           && (Entry_Refresh_Table[i].DefaultVRefresh != REFRESH_DISABLED)
           && (Entry_Refresh_Table[i].DefaultVRefresh != TSENG_REFRESH_UNKNOWN) )
        {
            switch(Adapter)
            {

                case TSENG_ADAPTER:

                    TsengSetVerticalRefreshRate(Entry_Refresh_Table[i].usXResolution, Entry_Refresh_Table[i].DefaultVRefresh ,0,0);
                    break;

                default:
                    break;

            }
        }
        i++;
    }


    if (TSENGDiamondW32)
    {
        outp(0x3bf, 0x03);  /* unlock */
        outp(0x3b8, 0xa0);
        outp(0x3d8, 0xa0);

        outp(CRT_INDEXPORT,0x31);
        bTemp = inp(CRT_DATAPORT);

        bTemp &= ~0x0f;
        bTemp |= ((TSENGDiamondW32EntryMonitorData) & 0x0f);   /* set monitor type that supports this mode */

        outp(CRT_DATAPORT,bTemp);
    }


}

/*****************************************************************************
 *
 * FUNCTION NAME = WriteComment()
 *
 * DESCRIPTION   = Write the given lines of text to the textfile as a 'C'
 *                 style comment block.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID WriteComment(INT lines,CHAR **s)
{
  register INT i;

  if( s != lastcomment )                                        /*          */
  {                                                             /*          */
    lastcomment = s;                                            /*          */
    fprintf(textfile, "/*\n");
    for (i = 0; i < lines; i++)
      fprintf(textfile, " *\t%s\n", s[i]);
    fprintf(textfile, " */\n\n");
  }                                                             /*          */
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = InpDelay()
 *
 * DESCRIPTION   = Inputs from a port with an IO delay
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BYTE InpDelay(                                                  /*          */
  USHORT usPort )                                               /*          */
{
  TextDelay();
  return( (BYTE) inp( psCurAdapterInfo->                        /*          */
                        pusfnSVGAAdjustedPort( usPort ) ) );    /*          */
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = InpwDelay()
 *
 * DESCRIPTION   = Inputs from a port with an IO delay
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

USHORT InpwDelay(                                               /*          */
  USHORT usPort )
{
  TextDelay();
  return( (USHORT) inpw( psCurAdapterInfo->
                           pusfnSVGAAdjustedPort( usPort ) ) );
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = OutpDelay()
 *
 * DESCRIPTION   = Outputs to a port with an IO delay
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID OutpDelay(                                                 /*          */
  USHORT usPort,                                                /*          */
  BYTE bData )
{
  TextDelay();
  outp( psCurAdapterInfo->                                      /*          */
          pusfnSVGAAdjustedPort( usPort ),                      /*          */
        bData );
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = OutpwDelay()
 *
 * DESCRIPTION   = Outputs to a port with an IO delay
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID OutpwDelay(                                                /*          */
  USHORT usPort,
  USHORT usData )
{
  TextDelay();
  outpw( psCurAdapterInfo->
           pusfnSVGAAdjustedPort( usPort ),
         usData );
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = SVGAAdjustedPort()
 *
 * DESCRIPTION   = Adjusts standard port addresses as necessary
 *
 * INPUT         = usStandardPort
 * OUTPUT        = usAdjustedPort
 *
 * RETURN-ERROR  = NONE
 * RETURN-NORMAL = NONE
 *
 ****************************************************************************/

USHORT SVGAAdjustedPort(                                        /*          */
  USHORT usStandardPort )
{
  return( usStandardPort );
}

/*****************************************************************************
 *
 * FUNCTION NAME = GetCurrentMonitorSelection()
 *
 * DESCRIPTION   = This contains code which attempts to format the current
 *                 monitor configuration file according to the special knowledge
 *                 about chipsets/adapters that we have. It handles Speedstar24,
 *                 Generic S3 and Number 9 S3 at this time. The current settings
 *                 are set in the _refresh_table for the chipset.           
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/
VOID GetCurrentMonitorSelection(INT Adapter, INT Chip)
{
  UCHAR cMonitorBits = 0;
  UCHAR cMonitorBits2 = 0;                                      /*          */
  USHORT us864RefreshBits = 0;                                  /*          */
  static union REGS regs;                                       /*@V3.0YEE01*/
  static struct SREGS sregs;                                    /*@V3.0YEE01*/
  SEDIDINFOBLOCK EDIDinfo = { 0 } ;                             /*@V3.0YEE01*/
  PSEDIDINFOBLOCK EDIDbuff = &EDIDinfo;                         /*@V3.0YEE01*/
  USHORT HorzPixel;                                             /*@V3.0YEE01*/
  BYTE   VertRef;                                               /*@V3.0YEE01*/
  UCHAR  i;                                                     /*@V3.0YEE02*/

  if ((Adapter != TSENG_ADAPTER) &&
      (Adapter != WESTERNDIG_ADAPTER) &&
      (Adapter != S3_ADAPTER) &&
      (Adapter != CIRRUS_ADAPTER))                              /*          */
     return;

  /*JWK10 for Diamond with TSENGW32 (Stealth 32/64)*/

  if( Adapter == TSENG_ADAPTER)
  {
      outp(0x3bf, 0x03);  /* unlock */
      outp(0x3b8, 0xa0);
      outp(0x3d8, 0xa0);

      if ((Chip == TSENG_ET4000_CHIP)
          && (sOEM.Manufacturer == DIAMOND_MANUFACTURER) )
      {

          /*
          ** Read CRT 31, bit 0
          */

          outp(CRT_INDEXPORT, 0x31);
          cMonitorBits |= (BYTE)inp(CRT_DATAPORT) & 0x1;
          /*
          ** Bits 2 and 3 are bits 5,6 of the BIOS data area, off 489
          */
          cMonitorBits |= ((BYTE) pBiosData[0x89] & 0x60) >> 4;
          //          
          strcpy(&sAdapter.MonitorName[0],&DiamondMonitorTableET[cMonitorBits&0x7].name[0]);
          Diamond_24_Refresh_Table[MON_INDEX_640].DefaultVRefresh =
             DiamondMonitorTableET[cMonitorBits&0x7].VRefr[MON_INDEX_640];
          Diamond_24_Refresh_Table[MON_INDEX_800].DefaultVRefresh =
             DiamondMonitorTableET[cMonitorBits&0x7].VRefr[MON_INDEX_800];
          Diamond_24_Refresh_Table[MON_INDEX_1024].DefaultVRefresh =
             DiamondMonitorTableET[cMonitorBits&0x7].VRefr[MON_INDEX_1024];
      }
      else /* not Diamond ET4000*/
      {
          if (TSENGDiamondW32)
          {

              /*
              ** Read CRT 31, bits 0-3 to get monitor type
              */

              outp(CRT_INDEXPORT, 0x31);
              cMonitorBits = (UCHAR)(inp(CRT_DATAPORT) & 0x0f);
              cMonitorBits++;
              TSENGMonitorRefresh[4] = cMonitorBits;
              strcpy(pszMonitorBuffer,&pMonitorTable[TSENGMonitorRefresh[4]].name[0]);       /*JWK26*/

          }

          /* JWK26 update our knowlege of the monitor, if not already set */

          if (  (!SetDefaultMonitor)
             && (!DisplayMonitorTable) )
          {

              TSENGMonitorRefresh[MON_INDEX_640 ] = TsengGetVerticalRefreshRate(640, 0);
              TSENGMonitorRefresh[MON_INDEX_800 ] = TsengGetVerticalRefreshRate(800, 0);
              TSENGMonitorRefresh[MON_INDEX_1024] = TsengGetVerticalRefreshRate(1024,0);
              TSENGMonitorRefresh[MON_INDEX_1280] = TsengGetVerticalRefreshRate(1280,0);

              /* if monitor selection allows, increase pmi refresh entries */          /*JWK26*/

              for (i=0;i<4;i++)                                                              /*JWK26*/
              {                                                                              /*JWK26*/
                  if ( (TSENGMonitorRefresh[i] > TSENGMaxMonitorRefresh[i])                  /*JWK26*/
                    && (TSENGMonitorRefresh[i] != REFRESH_DISABLED)                          /*JWK26*/
                    && (TSENGMonitorRefresh[i] != NO_REFRESH) )                              /*JWK26*/
                  {                                                                          /*JWK26*/
                      TSENGMaxMonitorRefresh[i] = TSENGMonitorRefresh[i];                    /*JWK26*/
                  }                                                                          /*JWK26*/
              }                                                                              /*JWK26*/
          }

          strcpy(&sAdapter.MonitorName[0],pszMonitorBuffer);  /*JWK26*/
          if (TSENGMonitorRefresh[4]) strcat( &sAdapter.MonitorName[0], szAdapterSpecific);

          sAdapter.RefreshTable[MON_INDEX_640].DefaultVRefresh =
             (BYTE)TsengGetVerticalRefreshRate(640, TSENG_CHECK_DISABLED);

          sAdapter.RefreshTable[MON_INDEX_800].DefaultVRefresh =
             (BYTE)TsengGetVerticalRefreshRate(800, TSENG_CHECK_DISABLED);

          sAdapter.RefreshTable[MON_INDEX_1024].DefaultVRefresh =
             (BYTE)TsengGetVerticalRefreshRate(1024,TSENG_CHECK_DISABLED);

          sAdapter.RefreshTable[MON_INDEX_1280].DefaultVRefresh =
             (BYTE)TsengGetVerticalRefreshRate(1280,TSENG_CHECK_DISABLED);
      }
  }

  else if( (Adapter == WESTERNDIG_ADAPTER)                      /*          */
           && (Chip == WESTERNDIG_WD9031_CHIP) )                /*          */
  {
     if (sOEM.Manufacturer != DIAMOND_MANUFACTURER)                /*          */
        return;
     /*
     ** Read SEQ 8
     */
     outp(SEQ_INDEXPORT, 0x08);
     cMonitorBits = (BYTE)inp(SEQ_DATAPORT);
     //          
     strcpy(&sAdapter.MonitorName[0],&DiamondMonitorTableWD[cMonitorBits&0x7].name[0]);
     Diamond_24_Refresh_Table[MON_INDEX_640].DefaultVRefresh =
        DiamondMonitorTableWD[cMonitorBits&0x7].VRefr[MON_INDEX_640];
     Diamond_24_Refresh_Table[MON_INDEX_800].DefaultVRefresh =
        DiamondMonitorTableWD[cMonitorBits&0x7].VRefr[MON_INDEX_800];
     Diamond_24_Refresh_Table[MON_INDEX_1024].DefaultVRefresh =
        DiamondMonitorTableWD[cMonitorBits&0x7].VRefr[MON_INDEX_1024];
  }
  else if (Adapter == S3_ADAPTER)
  {
     UCHAR andMask, shiftMask;
     USHORT S3andMask;                                          /*          */
     if ((sOEM.Manufacturer != NUMBER9_MANUFACTURER) &&         /*          */
         (sOEM.Manufacturer != S3_MANUFACTURER))                /*          */
        return;

     outp(CRT_INDEXPORT,0x52);
     cMonitorBits = (BYTE) inp(CRT_DATAPORT);

     if ((sOEM.Manufacturer == NUMBER9_MANUFACTURER) &&         /*          */
         (Chip == S3_86C928_CHIP))                              /*@V3.0YEE03*/
     {                                                          /*          */
       /*
       ** Number9 records its monitor selection in scratch register 52.
       ** 640x480    and mask 0x3
       ** 800x600    and mask 0xc
       ** 1024x768   and mask 0x30
       ** 1280, 1600 and mask 0xc0
       ** 60/56 Hz   or mask  10  (default)
       ** 70    Hz   or mask  00
       ** 72    Hz   or mask  11
       ** 76    Hz   or mask  01
       */
       for(i=0,andMask = 0x3,shiftMask = 0;i<4;i++,shiftMask+= 2,andMask <<= 2)
       {
         switch((cMonitorBits & andMask) >> shiftMask)
         {
           case 0:
             S3_N9_Refresh_Table[i].DefaultVRefresh = 70;
             break;
           case 1:
             S3_N9_Refresh_Table[i].DefaultVRefresh = 76;
             break;
           case 2:
             if (i == MON_INDEX_800)
               S3_N9_Refresh_Table[i].DefaultVRefresh = 56;
             else
               S3_N9_Refresh_Table[i].DefaultVRefresh = 60;
             break;
           case 3:
             S3_N9_Refresh_Table[i].DefaultVRefresh = 72;
             break;
         }
       }
     }                                                          /*          */
     else if ((sOEM.Manufacturer == NUMBER9_MANUFACTURER) ||    /*@V3.0YEE03*/
              (sDACINFO.DACFamily == S3SDAC_DAC) ||             /*@V3.0YEE03*/
              (sDACINFO.DACFamily == SGS1703_DAC))              /*@V3.0YEE08*/
     {
       /*  864/964 refresh rates specified in CR5B and CR52.      @V3.0YEE04
       **
       **  The structure is like this:
       **
       **         |<-----CR5B------>|<----CR52------->|
       **   Bits: |7 6 5| 4 3 2| 1 0 7| 6 5 4| 3 2 1 0|
       **         |x x x| x x x| x x x| x x x| x x x x|
       **                                    
       **            ³      ³      ³      ³      ³
       **            ³      ³      ³      ³      ÀÄ  unused
       **            ³      ³      ³      ÀÄ 640x480 resolutions
       **            ³      ³      ÀÄÄÄÄÄÄÄÄ 800x600 resolutions
       **            ³      ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 1024x768 resolutions
       **            ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ 1280x1024 and 1600x1200 resolutions
       */

       outp(CRT_INDEXPORT,0x5B);
       us864RefreshBits = ((BYTE) inp(CRT_DATAPORT)  << 8);

       us864RefreshBits |= cMonitorBits;    /* set low byte */
       us864RefreshBits >>= 4;              /* get rid of unused portion */

       for(i=0,S3andMask=0x7,shiftMask=0; i<4; i++,shiftMask+=3,S3andMask<<=3) /*          */
       {
         switch((us864RefreshBits & S3andMask) >> shiftMask)                   /*          */
         {
           case 0:
             if (i == MON_INDEX_640)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 60;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 60;   /*          */
             }

             else if (i == MON_INDEX_800)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 56;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 56;   /*          */
             }

             else if (i == MON_INDEX_1024)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 43;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 43;   /*          */
             }

             else if (i == MON_INDEX_1280)                      /*          */
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 45;   /*          */
             break;

           case 1:
             if (i == MON_INDEX_640)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 72;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 72;   /*          */
             }

             else if (i == MON_INDEX_800)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 60;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 60;   /*          */
             }
             break;

           case 2:
             if (i == MON_INDEX_640)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 75;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 75;   /*          */
             }

             else if (i == MON_INDEX_800)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 72;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 72;   /*          */
             }

             else if (i == MON_INDEX_1024)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 60;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 60;   /*          */
             }

             else if (i == MON_INDEX_1280)
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 45;
             break;

           case 3:
             if (i == MON_INDEX_800)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 75;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 75;   /*          */
             }

             else if (i == MON_INDEX_1024)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 70;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 70;   /*          */
             }
             break;

           case 4:
             if (i == MON_INDEX_640)                            /*          */
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 85;   /*          */

             else if (i == MON_INDEX_800)                       /*          */
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 85;   /*          */

             else if (i == MON_INDEX_1024)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 75;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 72;   /*          */
             }

             else if (i == MON_INDEX_1280)
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 60;
             break;

           case 5:
             if (i == MON_INDEX_1024)                           /*          */
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 75;   /*          */

             else if (i == MON_INDEX_1280)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 72;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 60;   /*          */
             }

             break;

           case 6:
             if (i == MON_INDEX_1280)
             {
               S3_N9x64_Refresh_Table[i].DefaultVRefresh = 75;
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 72;   /*          */
             }
             break;

           case 7:                                              /*          */
             if (i == MON_INDEX_1280)                           /*          */
               S3_SDAC_Refresh_Table[i].DefaultVRefresh = 75;   /*          */
             break;                                             /*          */
         }                     /* end us864RefreshBits test */
       }                       /* end for loop              */
       S3_N9x64_Refresh_Table[4].DefaultVRefresh = 60;        /*          */
       S3_SDAC_Refresh_Table[4].DefaultVRefresh = 49;           /*          */
     }                         /* end manufacturer test                     */

     else if (sOEM.Manufacturer == S3_MANUFACTURER)             /*@V3.0YEE03*/
     {
       /*  864 refresh rates specified in CR52.
       **  Used by Actix and miromagic.
       */

       /*  assume default refreshes */
       S3_ICD2061_Refresh_Table[MON_INDEX_640].DefaultVRefresh = 60;
       S3_ICD2061_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 56;
       S3_ICD2061_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 43;
       S3_ICD2061_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 44;
       S3_ICD2061_Refresh_Table[MON_INDEX_1600].DefaultVRefresh = 60;


       cMonitorBits &= 0x07;
       if (cMonitorBits == 0x01)
       {
          S3_ICD2061_Refresh_Table[MON_INDEX_640].DefaultVRefresh = 75;
          S3_ICD2061_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 60;
       }

       else if (cMonitorBits == 0x02)
       {
          S3_ICD2061_Refresh_Table[MON_INDEX_640].DefaultVRefresh = 90;
          S3_ICD2061_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 75;
          S3_ICD2061_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 60;
       }

       else if (cMonitorBits >= 0x03)
       {
          S3_ICD2061_Refresh_Table[MON_INDEX_640].DefaultVRefresh = 90;
          S3_ICD2061_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 95;
          S3_ICD2061_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 70;

          if (cMonitorBits >= 0x04)
          {
             S3_ICD2061_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 75;
             S3_ICD2061_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 60;
             if (cMonitorBits == 0x05)
               S3_ICD2061_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 72;
             else if (cMonitorBits == 0x06)
               S3_ICD2061_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 75;
          }
       }                       /* end cMonitorBits test */
     }                         /* end manufacturer test           @V3.0YEE03*/
  }
  else if (Adapter == CIRRUS_ADAPTER)                           /*          */
  {
     if (sOEM.Manufacturer == CIRRUS_MANUFACTURER)  /* i.e. 543x */
     {
        /*
        ** Read SEQ A & SEQ 14 to get refresh rates for 640x480
        */
        outp(SEQ_INDEXPORT, 0x0A);
        cMonitorBits = (BYTE)inp(SEQ_DATAPORT);
        if ((cMonitorBits & 0x01) == 0x01)
        {
           outp(SEQ_INDEXPORT, 0x14);
           cMonitorBits2 = (BYTE)inp(SEQ_DATAPORT);
           cMonitorBits2 = (BYTE)((cMonitorBits2 & 0x18) >> 3);
           if (!cMonitorBits2)
             Cirrus543x_Refresh_Table[MON_INDEX_640].DefaultVRefresh = 72;
           else
             Cirrus543x_Refresh_Table[MON_INDEX_640].DefaultVRefresh = 75;
        }
        else
          Cirrus543x_Refresh_Table[MON_INDEX_640].DefaultVRefresh = 60;

        /*
        ** Read SEQ A to get refresh rates for 1280x1024
        */
        cMonitorBits = (BYTE)((cMonitorBits & 0x0e) >> 1);
        switch (cMonitorBits)
        {
          case 0:
            Cirrus543x_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 43;
            break;
          case 1:
            Cirrus543x_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 60;
            break;
          case 2:
            Cirrus543x_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 72;
            break;
          case 3:
            Cirrus543x_Refresh_Table[MON_INDEX_1280].DefaultVRefresh = 75;
            break;
        }

        /*
        ** Read SEQ 9 to get refresh rates for 800x600 and 1024x768
        */
        outp(SEQ_INDEXPORT, 0x09);
        cMonitorBits = (BYTE)inp(SEQ_DATAPORT);
        cMonitorBits2 = (BYTE)((cMonitorBits & 0xe0) >> 5);  /* 1024x768 */
        cMonitorBits = (BYTE)((cMonitorBits & 0x1c) >> 2);   /* 800x600  */
        switch (cMonitorBits)
        {
          case 0:
            Cirrus543x_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 56;
            break;
          case 1:
            Cirrus543x_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 60;
            break;
          case 2:
            Cirrus543x_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 72;
            break;
          case 3:
            Cirrus543x_Refresh_Table[MON_INDEX_800].DefaultVRefresh = 75;
            break;
        }

        switch (cMonitorBits2)
        {
          case 0:
            Cirrus543x_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 43;
            break;
          case 1:
            Cirrus543x_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 60;
            break;
          case 2:
            Cirrus543x_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 70;
            break;
          case 3:
            Cirrus543x_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 72;
            break;
          case 4:
            Cirrus543x_Refresh_Table[MON_INDEX_1024].DefaultVRefresh = 75;
            break;
        }
     }                         /* end Cirrus manufacturer test              */
  }                            /* end adaptertype test                      */

  /*
  **  Check to see if a DDC monitor is attached by issuing the   @V3.0YEE01
  **  VESA Bios call
  */
  regs.x.ax = 0x4f15;
  regs.x.bx = 0x0000;
  regs.x.cx = 0x0000;
  int86(VBIOS, &regs, &regs);
  if ((regs.x.ax == 0x004f) &&
      (regs.h.bl & 0x01))                      /* bit0 on = DDC1 supported */
  {
     regs.x.ax = 0x4f15;                       /* now get the EDID info    */
     regs.x.bx = 0x0001;
     regs.x.cx = 0x0000;
     regs.x.dx = 0x0000;
     regs.x.di = OFFSETOF(EDIDbuff);
     sregs.es = SEGMENTOF(EDIDbuff);
     int86x(VBIOS, &regs, &regs, &sregs);

     if (regs.x.ax == 0x004f)                  /* got it OK                */
     {
        /*
        **  Get first 2 bytes of the established timing data and
        **  look for highest refresh rate for the resolution
        */
        strcpy(&sAdapter.MonitorName[0],"DDC");   /* indicate DDC-enabled  */
        sAdapter.RefreshTable[MON_INDEX_1280].DefaultVRefresh = 45; /*default*/
        sAdapter.RefreshTable[MON_INDEX_1600].DefaultVRefresh = REFRESH_DISABLED;

        /*   set max vertical refresh for 640x480 resolution    */
        if (EDIDinfo.EstablishedTimings[0] & 0x04)
          sAdapter.RefreshTable[MON_INDEX_640].DefaultVRefresh = 75;
        else if (EDIDinfo.EstablishedTimings[0] & 0x08)
          sAdapter.RefreshTable[MON_INDEX_640].DefaultVRefresh = 72;
        else if (EDIDinfo.EstablishedTimings[0] & 0x20)
          sAdapter.RefreshTable[MON_INDEX_640].DefaultVRefresh = 60;

        /*   set max vertical refresh for 800x600 resolution    */
        if (EDIDinfo.EstablishedTimings[1] & 0x40)
          sAdapter.RefreshTable[MON_INDEX_800].DefaultVRefresh = 75;
        else if (EDIDinfo.EstablishedTimings[1] & 0x80)
          sAdapter.RefreshTable[MON_INDEX_800].DefaultVRefresh = 72;
        else if (EDIDinfo.EstablishedTimings[0] & 0x01)
          sAdapter.RefreshTable[MON_INDEX_800].DefaultVRefresh = 60;
        else if (EDIDinfo.EstablishedTimings[0] & 0x02)
          sAdapter.RefreshTable[MON_INDEX_800].DefaultVRefresh = 56;

        /*   set default for 1024x768 resolution    */
        /*   set max vertical refresh for 1024x768 resolution    */
        if (EDIDinfo.EstablishedTimings[1] & 0x02)
          sAdapter.RefreshTable[MON_INDEX_1024].DefaultVRefresh = 75;
        else if (EDIDinfo.EstablishedTimings[1] & 0x04)
          sAdapter.RefreshTable[MON_INDEX_1024].DefaultVRefresh = 70;
        else if (EDIDinfo.EstablishedTimings[0] & 0x08)
          sAdapter.RefreshTable[MON_INDEX_1024].DefaultVRefresh = 60;
        else if (EDIDinfo.EstablishedTimings[0] & 0x10)
          sAdapter.RefreshTable[MON_INDEX_1024].DefaultVRefresh = 44;

        /*   set max vertical refresh for 1280x1024 resolution    */
        if (EDIDinfo.EstablishedTimings[1] & 0x01)
          sAdapter.RefreshTable[MON_INDEX_1280].DefaultVRefresh = 75;

        /*
        **  Now look at the Standard Timings and change default
        **  refresh if higher values are specified.
        **  Note that IBM DDC monitors use 01 if no timing specified,
        **  but the VESA spec says the unused bytes should be set to 00.
        */
        for (i=0; i<8; i++)         /* up to 8 standard timings */
        {
          if (EDIDinfo.EstablishedTimings[i*2+3] > 0x01) /* timing specified */
          {
            /*** Horizontal resolution is stored as a multiple of 8 ***/
            /*** minus 31                                           ***/
            HorzPixel = (USHORT)((EDIDinfo.EstablishedTimings[i*2+3] + 31) << 3);

            /*** Bits 0-5 contains vertical refresh rate minus 60   ***/
            VertRef = (BYTE)((EDIDinfo.EstablishedTimings[i*2+4] & 0x3F) + 60);

            switch(HorzPixel)
            {
              case 640:                       /*640x480  */
                if (VertRef > sAdapter.RefreshTable[MON_INDEX_640].DefaultVRefresh)
                  sAdapter.RefreshTable[MON_INDEX_640].DefaultVRefresh = VertRef;
                break;

              case 800:                       /*800x600  */
                if (VertRef > sAdapter.RefreshTable[MON_INDEX_800].DefaultVRefresh)
                  sAdapter.RefreshTable[MON_INDEX_800].DefaultVRefresh = VertRef;
                break;

              case 1024:                      /*1024x768 */
                if (VertRef == 86)            /*interlaced*/
                  VertRef >>= 1;              /* divide by 2*/
                if (VertRef > sAdapter.RefreshTable[MON_INDEX_1024].DefaultVRefresh)
                  sAdapter.RefreshTable[MON_INDEX_1024].DefaultVRefresh = VertRef;
                break;

              case 1280:                      /*1280x1024*/
                if ((VertRef == 86) || (VertRef == 90))     /*interlaced*/
                  VertRef >>= 1;              /* divide by 2*/
                if (VertRef > sAdapter.RefreshTable[MON_INDEX_1280].DefaultVRefresh)
                  sAdapter.RefreshTable[MON_INDEX_1280].DefaultVRefresh = VertRef;
                break;

              case 1600:                      /*1600x1200*/
                if (VertRef == 98)            /*interlaced*/
                  VertRef >>= 1;              /* divide by 2*/
                sAdapter.RefreshTable[MON_INDEX_1600].DefaultVRefresh = VertRef;
                break;
            }                                  /* end switch HorzPixel       */
          }                                    /* end timings > 01           */
        }                                      /* end standard timings check */

        GenerateRefresh = 1;                   /* @V3.0YEE02 */
        for (i=0; i<5; i++)
        {
          Refresh[i] = sAdapter.RefreshTable[i].DefaultVRefresh;
          if (Refresh[i] == REFRESH_DISABLED)
             Refresh[i] == -1;
        }
     }                                         /* end EDID info              */
  }                                            /* end DDC test               */
}

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

VOID WriteFileHeader()
{
  WriteComment(sizeof(fileheader)/sizeof(CHAR *), &fileheader[0]);
  fprintf(textfile, "[PMIVersion]\n");                          /*          */
  fprintf(textfile, "        %s\n\n", VERSION);                 /*          */
}

/*****************************************************************************
 *
 * FUNCTION NAME = BuildModeString()
 *
 * DESCRIPTION   = Form a string describing the given video mode header.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

CHAR * BuildModeString(PCHIPHEADER pChipHdr, CHAR * s)
{
  if (pChipHdr->bModeAttributes & GRAPHICS_MODEATTR)
  {
    sprintf(s, "Graphics Mode: %d x %d x ",
                pChipHdr->usXResolution,
                pChipHdr->usYResolution);

    switch (pChipHdr->bBitsPerPixel)
    {
      case 15: strcat(s, "32K");
               break;

      case 16: strcat(s, "64K");
               break;

      case 24:
      case 32:                        /*          */
               strcat(s, "16M");
               break;

      default: sprintf(&s[strlen(s)], "%d", (ULONG)(1 << pChipHdr->bBitsPerPixel));
               break;
    }
    strcat(s, " colors");                        /*JWK10 let actual printf add period */
  }                                              /*      so others can build on this string */
  else
    sprintf(s, "Text Mode: %d cols, %d rows",    /*JWK10 let actual printf add period */
            pChipHdr->usBytesPerScanLine, pChipHdr->usTextRows);

  return (s);
}

/*****************************************************************************
 *
 * FUNCTION NAME = WriteHeader()
 *
 * DESCRIPTION   = Write header information to PMI-file.
 *
 *                 old style
 *                  [comment]
 *                  [AdapterType]
 *                  [ChipSet]
 *                  [OEMName]
 *
 *                 new style
 *                  #includecode
 *                  [Hardware]
 *                  [IdentifyAdapter]
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

INT WriteHeader(PCHIPHEADER pChipHdr)
{
  PSSVGADACINFO psSVGADacInfo;                                  /*          */
  CHAR szTempBuffer [256];                                      /*          */
  CHAR *pszTempBuffer = &szTempBuffer [0];                      /*          */

  /* keep few strings around to keep dirty S3 driver happy */   /*          */
  /* Put back in some strings to maintain compatibility    */   /*          */
    fprintf(textfile, "[AdapterType]\n");
    fprintf( textfile,                                          /*          */
             "        %s\n\n",                                  /*          */
             pszAdapter );                                      /*          */
    if ((sSVGA.AdapterType == S3_ADAPTER)                       /*          */
        && (sOEM.Manufacturer == LACUNA_MANUFACTURER) )         /*          */
      fprintf(textfile, "        %s\n\n",sAdapter.szRevision);
    fprintf(textfile, "[ChipSet]\n");                           /*          */
    fprintf(textfile, "        %s\n\n", pszChipset);            /*          */
//  if( sOEM.Manufacturer                                       /*          */
//    && (sOEM.Manufacturer <= MANUFACTURER_MAX) )              /*          */
//  {
//    fprintf(textfile, "[OEMName]\n");
//    fprintf(textfile, "        %s\n\n", manufacturer[sOEM.Manufacturer]);
//  }
  /*           
  ** AdapterInfo structure and other per adapter data is initialized
  ** by the SetupChipInfo function.
  */
  if (sAdapter.DLLName[0])
    fprintf(textfile,"#includecode \"%s\";\n",sAdapter.DLLName);
  fprintf(textfile, "[Hardware]\n");
  fprintf(textfile, "BusType         = %s\n",BusName[sAdapter.usBusType]);/*            */
  fprintf(textfile, "OEMString       = \"%s\"\n", sAdapter.szOEMString);        /*            */
  if (sAdapter.szRevision[0])
    fprintf(textfile, "Version         = \"%s\"\n",sAdapter.szRevision);        /*            */
  if( sDACINFO.DACFamily > DEFAULT_DAC )                        /*          */
  {                                                             /*          */
    psSVGADacInfo = &asSVGADacInfo [sDACINFO.DACFamily];        /*          */
    strcpy( pszTempBuffer,                                      /*          */
            "HI-COLOR DAC" );                                   /*          */
    if( (psSVGADacInfo->pszDacManufacturer == szBrooktree )     /*          */
        || (psSVGADacInfo->pszDacManufacturer == szMusic )      /*          */
        || (psSVGADacInfo->pszDacManufacturer == szATT )        /*          */
        || (psSVGADacInfo->pszDacManufacturer == szTI ) )       /*@V3.0YEE04*/
    {                                                           /*          */
      strcat( pszTempBuffer,                                    /*          */
              " by " );                                         /*          */
      strcat( pszTempBuffer,                                    /*          */
              psSVGADacInfo->pszDacManufacturer );              /*          */
    }                                                           /*          */
    WriteComment( 1,                                            /*          */
                  &pszTempBuffer );                             /*          */
  }                                                             /*          */
  fprintf(textfile, "DACString       = \"%s\"\n",sAdapter.szDACString);         /*            */
  fprintf(textfile, "TotalMemory     = %ld\n",sAdapter.ulTotalMemory);    /*            */
  fprintf(textfile, "MemoryIOAddress = 0x%08lx\n", sAdapter.ulMMIOBaseAddress); /*            */
  fprintf(textfile, "Endian          = LITTLE\n");/*            */
  /*
  ** Write [IdentifyAdapter] section
  */
  if (sAdapter.FormatSectionFlag & CALL_IDENTIFY)
  {
    fprintf (textfile, "[IdentifyAdapter]\n");
    fprintf (textfile, "call pfnPMIIdentifyAdapter;\n\n");
  }
  return (0);
}

/*****************************************************************************
 *
 * FUNCTION NAME = EmitCmd()
 *
 * DESCRIPTION   = Emit a command to the PMI-file.
 *
 *  Format of commands:
 *      EmitCmd(PMICMD_INB,   Data, Port);
 *      EmitCmd(PMICMD_INW,   Data, Port);
 *      EmitCmd(PMICMD_OUTB,  Flags, Port, Data);
 *      EmitCmd(PMICMD_OUTW,  Flags, Port, Data);
 *      EmitCmd(PMICMD_BINB,  NumEntries, StartIndex, IndexPort, DataPort);
 *      EmitCmd(PMICMD_BOUTB, Flags, IndexPort, DataPort, StartIndex, NumEntries, LastEntry, pbData);
 *      EmitCmd(PMICMD_RMWBI, IndexPort, DataPort, Index, ANDMask, ORMask);
 *      EmitCmd(PMICMD_RMWBN, IndexPort, DataPort, ANDMask, ORMask);
 *      EmitCmd(PMICMD_RMWWN, IndexPort, DataPort, ANDMask, ORMask);
 *      EmitCmd(PMICMD_REGOP, RegOp, RegSize, DstRegIndex, SrcRegIndex, OpData);
 *      EmitCmd(PMICMD_WAITW, Port, Mask, Timeout, Value);
 *      EmitCmd(PMICMD_READB, Destination, Source, Flag, DeclarationPtr);
 *      EmitCmd(PMICMD_READW, Destination, Source, Flag, DeclarationPtr);
 *      EmitCmd(PMICMD_READDW,Destination, Source, Flag, DeclarationPtr);
 *      EmitCmd(PMICMD_WRITEB,Destination, Source, Flag, DeclarationPtr);
 *      EmitCmd(PMICMD_WRITEW,Destination, Source, Flag, DeclarationPtr);
 *      EmitCmd(PMICMD_WRITEDW,Destination,Source, Flag, DeclarationPtr);
 *      EmitCmd(PMICMD_WHILE,RegisterIndex,EndValue);
 *      EmitCmd(PMICMD_ENDWHILE);
 *
 * INPUT         =
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID EmitCmd(USHORT Command,...)
{
  va_list argptr;
  USHORT  j, n;
  USHORT  usFlags,usOp;
  USHORT  usIndexPort;
  USHORT  usDataPort;
  USHORT  usStartIndex,usDstIndex, usSrcIndex, usBytes;
  USHORT  usNumEntries;
  USHORT  usLastEntry;
  PBYTE   pbData;
  USHORT  *pwData;
  ULONG   *pulData;
  CHAR    RegChar,RegChar1,RegChar2,RegChar3;
  CHAR s[MAX_REGISTER_NAME+2],d[MAX_REGISTER_NAME+2];
  ULONG ulDestination, ulSource;
  PVARIABLE_DEC  pDecSection;


  va_start(argptr, Command);

  switch (Command)
  {
    case PMICMD_INB:
      vfprintf(textfile, "inb(r%-1d, 0x%03x);\n", argptr);
      break;

    case PMICMD_INW:
      vfprintf(textfile, "inw(r%-1d, 0x%03x);\n", argptr);
      break;

    case PMICMD_OUTB:
      usFlags = va_arg(argptr, USHORT);
      if (usFlags & WRITEREG_DATA)
        vfprintf(textfile, "outb(0x%03x, r%-1u);\n", argptr);
      else
        vfprintf(textfile, "outb(0x%03x, 0x%02x);\n", argptr);
      break;

    case PMICMD_OUTW:
      usFlags = va_arg(argptr, USHORT);
      if (usFlags & WRITEREG_DATA)
        vfprintf(textfile, "outw(0x%03x, r%-1u);\n", argptr);
      else
        vfprintf(textfile, "outw(0x%03x, 0x%04x);\n", argptr);
      break;

    case PMICMD_WHILE:                  /*            */
      vfprintf(textfile, "while(r%-1d < 0x%03x)\n", argptr);
      break;

    case PMICMD_ENDWHILE:                  /*            */
      vfprintf(textfile, "endwhile\n", argptr);
      break;

    case PMICMD_READB:                  /*            */
    case PMICMD_READW:
    case PMICMD_READDW:
    case PMICMD_WRITEB:
    case PMICMD_WRITEW:
    case PMICMD_WRITEDW:
      ulDestination = va_arg(argptr,ULONG);
      ulSource = va_arg(argptr,ULONG);
      usFlags = va_arg(argptr, USHORT);
      pDecSection = va_arg(argptr,PVARIABLE_DEC);
      switch(usFlags & MMIO_DST_MASK)
      {
        case MMIO_DST_REGISTER:
          sprintf(d,"r%-3d",ulDestination & 0x1FF);
          break;
        case MMIO_DST_VARIABLE:
          sprintf(d,"%s",pDecSection[ulDestination].RegisterName);
//          if (!strcmp(d,"sysconfig"))
//          {
//            _asm int 3;
//          }
          break;
        case MMIO_DST_IMMEDIATE:
          sprintf(d,"0x%08lx",ulDestination);
          break;
      }
      switch(usFlags & MMIO_SRC_MASK)
      {
        case MMIO_SRC_REGISTER:
          sprintf(s,"r%-3d",ulSource & 0x1FF);
          break;
        case MMIO_SRC_VARIABLE:
          sprintf(s,"%s",pDecSection[ulSource].RegisterName);
          break;
        case MMIO_SRC_IMMEDIATE:
          sprintf(s,"0x%08lx",ulSource);
          break;
      }
      switch( Command )
      {
        case PMICMD_READB:
          fprintf(textfile, "readb(%s,%s);\n",d,s);
          break;
        case PMICMD_READW:
          fprintf(textfile, "readw(%s,%s);\n",d,s);
          break;
        case PMICMD_READDW:
          fprintf(textfile, "readdw(%s,%s);\n",d,s);
          break;
        case PMICMD_WRITEB:
          if( (usFlags & MMIO_READWRITE_ALL)
              && (usFlags & MMIO_DST_VARIABLE) )
          {
            pbData = (BYTE *)ulSource;
            for(j=0;(pDecSection[j].RegisterName != NULL);j++)
               fprintf(textfile, "writeb(%s,0x%08x);\n",
                   pDecSection[j].RegisterName,pbData[j]);
          }
          else
            fprintf(textfile, "writeb(%s,%s);\n",d,s);
          break;
        case PMICMD_WRITEW:
          if( (usFlags & MMIO_READWRITE_ALL)
              && (usFlags & MMIO_DST_VARIABLE) )
          {
            pwData = (USHORT *)ulSource;
            for(j=0;(pDecSection[j].RegisterName != NULL);j++)
               fprintf(textfile, "writeb(%s,0x%08x);\n",
                   pDecSection[j].RegisterName,pwData[j]);
          }
          else
            fprintf(textfile, "writew(%s,%s);\n",d,s);
          break;
        case PMICMD_WRITEDW:
          if( (usFlags & MMIO_READWRITE_ALL)
              && (usFlags & MMIO_DST_VARIABLE) )
          {
            pulData = (ULONG *)ulSource;
            for(j=0;(pDecSection[j].RegisterName != NULL);j++)
               fprintf(textfile, "writeb(%s,%s);\n",
                   pDecSection[j].RegisterName,pulData[j]);
          }
          else
            fprintf(textfile, "writedw(%s,%s);\n",d,s);
          break;
      }
      break;
    case PMICMD_BINB:
      vfprintf(textfile, "binb(%d, 0x%02x, 0x%03x, 0x%03x);\n\n", argptr);
      break;

    case PMICMD_BOUTB:
      usFlags = va_arg(argptr, USHORT);
      usIndexPort = va_arg(argptr, USHORT);
      usDataPort = va_arg(argptr, USHORT);
      usStartIndex = va_arg(argptr, USHORT);
      usNumEntries = va_arg(argptr, USHORT);
      usLastEntry = va_arg(argptr, USHORT);
      pbData = va_arg(argptr, PBYTE);

      if ( !(usFlags & DONTWRITE_DATA) )
      {
        for( n = usStartIndex, j = 0;
             n < usLastEntry;
             n++, j++, pbData++ )
          fprintf(textfile, "r%-3d = 0x%02x;%c", n, *pbData, ((j+1)%5)?' ':'\n') ;

        if ((j%5) || (usNumEntries < 5))
          fprintf(textfile, "\n");
      }
      fprintf(textfile, "boutb(%d, 0x%02x, 0x%03x, 0x%03x);\n\n",
              usNumEntries, usStartIndex, usIndexPort, usDataPort);
      break;

    case PMICMD_RMWBI:
      vfprintf(textfile, "rmwbi(0x%03x, 0x%03x, 0x%02x, 0x%02x, 0x%02x);\n", argptr);
      break;

    case PMICMD_RMWBN:                                           /*          */
      vfprintf(textfile, "rmwbn(0x%03x, 0x%03x, 0x%02x, 0x%02x);\n", argptr);
      break;

    case PMICMD_RMWWN:                                          /*          */
      vfprintf(textfile, "rmwwn(0x%04x, 0x%04x, 0x%04x, 0x%04x);\n", argptr);
      break;

    case PMICMD_WAITW:                                          /*          */
      vfprintf(textfile, "waitw(0x%04x, 0x%04x, 0x%04x, 0x%04x);\n", argptr);
      break;

    case PMICMD_REGOP:
      usOp = va_arg(argptr, USHORT);
      usBytes = va_arg(argptr, USHORT);
      usDstIndex = va_arg(argptr, USHORT);
      usSrcIndex = va_arg(argptr, USHORT);
      pbData = va_arg(argptr, PBYTE);
      fprintf( textfile,                                        /*          */
               "r%-3d ",                                        /*          */
               usDstIndex );                                    /*          */
      RegChar2 = ' ';                                           /*          */
      switch( usOp & REGISTER_ALL )
      {
        case REGISTER_AND:
          RegChar = '&';
          break;
        case REGISTER_OR:
          RegChar = '|';
          break;
        case REGISTER_XOR:
          RegChar = '^';
          break;
        case REGISTER_SHL:
          RegChar = '<';
          RegChar2 = '<';
          break;
        case REGISTER_SHR:
          RegChar = '>';
          RegChar2 = '>';
          break;
        case NONE:                                              /*          */
        default:                                                /*          */
          RegChar = ' ';                                        /*          */
          break;                                                /*          */
      }
      if( usOp & REGISTER_NEGATE )
        RegChar1 = '~';
      else
        RegChar1 = ' ';
      if( ( usSrcIndex == usDstIndex )                          /*          */
          || ( usOp & REGISTER_OPEQUAL )                        /*          */
          || ( ( usOp & REGISTER_OPERAND )                      /*          */
               && !( usOp & REGISTER_ALL ) ) )                  /*          */
      {                                                         /*          */
        RegChar3 = ' ';                                         /*          */
        if( RegChar == ' ' )                                    /*          */
          RegChar = '=';                                        /*          */
        else if( RegChar2 == ' ' )                              /*          */
          RegChar2 = '=';                                       /*          */
        else                                                    /*          */
          RegChar3 = '=';                                       /*          */
        fprintf( textfile,                                      /*          */
                 "%c%c%c%c",                                    /*          */
                 RegChar,                                       /*          */
                 RegChar2,                                      /*          */
                 RegChar3,                                      /*          */
                 RegChar1 );                                    /*          */
        if( ( usOp & REGISTER_OPERAND )                         /*          */
            && !( usSrcIndex == usDstIndex ) )                  /*          */
          fprintf( textfile,                                    /*          */
                   "r%-1d",                                     /*          */
                   usSrcIndex );                                /*          */
      }                                                         /*          */
      else                                                      /*          */
      {                                                         /*          */
        fprintf( textfile,                                      /*          */
                 "=  %c",                                       /*          */
                 RegChar1 );                                    /*          */
        if( usOp & REGISTER_ALL )                               /*          */
          fprintf( textfile,                                    /*          */
                   "r%-1d %c%c ",                               /*          */
                   usSrcIndex,                                  /*          */
                   RegChar,                                     /*          */
                   RegChar2 );                                  /*          */
      }                                                         /*          */
      if( !( usOp & REGISTER_OPERAND )                          /*          */
          || ( !( usOp & REGISTER_OPEQUAL )                     /*          */
               && ( usOp & REGISTER_ALL ) ) )                   /*          */
        fprintf( textfile,                                      /*          */
                 "0x%08lx",                                     /*          */
                 (( usBytes == 1 )      /* reg size is 1 byte *//*          */
                  ? (LONG)*pbData                               /*          */
                  : (( usBytes == 4 )   /* reg size is 4 bytes*//*          */
                     ? *(ULONG *)pbData                         /*          */
                     : 0x01234567L)) ); /* Internal ERROR!    *//*          */
      fprintf( textfile,                                        /*          */
               ";\n" );                                         /*          */
      break;

  }
  va_end(argptr);
}

/*****************************************************************************
 *
 * FUNCTION NAME = WriteCmd()
 *
 * DESCRIPTION   = Write a command to the PMI-file.
 *
 * INPUT         =
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID WriteCmd(PREGDATA pRegData)
{
  USHORT StartIndex, Value;
  PBYTE  pbData   = pRegData->Data;

  switch( pRegData->Command )
  {
    case PMICMD_WHILE:                            /*            */
      EmitCmd(PMICMD_WHILE,
               pRegData->R.WHILE.LoopIndex,
               pRegData->R.WHILE.EndValue);
      break;

    case PMICMD_ENDWHILE:                         /*            */
      EmitCmd(PMICMD_ENDWHILE);
      break;

    case PMICMD_INB:
      EmitCmd(PMICMD_INB,
               pRegData->R.WPortIO.Value,
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.PortIO.IndexPort ) );
      break;

    case PMICMD_INW:
      EmitCmd(PMICMD_INW,
               pRegData->R.WPortIO.Value,
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.WPortIO.Port ) );
      break;

    case PMICMD_OUTB:
      StartIndex = pRegData->R.PortIO.StartIndex;
      if ( !(pRegData->R.PortIO.Flags & WRITEREG_DATA) )
        StartIndex = *pbData;
      EmitCmd(PMICMD_OUTB,
               pRegData->R.PortIO.Flags,
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.PortIO.IndexPort ),              /*          */
               StartIndex);
      break;

    case PMICMD_OUTW:
      Value = pRegData->R.WPortIO.Value;
      if ( !(pRegData->R.WPortIO.WFlags & WRITEREG_DATA) )
        Value = *(USHORT *)pbData;                              /*          */
      EmitCmd(PMICMD_OUTW,
               pRegData->R.WPortIO.WFlags,
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.WPortIO.Port ),
               Value);
      break;

    case PMICMD_BINB:
      EmitCmd(PMICMD_BINB,
               pRegData->R.PortIO.NumEntries,
               pRegData->R.PortIO.StartIndex,
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.PortIO.IndexPort ),
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.PortIO.DataPort ) );
      break;

    case PMICMD_BOUTB:
      EmitCmd(PMICMD_BOUTB,
               pRegData->R.PortIO.Flags,
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.PortIO.IndexPort ),
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.PortIO.DataPort ),
               pRegData->R.PortIO.StartIndex,
               pRegData->R.PortIO.NumEntries,
               pRegData->R.PortIO.StartIndex+pRegData->R.PortIO.NumEntries,
               pbData);
      break;

    case PMICMD_RMWBI:
      EmitCmd(PMICMD_RMWBI,
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.RMW.IndPort ),
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.RMW.DPort ),
               pRegData->R.RMW.Index,
               pRegData->R.RMW.ANDMask,
               *pRegData->Data & ~ pRegData->R.RMW.ANDMask );   /*          */
      break;

    case PMICMD_RMWBN:                                          /*          */
      EmitCmd(PMICMD_RMWBN,                                     /*          */
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.RMW.IndPort ),
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.RMW.DPort ),
               pRegData->R.RMW.ANDMask,
               *pRegData->Data & ~ pRegData->R.RMW.ANDMask );   /*          */
      break;                                                    /*          */

    case PMICMD_RMWWN:                                          /*          */
      EmitCmd(PMICMD_RMWWN,                                     /*          */
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.RMW.IndPort ),
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.RMW.DPort ),
               pRegData->R.RMW.ANDMask,                         /*          */
               *(PUSHORT)pRegData->Data                         /*          */
                 & ~ pRegData->R.RMW.ANDMask );                 /*          */
      break;                                                    /*          */

    case PMICMD_REGOP:
      EmitCmd(PMICMD_REGOP,
               pRegData->R.RegOp.Operation,
               pRegData->R.RegOp.RegSize,
               pRegData->R.RegOp.DstRegIndex,
               pRegData->R.RegOp.SrcRegIndex,
               pbData);
      break;

    case PMICMD_WAITW:                                          /*          */
      EmitCmd(PMICMD_WAITW,                                     /*          */
               psCurAdapterInfo->                               /*          */
                 pusfnSVGAAdjustedPort(                         /*          */
                   pRegData->R.Wait.IPort ),
               pRegData->R.Wait.Mask,
               /* pRegData->R.Wait.Count, */                    /*          */
               pRegData->R.Wait.TimeOut,
               pRegData->R.Wait.WValue,
               pbData);
      break;

    case PMICMD_READB:
    case PMICMD_READW:
    case PMICMD_READDW:
    case PMICMD_WRITEB:
    case PMICMD_WRITEW:
    case PMICMD_WRITEDW:
      if(pRegData->R.MMIO.MemFlags & MMIO_READWRITE_ALL)
        EmitCmd(pRegData->Command,
              pRegData->R.MMIO.Destination,
              pbData,
              pRegData->R.MMIO.MemFlags,
              sAdapter.pDecSection);
      else if (pRegData->R.MMIO.MemFlags & MMIO_RUNTIME_DATA)   /*          */
      {
        EmitCmd(pRegData->Command,
              pRegData->R.MMIO.Destination,
              (ULONG) *((PULONG)pbData),                        /*          */
              pRegData->R.MMIO.MemFlags,
              sAdapter.pDecSection);                            /*          */
      }
      else
        EmitCmd(pRegData->Command,
              pRegData->R.MMIO.Destination,
              pRegData->R.MMIO.Source,
              pRegData->R.MMIO.MemFlags,
              sAdapter.pDecSection);                            /*          */
      break;
    case PMICMD_CALL:                                           /*          */
      if (pRegData->R.CALL.Function & CALL_NON_STANDARD)
            fprintf(textfile,"call %s;\n",pbData);
      else      /* adapter flag has to match */
      if (pRegData->R.CALL.Function & sAdapter.FormatSectionFlag)
      {
         if (pRegData->R.CALL.Function & CALL_MONITOR_TIMINGS)
            fprintf(textfile,"call pfnPMISetMonitorTimings;\n");
      }
      break;
  }
}

/*****************************************************************************
 *
 * FUNCTION NAME = WriteCmds()
 *
 * DESCRIPTION   = Write list
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID  WriteCmds(                                                /*          */
  PREGDATA pRegData )
{
  if( pRegData )                                                /*          */
    while( pRegData->Command != PMICMD_NONE )
    {
      WriteCmd( pRegData );
      pRegData++;
    }
}

/*****************************************************************************
 *
 * FUNCTION NAME = WriteCmdSection()
 *
 * DESCRIPTION   = Write whole command section.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/
VOID  WriteCmdSection(PREGDATA pRegData)
{
  WriteCmds( pRegData );                                        /*          */
  fprintf(textfile, "\n");
}

/*****************************************************************************
 *
 * FUNCTION NAME = SetupPortMask()
 *
 * DESCRIPTION   = Update the bit mask of indices, given the start and number.
 *                 This function looks a bit clumsy, since the input range is
 *                 not limited in any fashion. It is assumed that the array passed
 *                 would fit the request.
 * INPUT         = USHORT StartIndex, NumEntries
 * OUTPUT        = BYTE *PortMask      array of bytes
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID SetupPortMask(BYTE *PortMask, USHORT NumEntries, USHORT StartIndex)
{
  USHORT i,j, Position;
  BYTE Field = 1;       /* bit mask */
  for (i = (StartIndex>>3); i <= ((StartIndex+NumEntries) >> 3);i++,Field = 1)
  {
    for (j=0;j < 8;j++,Field<<=1)
    {
      Position = (i<<3)+j;
      if ((Position >= StartIndex) && (Position < StartIndex+NumEntries))
        PortMask[i] |= Field;
    }
  }
}
/*****************************************************************************
 *
 * FUNCTION NAME = FindLockData()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PREGDATA FindLockData(INT Adapter,INT Chip)
{
  switch (Adapter)
  {
    case ATI_ADAPTER:                                           /*          */
      return( (Chip == ATI_88800_CHIP)                          /*          */
              ? aRegDataATIMach64Lock                           /*          */
              : VGAUnLock );                                    /*          */

    case CIRRUS_ADAPTER:
      return CirrusLockData;

    case S3_ADAPTER:
      return S3LockData;

    case TSENG_ADAPTER:
      return( (Chip >= TSENG_ET4000W32_CHIP)                    /*          */
              ? TsengLockDataW32                                /*          */
              : TsengLockData);                                 /*          */

    case VIDEO7_ADAPTER:
      return HeadlandLockData;

    case WEITEK_ADAPTER:
      switch (sOEM.Manufacturer)
      {
        case  DIAMOND_MANUFACTURER :
        return Weitek5x86LockData;

        default:
          return VGAUnLock;
      }

    case WESTERNDIG_ADAPTER:
      switch (Chip)
      {
        case  WESTERNDIG_PVGA1A_CHIP :
          return ParadiseLockData1;
          break;
        case  WESTERNDIG_WD9000_CHIP :
          return ParadiseLockData2;
          break;
        case  WESTERNDIG_WD9011_CHIP :                          /*          */
        case  WESTERNDIG_WD9030_CHIP :                          /*          */
        case  WESTERNDIG_WD9031_CHIP :                          /*          */
        case  WESTERNDIG_WD9033_CHIP :                          /*          */
        default:
          /* Desktop */                                         /*          */
          return ParadiseLockData3;
          break;
        case  WESTERNDIG_WD9024_CHIP :                          /*          */
        case  WESTERNDIG_WD9026_CHIP :                          /*          */
        case  WESTERNDIG_WD9027_CHIP :                          /*          */
          /* LCD/Laptop/Flat Panel */                           /*          */
          return ParadiseLockData4;                             /*          */
          break;                                                /*          */
      }
      break;

    default:
      return VGALock;
  }
  return( VGAUnLock );                                          /*          */
}

PREGDATA FindUnlockData(INT Adapter,INT Chip)
{
  switch (Adapter)
  {
    case ATI_ADAPTER:                                           /*          */
      return( (Chip == ATI_88800_CHIP)                          /*          */
              ? aRegDataATIMach64Unlock                         /*          */
              : VGAUnLock );                                    /*          */

    case CIRRUS_ADAPTER:
      return CirrusUnLockData;

    case S3_ADAPTER:
      return S3UnLockData;

    case TSENG_ADAPTER:
      return( (Chip >= TSENG_ET4000W32_CHIP)                    /*          */
              ? TsengUnLockDataW32                              /*          */
              : TsengUnLockData);                               /*          */

    case VIDEO7_ADAPTER:
      return HeadlandUnLockData;

    case WEITEK_ADAPTER:
      switch (sOEM.Manufacturer)
      {
        case  DIAMOND_MANUFACTURER :
        return Weitek5x86UnLockData;

        default:
          return VGAUnLock;
      }

    case WESTERNDIG_ADAPTER:
      switch (Chip)
      {
        case  WESTERNDIG_PVGA1A_CHIP :
          return ParadiseUnLockData1;
        case  WESTERNDIG_WD9000_CHIP :
          return ParadiseUnLockData2;
        case  WESTERNDIG_WD9011_CHIP :                          /*          */
        case  WESTERNDIG_WD9030_CHIP :                          /*          */
        case  WESTERNDIG_WD9031_CHIP :                          /*          */
        case  WESTERNDIG_WD9033_CHIP :                          /*          */
        default:
          /* Desktop */                                         /*          */
          return ParadiseUnLockData3;
          break;
        case  WESTERNDIG_WD9024_CHIP :                          /*          */
        case  WESTERNDIG_WD9026_CHIP :                          /*          */
        case  WESTERNDIG_WD9027_CHIP :                          /*          */
          /* LCD/Laptop/Flat Panel */                           /*          */
          return ParadiseUnLockData4;                           /*          */
          break;                                                /*          */
      }
      break;

    default:
      return VGAUnLock;

  }
  return( VGAUnLock );                                          /*          */
}
/*****************************************************************************
 *
 * FUNCTION NAME = AddTrapReg()
 *
 * DESCRIPTION   = Add a trap register to the list if needed
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

USHORT AddTrapReg(
  ULONG ulPort,
  USHORT usFlag )             /* size, port or mmio */
{
  USHORT usIndex;
  BYTE bFound;

  PortList [PortCount].PortAddress = ulPort;
  PortList [PortCount].PortFlag = usFlag;
  for (usIndex = 0;
       !(bFound = (BYTE)
                  ((ulPort == PortList [usIndex].PortAddress)
                   && !((PortList [usIndex].PortFlag ^ usFlag)
                        & (IOPORT | MMIO_DST_MASK))));
       usIndex++ )
  {}
  PortCount += (usIndex >= PortCount);
  PortList [usIndex].PortFlag |= usFlag;
  return( usIndex );
}
/*****************************************************************************
 *
 * FUNCTION NAME = CheckCmdTrapRegs()
 *
 * DESCRIPTION   = Check a PMI command for trap registers
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID CheckCmdTrapRegs(                                          /*          */
  PREGDATA pRegData )
{
  USHORT index;
  USHORT ByteSize;
  ULONG ulPort;                                                 /*          */

  ByteSize = BYTE_REG >> 2;
  switch( pRegData->Command )
  {
    case PMICMD_OUTB:
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.PortIO.IndexPort );      /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | WRITE_REG );
      break;
    case PMICMD_OUTW:
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.WPortIO.Port );          /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | WORD_REG | WRITE_REG );
      break;
    case PMICMD_INB:                                            /*          */
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.PortIO.IndexPort );      /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | READ_REG );
      break;
    case PMICMD_INW:                                            /*          */
    case PMICMD_WAITW:                                          /*          */
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.WPortIO.Port );          /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | WORD_REG | WRITE_REG );
      break;
    case PMICMD_RMWBI:                                          /*          */
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.IndPort );
      index = AddTrapReg( ulPort,
                          IOPORT | BYTE_REG | WRITE_REG );
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.DPort );
      index = AddTrapReg( ulPort,
                          IOPORT | BYTE_REG | READ_REG | WRITE_REG );
      PortList[index].PortFlag |= MULTIPORT;
      SetupPortMask(&PortList[index].PortMask[0],
                    1,
                    pRegData->R.RMW.Index);
      break;
    case PMICMD_RMWBN:                                          /*          */
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.IndPort );           /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | READ_REG );
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.DPort );             /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | WRITE_REG );
      break;
    case PMICMD_RMWWN:                                          /*          */
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.IndPort );           /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | WORD_REG | READ_REG );       /*          */
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.DPort );             /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | WORD_REG | WRITE_REG );      /*          */
      break;                                                    /*          */
    case PMICMD_BOUTB:
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.IndPort );           /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | WRITE_REG );
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.RMW.DPort );             /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | READ_REG | WRITE_REG );
      /*
      ** create the mask, if any indices specified.
      */
      if( pRegData->R.PortIO.NumEntries )
      {
        PortList[index].PortFlag |= MULTIPORT;
        SetupPortMask( &PortList[index].PortMask[0],
                       pRegData->R.PortIO.NumEntries,
                       pRegData->R.PortIO.StartIndex );
      }
      break;
    case PMICMD_BINB:                                           /*          */
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.PortIO.IndexPort );      /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | WRITE_REG );
      ulPort = (ULONG) psCurAdapterInfo->                       /*          */
                         pusfnSVGAAdjustedPort(                 /*          */
                           pRegData->R.PortIO.DataPort );       /*          */
      index = AddTrapReg( ulPort,                               /*          */
                          IOPORT | BYTE_REG | READ_REG | READ_REG );
      /*
      ** create the mask, if any indices specified.
      */
      if( pRegData->R.PortIO.NumEntries )
      {
        PortList[index].PortFlag |= MULTIPORT;
        SetupPortMask( &PortList[index].PortMask[0],
                       pRegData->R.PortIO.NumEntries,
                       pRegData->R.PortIO.StartIndex );
      }
      break;
    case PMICMD_WRITEB:
      ByteSize <<= 1;      /* no break here, let it thru */
    case PMICMD_WRITEW:
      ByteSize <<= 1;      /* no break here, let it thru */
    case PMICMD_WRITEDW:   /* byteSize corresponds to size flags above */
      ulPort = pRegData->R.MMIO.Destination;                    /*          */
      AddTrapReg( ulPort,                                       /*          */
                  ByteSize
                  | (pRegData->R.MMIO.MemFlags & MMIO_DST_MASK)
                  | WRITE_REG );
      break;
    case PMICMD_READB:                                          /*          */
      ByteSize <<= 1;      /* no break here, let it thru */
    case PMICMD_READW:                                          /*          */
      ByteSize <<= 1;      /* no break here, let it thru */
    case PMICMD_READDW:    /* byteSize corresponds to size */   /*          */
      ulPort = pRegData->R.MMIO.Destination;                    /*          */
      AddTrapReg( ulPort,                                       /*          */
                  ByteSize
                  | (USHORT) (pRegData->R.MMIO.MemFlags & MMIO_DST_MASK)
                  | READ_REG );
      break;
  }
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = CheckProgramTrapRegs()
 *
 * DESCRIPTION   = Check a PMI command program for trap registers
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID CheckProgramTrapRegs(                                      /*          */
  PREGDATA pRegData )
{
  if( pRegData )
    for( ;
         (pRegData->Command != PMICMD_NONE)
         && (PortCount < MAX_PORTS);
         pRegData++ )
      CheckCmdTrapRegs( pRegData );
}
/*****************************************************************************
 *
 * FUNCTION NAME = ProcessTrapRegs()
 *
 * DESCRIPTION   = write out all ports accessed (for virtualisation use)
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

INT ProcessTrapRegs(PCHIPINFO Chip)
{
  USHORT i,j,usMode,k;
  PSSVGADACINFO psSVGADacInfo;                                  /*          */

  PortCount = 0;
  PortList[PortCount].PortAddress = (ULONG) MISCOUTPUTREG_WRITE;
  PortList[PortCount++].PortFlag = IOPORT | BYTE_REG | WRITE_REG;

  for (usMode = 0; usMode < usNumModes; usMode++)
    CheckProgramTrapRegs( Chip[usMode].pRegData );              /*          */
  CheckProgramTrapRegs( FindLockData( sSVGA.AdapterType,        /*          */
                                      sSVGA.ChipType ) );       /*          */
  CheckProgramTrapRegs( FindUnlockData( sSVGA.AdapterType,      /*          */
                                        sSVGA.ChipType ) );     /*          */
  psSVGADacInfo = &asSVGADacInfo [sDACINFO.DACFamily];          /*          */
  CheckProgramTrapRegs( psSVGADacInfo->pRegDataDacProgram );    /*          */
  CheckProgramTrapRegs( psSVGADacInfo->pRegDataDacIPFSet );     /*          */
  CheckProgramTrapRegs( psSVGADacInfo->pRegDataDacIPFClear );   /*          */
  fprintf(textfile, "[TrapRegs]\n");
  for (i = 0; i < PortCount; i++)
  {
    switch(PortList[i].PortFlag & SIZE_FIELD)
    {
      case BYTE_REG:
      case BYTE_REG | WORD_REG:
      case BYTE_REG | WORD_REG | DWORD_REG:
        if (PortList[i].PortFlag & IOPORT)
          fprintf(textfile, "BYTE_IOPORT 0x%04x", PortList[i].PortAddress);
        else if (PortList[i].PortFlag & MMIO_DST_IMMEDIATE)
          fprintf(textfile, "BYTE_MMIOPORT 0x%08lx", PortList[i].PortAddress);
        else if (PortList[i].PortFlag & MMIO_DST_VARIABLE)
          fprintf( textfile,
                   "BYTE_MMIOPORT %s",
                   sAdapter.pDecSection                         /*          */
                     [PortList[i].PortAddress]
                       .RegisterName);
        break;
      case WORD_REG:
      case WORD_REG | DWORD_REG:
        if (PortList[i].PortFlag & IOPORT)
          fprintf(textfile, "WORD_IOPORT 0x%04x", PortList[i].PortAddress);
        else if (PortList[i].PortFlag & MMIO_DST_IMMEDIATE)
          fprintf(textfile, "WORD_MMIOPORT 0x%08lx", PortList[i].PortAddress);
        else if (PortList[i].PortFlag & MMIO_DST_VARIABLE)
          fprintf( textfile,
                   "WORD_MMIOPORT %s",
                   sAdapter.pDecSection                         /*          */
                     [PortList[i].PortAddress]
                       .RegisterName);
        break;
      case DWORD_REG:
        if (PortList[i].PortFlag & IOPORT)
          fprintf(textfile, "DWORD_IOPORT 0x%04x", PortList[i].PortAddress);
        else if (PortList[i].PortFlag & MMIO_DST_IMMEDIATE)
          fprintf(textfile, "DWORD_MMIOPORT 0x%08lx", PortList[i].PortAddress);
        else if (PortList[i].PortFlag & MMIO_DST_VARIABLE)
          fprintf( textfile,
                   "DWORD_MMIOPORT %s",
                   sAdapter.pDecSection                         /*          */
                     [PortList[i].PortAddress]
                       .RegisterName);
        break;
    }
    if (PortList[i].PortFlag & MULTIPORT)
    {
      BYTE InRange = FALSE;            /* a range of indices started */
      USHORT IndexStart = 0;
      USHORT IndexEnd = 0;
      BYTE BitField;
      for (j = 0; j < 32; j++)    /* go thru all the mask bytes */
      {
        BitField = 1;
        for (k=0;k < 8;k++,BitField <<=1)
        {
          if (PortList[i].PortMask[j] & BitField)
          {
            if (!InRange)
            {
              IndexEnd = IndexStart = (j<<3)+k;
              InRange = TRUE;
            }
            else
              IndexEnd = (j<<3)+k;
          }
          else if (InRange)          /* a range ended, write it */
          {
            fprintf(textfile, ", 0x%02x-0x%02x",IndexStart,IndexEnd);
            InRange = FALSE;
          }
        }
      }
    }
    fprintf(textfile, ";\n");
  }
  fprintf(textfile, "\n");
  return (0);
}
/*****************************************************************************
 *
 * FUNCTION NAME = RegisterOperation()
 *
 * DESCRIPTION   = Execute register operation
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/
VOID RegisterOperation(                                         /*          */
  VOID *pDstRegister,
  VOID *pSrcRegister,
  USHORT Size,
  USHORT Operation,
  ULONG ulRight )                                               /*          */
{
  PVOID pvLeft;                                                 /*          */
  ULONG ulLeft;                                                 /*          */

  pvLeft =                                                      /*          */
    (( Operation & REGISTER_OPEQUAL )                           /*          */
     ? pDstRegister                                             /*          */
     : pSrcRegister);                                           /*          */
  ulLeft =                                                      /*          */
    ((Size == 1)                                                /*          */
     ? (ULONG) *(BYTE *) pvLeft                                 /*          */
     : *(ULONG *) pvLeft);                                      /*          */
  if( ( Operation & REGISTER_OPERAND )                          /*          */
      && ( ( Operation & REGISTER_OPEQUAL )                     /*          */
           || !( Operation & REGISTER_ALL ) ) )                 /*          */
    ulRight =                                                   /*          */
     ( (Size == 1)                                              /*          */
       ? (ULONG) *((BYTE *)pSrcRegister)                        /*          */
       : *((ULONG *)pSrcRegister) );                            /*          */
  if( Operation & REGISTER_NEGATE )                             /*          */
    ulRight = ~ ulRight;                                        /*          */
  switch( Operation & REGISTER_ALL )                            /*          */
  {
    case REGISTER_AND:
      ulLeft &= ulRight;                                        /*          */
      break;
    case REGISTER_OR:
      ulLeft |= ulRight;                                        /*          */
      break;
    case REGISTER_XOR:
      ulLeft ^= ulRight;                                        /*          */
      break;
    case REGISTER_SHL:
      ulLeft <<= ulRight;                                       /*          */
      break;
    case REGISTER_SHR:
      ulLeft >>= ulRight;                                       /*          */
      break;
    case NONE:                                                  /*          */
    default:                                                    /*          */
      ulLeft = ulRight;                                         /*          */
      break;                                                    /*          */
  }
  if( Size == 1 )                                               /*          */
    *((BYTE *)pDstRegister) = (BYTE) ulLeft;                    /*          */
  else if (Size == 4)                                           /*          */
    *((ULONG *)pDstRegister) = ulLeft;                          /*          */
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = DoCmd ( or DoOp ... Diddy Diddy Dum Diddy Do! )
 *
 * DESCRIPTION   = Do a pRegData operation on actual registers!
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID DoCmd(
  PREGDATA pRegData,
  PULONG pulRegs )                                              /*          */
{
  USHORT usIn;
  BYTE bSaveIndex;                                              /*          */
  USHORT usIndex;                                               /*          */
  USHORT usLastEntry;                                           /*          */

  switch( pRegData->Command )
  {
    case PMICMD_REGOP:                                          /*          */
      RegisterOperation(
        &pulRegs [pRegData->R.RegOp.DstRegIndex],               /*          */
        &pulRegs [pRegData->R.RegOp.SrcRegIndex],               /*          */
        pRegData->R.RegOp.RegSize,
        pRegData->R.RegOp.Operation,
        *(ULONG *)pRegData->Data );
      break;
    case PMICMD_INB:                                            /*          */
      pulRegs [pRegData->R.PortIO.StartIndex] =                 /*          */
        InpDelay( pRegData->R.PortIO.IndexPort );               /*          */
      break;
    case PMICMD_INW:                                            /*          */
      pulRegs [pRegData->R.PortIO.StartIndex] =                 /*          */
        InpwDelay( pRegData->R.WPortIO.Port );                  /*          */
      break;                                                    /*          */
    case PMICMD_OUTB:                                           /*          */
      OutpDelay( pRegData->R.PortIO.IndexPort,                  /*          */
                 (BYTE)                                         /*          */
                   ((pRegData->R.PortIO.Flags & WRITEREG_DATA)  /*          */
                    ? pulRegs [pRegData->R.PortIO.StartIndex]   /*          */
                    : *pRegData->Data) );                       /*          */
      break;
    case PMICMD_OUTW:
      OutpwDelay( pRegData->R.WPortIO.Port,                     /*          */
                  (USHORT)                                      /*          */
                    ((pRegData->R.PortIO.Flags & WRITEREG_DATA) /*          */
                     ? *(PUSHORT) &pulRegs [pRegData->R.PortIO.StartIndex] /*          */
                     : *(PUSHORT) pRegData->Data) );            /*          */
      break;
    case PMICMD_RMWBI:
      if( pRegData->R.RMW.IndPort == ATC_INDEXPORT )            /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      bSaveIndex = InpDelay( pRegData->R.RMW.IndPort );         /*          */
      if( pRegData->R.RMW.IndPort == ATC_INDEXPORT )            /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      OutpDelay( pRegData->R.RMW.IndPort,                       /*          */
                 (BYTE) pRegData->R.RMW.Index );                /*          */
      usIn = InpDelay( pRegData->R.RMW.DPort );                 /*          */
      usIn &= pRegData->R.RMW.ANDMask;
      usIn |= *pRegData->Data
              & ~ pRegData->R.RMW.ANDMask;                      /*          */
      if( pRegData->R.RMW.IndPort == ATC_INDEXPORT )            /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      OutpDelay( pRegData->R.RMW.IndPort,                       /*          */
                 (BYTE) pRegData->R.RMW.Index );                /*          */
      /* Cannot write to ATC1 == 0x03c1 on all adapters! */     /*          */
      /* Particularely not on TsengET4000W32!            */     /*          */
      OutpDelay( ((pRegData->R.RMW.IndPort == ATC_INDEXPORT)    /*          */
                  ? pRegData->R.RMW.IndPort                     /*          */
                  : pRegData->R.RMW.DPort ),                    /*          */
                 (BYTE) usIn );                                 /*          */
      if( pRegData->R.RMW.IndPort == ATC_INDEXPORT )            /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      OutpDelay( pRegData->R.RMW.IndPort,                       /*          */
                 bSaveIndex );                                  /*          */
      break;
    case PMICMD_RMWBN:                                          /*          */
      usIn = InpDelay( pRegData->R.RMW.IndPort );               /*          */
      usIn &= pRegData->R.RMW.ANDMask;
      usIn |= *pRegData->Data
              & ~ pRegData->R.RMW.ANDMask;                      /*          */
      OutpDelay( pRegData->R.RMW.DPort,                         /*          */
                 (BYTE) usIn );                                 /*          */
      break;
    case PMICMD_RMWWN:                                          /*          */
      usIn = InpwDelay( pRegData->R.RMW.IndPort );              /*          */
      usIn &= pRegData->R.RMW.ANDMask;                          /*          */
      usIn |= *(PUSHORT)pRegData->Data                          /*          */
              & ~ pRegData->R.RMW.ANDMask;                      /*          */
      OutpwDelay( pRegData->R.RMW.DPort,                        /*          */
                  usIn );                                       /*          */
      break;                                                    /*          */
    case PMICMD_BINB:                                           /*          */
      usLastEntry  = pRegData->R.PortIO.StartIndex +            /*          */
                       pRegData->R.PortIO.NumEntries;           /*          */
      if( pRegData->R.PortIO.IndexPort == ATC_INDEXPORT )       /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      bSaveIndex = InpDelay( pRegData->R.PortIO.IndexPort );    /*          */
      for( usIndex = pRegData->R.PortIO.StartIndex;             /*          */
           usIndex < usLastEntry;                               /*          */
           usIndex++ )                                          /*          */
      {
        if( pRegData->R.PortIO.IndexPort == ATC_INDEXPORT )     /*          */
          InpDelay( INPSTATUSREG1 );                            /*          */
        OutpDelay( pRegData->R.PortIO.IndexPort,                /*          */
                   (BYTE) usIndex );                            /*          */
        pulRegs [usIndex] =                                     /*          */
          InpDelay( pRegData->R.PortIO.DataPort );              /*          */
      }
      if( pRegData->R.PortIO.IndexPort == ATC_INDEXPORT )       /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      OutpDelay( pRegData->R.PortIO.IndexPort,                  /*          */
                 bSaveIndex );                                  /*          */
      break;                                                    /*          */
    case PMICMD_BOUTB:                                          /*          */
      usLastEntry  = pRegData->R.PortIO.StartIndex +            /*          */
                       pRegData->R.PortIO.NumEntries;           /*          */
      if( pRegData->R.PortIO.IndexPort == ATC_INDEXPORT )       /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      bSaveIndex = InpDelay( pRegData->R.PortIO.IndexPort );    /*          */
      for( usIndex = pRegData->R.PortIO.StartIndex;             /*          */
           usIndex < usLastEntry;                               /*          */
           usIndex++ )                                          /*          */
      {
        if( pRegData->R.PortIO.IndexPort == ATC_INDEXPORT )     /*          */
          InpDelay( INPSTATUSREG1 );                            /*          */
        OutpDelay( pRegData->R.PortIO.IndexPort,                /*          */
                   (BYTE) usIndex );                            /*          */
        OutpDelay( pRegData->R.PortIO.DataPort,                 /*          */
                   (BYTE) pulRegs [usIndex] );                  /*          */
      }
      if( pRegData->R.PortIO.IndexPort == ATC_INDEXPORT )       /*          */
        InpDelay( INPSTATUSREG1 );                              /*          */
      OutpDelay( pRegData->R.PortIO.IndexPort,                  /*          */
                 bSaveIndex );                                  /*          */
      break;                                                    /*          */
  }
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = DoCmds
 *
 * DESCRIPTION   = Do pRegData operations on actual registers!
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID DoCmds(                                                    /*          */
  PREGDATA pRegData,
  PULONG pulRegs )                                              /*          */
{
  if( pRegData )
    while( pRegData->Command != PMICMD_NONE )
    {
      DoCmd( pRegData,
             pulRegs );                                         /*          */
      pRegData++;
    }
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = LockPushState()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID LockPushState(                                             /*          */
  INT Adapter,
  INT Chip,
  PULONG pulRelockInfo )                                        /*          */
{
  DoCmds( FindUnlockData( Adapter,                              /*          */
                          Chip ),                               /*          */
          pulRelockInfo );                                      /*          */
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = LockPopState()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID LockPopState(                                              /*          */
  INT Adapter,
  INT Chip,
  PULONG pulRelockInfo )                                        /*          */
{
  PREGDATA pLockInfo;

  if( pLockInfo = FindLockData( Adapter, Chip ) )
    /* Skip over actual lock info */                            /*          */
    while( (pLockInfo->Command == PMICMD_REGOP)
           && (pLockInfo->R.PortIO.Flags & READWRITE_DATA) )
      pLockInfo++;
  DoCmds( pLockInfo,                                            /*          */
          pulRelockInfo );                                      /*          */
}

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

INT WriteLockData(INT Adapter,INT Chip)
{
  PREGDATA pLockInfo;

  LockPushState( Adapter,                                       /*          */
                 Chip,                                          /*          */
                 aulRelockInfo );                               /*          */
  /**
   **  Following change is for PMI file generated on internal     @V3.0YEE07
   **  to be run on external.  Always keep PR1B(CRT34) unlocked
   **  for read so that PMI file runs successful when run on
   **  external.  Otherwise, read as byte from the WD ID string.
   **  Now, make sure r5 in ParadiseUnlockData[4] always references
   **  CRT34 in svgawd.c.
   **/
  if ((Adapter == WESTERNDIG_ADAPTER) &&
      ((Chip == WESTERNDIG_WD9024_CHIP) ||
       (Chip == WESTERNDIG_WD9026_CHIP) ||
       (Chip == WESTERNDIG_WD9027_CHIP)))
    aulRelockInfo [5] = 0xa0;

  pLockInfo = FindLockData( Adapter, Chip );                    /*          */
  while( (pLockInfo->Command == PMICMD_REGOP)                   /*          */
         && (pLockInfo->R.PortIO.Flags & READWRITE_DATA) )      /*          */
  {                                                             /*          */
    if( pLockInfo->R.RegOp.RegSize == 1 )                       /*          */
      *pLockInfo->Data =                                        /*          */
        (BYTE) aulRelockInfo [pLockInfo->R.RegOp.DstRegIndex];  /*          */
    else if( pLockInfo->R.RegOp.RegSize == 4 )                  /*          */
      *(PULONG)pLockInfo->Data =                                /*          */
        aulRelockInfo [pLockInfo->R.RegOp.DstRegIndex];         /*          */
    pLockInfo++;                                                /*          */
  }                                                             /*          */
  LockPopState( Adapter,                                        /*          */
                Chip,                                           /*          */
                aulRelockInfo );                                /*          */
  if (pLockInfo = FindUnlockData(Adapter,Chip))
  {
    WriteComment(1, &comments[COMMENT_UNLOCKREGS]);
    fprintf(textfile, "[UnLock]\n");
    WriteCmdSection(pLockInfo);
  }
  if (pLockInfo = FindLockData(Adapter,Chip))
  {
    WriteComment(1, &comments[COMMENT_LOCKREGS]);
    WriteComment( sizeof(lockheader)/sizeof(char *),            /*          */
                  &lockheader[0] );                             /*          */
    fprintf(textfile, "[Lock]\n");
    WriteCmdSection(pLockInfo);
  }
  return (0);
}

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

INT WriteModeInfo(
  PCHIPINFO ChipInfo )                                          /*          */
{
  USHORT        usYResolution, usYCharSize;
  USHORT i = 0, j =0;                                           /*          */
  PCHIPHEADER   pChipHdr = ChipInfo->pChipHdr;
  CHAR          s[80];
  ULONG ulModeMemory;                                           /*          */

  fprintf(textfile, "[comment]\n\t");
  fprintf(textfile, "%s.\n\n", BuildModeString(pChipHdr, s));   /*JWK10*/

  fprintf(textfile, "[ModeInfo]\n");
  fprintf(textfile, "        ModeAttributes   = 0x%02x\n", pChipHdr->bModeAttributes);
  fprintf(textfile, "        BytesPerScanLine = %d\n", pChipHdr->usBytesPerScanLine);
  fprintf(textfile, "        XResolution      = %d\n", pChipHdr->usXResolution);

  if( !(pChipHdr->bModeAttributes & GRAPHICS_MODEATTR) )        /*          */
  { /*Even 132x44,80x43 and other numbers need calculation! */  /*          */
    usYCharSize = (CRTRegData[0x09] & 0x0f) + 1;                /*          */
    usYResolution = 1 + (CRTRegData[0x12] & 0xff)               /*          */
                      + ((CRTRegData[0x07] & 0x02) << 7)        /*          */
                      + ((CRTRegData[0x07] & 0x40) << 3);       /*          */
  }
  else
  {
    usYCharSize = pChipHdr->usYCharSize;
    usYResolution = pChipHdr->usYResolution;
  }

  fprintf(textfile, "        YResolution      = %d\n", usYResolution);

  if (pChipHdr->usXCharSize && usYCharSize)
  {
    fprintf(textfile, "        XCharSize        = %d\n", pChipHdr->usXCharSize);
    fprintf(textfile, "        YCharSize        = %d\n", usYCharSize);
  }

  fprintf(textfile, "        TextRows         = %d\n", pChipHdr->usTextRows);
  fprintf(textfile, "        BitsPerPixel     = %d\n", pChipHdr->bBitsPerPixel) ;
  fprintf(textfile, "        NumberOfPlanes   = %d\n", pChipHdr->bNumberOfPlanes);
  fprintf(textfile, "        PageLength       = %ld\n", pChipHdr->ulPageLength);
  fprintf(textfile, "        SaveSize         = %ld\n", pChipHdr->ulSaveSize);
  /* Required by existing PM drivers still: */                  /*          */
//fprintf(textfile, "        TotalMemory      = %ld\n", ulMemory);        /*          */
//fprintf(textfile, "        InterlaceMode    = %d\n", usInterlaceMode ); /*          */
  if( (sSVGA.AdapterType == WESTERNDIG_ADAPTER)                 /*          */
      && ((sSVGA.ChipType == WESTERNDIG_WD9024_CHIP)            /*          */
          || (sSVGA.ChipType == WESTERNDIG_WD9026_CHIP)         /*          */
          || (sSVGA.ChipType == WESTERNDIG_WD9027_CHIP))        /*          */
      && ((CRTRegData [0x33] & 0x60) == 0x60) /* Dual 16b STN *//*          */
      && (pChipHdr->usXResolution <= 720) )                     /*          */
    /* Dual panel 16-bit STNs (Super Twisted Nematic) must be *//*          */
    /* only 1/2M organization in order to function at all */    /*          */
    /* But do not limit for external only (non-STN) modes */    /*          */
    ulModeMemory =  0x80000L;           /* 1/2M */              /*          */
  else                                                          /*          */
    ulModeMemory =  sAdapter.ulTotalMemory;                     /*          */
  fprintf( textfile,                                            /*          */
           "        TotalMemory      = %ld\n",                  /*          */
           ulModeMemory );                                      /*          */
  fprintf(textfile, "        InterlaceMode    = %d\n", usInterlaceMode ); /*          */
//fprintf(textfile, "        MemoryIOAddress  = 0x%08lx\n", pChipHdr->ulMemoryIOAddress); /*          *//*          */
  if ((sAdapter.FormatSectionFlag & LINEAR_APERTURE_DECLARED) &&   /*            */
     (pChipHdr->bBitsPerPixel > 4))
  {
    fprintf(textfile, "        BufferAddress    = %s\n",
                        sAdapter.pDecSection[sAdapter.usLinearAperture].RegisterName);
    fprintf(textfile, "        ApertureSize     = 0x%08lx\n", sAdapter.ulTotalMemory);

  }
  else
  {
    fprintf(textfile, "        BufferAddress    = 0x%08lx\n", pChipHdr->ulBufferAddress);
    fprintf(textfile, "        ApertureSize     = 0x%08lx\n", pChipHdr->ulApertureSize);
  }
  fprintf(textfile, "        Int10ModeSet     = 0x%03x\n", ChipInfo->Int10Mode);
  fprintf(textfile, "\n");
  /*
  ** If there is monitor mode info for this mode, format it           
  */

  /* jwk02
  ** quick fix for tseng hardware cursor (until configurator fully implemented)
  */

  /* JWK10 for tsengw32, will use 1 monitormodeinfo in each mode set
  **       until can put setmode into dll (to program other registers
  **       for each refresh rate, ie other clocks and other crtc regs)
  */

  /* intercept if tseng and not diamond */
  if ( sSVGA.AdapterType == TSENG_ADAPTER
      && !((sOEM.Manufacturer == DIAMOND_MANUFACTURER) && (sSVGA.ChipType == TSENG_ET4000_CHIP)))  //          
  {
      fprintf(textfile, "[MonitorModeInfo]\n");
      fprintf(textfile, "        VerticalRefresh         = %d\n",
              TsengGetVerticalRefreshRate(pChipHdr->usXResolution,0));
      fprintf(textfile, "        VPolarityPositive       = %d\n",   /*JWK10*/
              TsengGetVerticalPolarity(pChipHdr->usXResolution));   /*JWK10*/
      fprintf(textfile, "        HPolarityPositive       = %d\n\n", /*JWK10*/
              TsengGetHorizontalPolarity(pChipHdr->usXResolution)); /*JWK10*/
  }
  else                                                /* @V3.0YEE02 */
  {
//@V3.0YEE03 if ((sDACINFO.DACFamily == S3SDAC_DAC) &&
    if ((sSVGA.AdapterType == S3_ADAPTER) &&
        ((sSVGA.ChipType == S3_86C864_CHIP) ||
         (sSVGA.ChipType == S3_86C964_CHIP)) &&                /*@V3.0YEE04*/
        (pChipHdr->bBitsPerPixel > 4))
    {
        fprintf(textfile, "[MonitorModeInfo]\n");
        fprintf(textfile, "        VerticalRefresh         = %d\n",MaxRefresh);
    }
    else
    {
      if (sAdapter.RefreshTable)
      {                                                                   /*JWK02*/
        while(i < MAX_REFRESH_MODES && sAdapter.RefreshTable[i].usYResolution)
        {
          if ((pChipHdr->usYResolution == sAdapter.RefreshTable[i].usYResolution) &&
              (pChipHdr->usXResolution == sAdapter.RefreshTable[i].usXResolution) &&
              (pChipHdr->bBitsPerPixel > 4))
          {
            j = 0;
            while(sAdapter.RefreshTable[i].VerticalRefresh[j] != NO_REFRESH)
            {
              fprintf(textfile, "[MonitorModeInfo]\n");
              fprintf(textfile, "        VerticalRefresh         = %d\n\n",
                                  sAdapter.RefreshTable[i].VerticalRefresh[j++]);
            }
            i = MAX_REFRESH_MODES;         //done
          }
          else
            i++;
        }
      }
    }
  }
  return (0);

}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = GetDACParameters()
 *
 * DESCRIPTION   = Read program parameters from DAC
 *                 Put into a register set array.
 *
 * INPUT         = usDACFamily = DAC family index.
 *                 pulRegs = register set array.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID GetDACParameters(                                          /*          */
  INT Adapter,                                                  /*          */
  INT Chip,                                                     /*          */
  USHORT usDacFamily,
  PULONG pulRegs )                                              /*          */
{
  PREGDATA pRegData;
  PSSVGADACINFO psSVGADacInfo;
  BOOL fRS2, fRS3, fForce;                                      /*          */

  LockPushState( Adapter,                                       /*          */
                 Chip,                                          /*          */
                 aulRelockInfo );                               /*          */
  psSVGADacInfo = &asSVGADacInfo [usDacFamily];
  pRegData = psSVGADacInfo->pRegDataDacProgram;
  /* Force RS3:2 commands for first output */                   /*          */
  fForce = TRUE;                                                /*          */
  fRS2 = fRS3 = FALSE;                                          /*          */
  for( pRegData = psSVGADacInfo->pRegDataDacProgram;
       pRegData->Command != PMICMD_NONE;
       pRegData++ )
  {
    if( pRegData->Command != PMICMD_REGOP )
    {
      /* Always set IPF when needed, even if already set */     /*          */
      if( fRS2
          || (pRegData->R.PortIO.Flags & RS2)
          || fForce )                                           /*          */
      {
        if( (fRS2 != (BOOL) !!(pRegData->R.PortIO.Flags & RS2)) /*          */
            || fForce )                                         /*          */
        {                                                       /*          */
          fRS2 = (BOOL) !!(pRegData->R.PortIO.Flags & RS2);
          DoCmds( (fRS2                                         /*          */
                   ? psCurAdapterInfo->pRegDataSVGADacRS2Set    /*          */
                   : psCurAdapterInfo->pRegDataSVGADacRS2Clear),/*          */
                  pulRegs );                                    /*          */
        }                                                       /*          */
        DoCmds( (fRS2                                           /*          */
                 ? psSVGADacInfo->pRegDataDacIPFSet             /*          */
                 : psSVGADacInfo->pRegDataDacIPFClear),         /*          */
                pulRegs );                                      /*          */
      }
      if( (fRS3 != (BOOL) !!(pRegData->R.PortIO.Flags & RS3))
          || fForce )                                           /*          */
      {
        fRS3 = (BOOL) !!(pRegData->R.PortIO.Flags & RS3);
        DoCmds( (fRS3
                 ? psCurAdapterInfo->pRegDataSVGADacRS3Set
                 : psCurAdapterInfo->pRegDataSVGADacRS3Clear),
                pulRegs );                                      /*          */
      }
      fForce = FALSE;                                           /*          */
    }
    if( (pRegData->Command != PMICMD_OUTB)
        || !(pRegData->R.PortIO.Flags & WRITEREG_DATA)
        || (pRegData->R.PortIO.Flags & EXECUTE_CMD) )
      DoCmd( pRegData,
             pulRegs );                                         /*          */
    else
    {
      /* Substitute INB for OUTB */
      pRegData->Command = PMICMD_INB;
      DoCmd( pRegData,
             pulRegs );                                         /*          */
      /* Restore original OUTB */
      pRegData->Command = PMICMD_OUTB;
    }
  } /* endfor () */
  LockPopState( Adapter,                                        /*          */
                Chip,                                           /*          */
                aulRelockInfo );                                /*          */
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = FormatParameters()
 *
 * DESCRIPTION   = Format program parameters to PMI file
 *                 from register set array.
 *
 * INPUT         = usDACFamily = DAC family index.
 *                 pulRegs = register set array.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID FormatParameters(                                          /*          */
  USHORT usCount,
  PULONG pulRegs )                                              /*          */
{
  BYTE bData;
  USHORT usParamIndex;
  REGDATA RegDataParam =
    {PMICMD_REGOP, NONE, NONE, 0x01, 0x00, WRITEONLY_DATA, &bData};

  for( usParamIndex = 0;
       usParamIndex < usCount;
       usParamIndex++ )
  {
    RegDataParam.R.RegOp.DstRegIndex = usParamIndex;
    bData = (BYTE) pulRegs [usParamIndex];                      /*          */
    WriteCmd( &RegDataParam );
  } /* endfor () */
}

/*****************************************************************************
 *
 * FUNCTION NAME = WriteDACParameters()                                    
 *
 * DESCRIPTION   = Depending on the bitsperpixel, and if a supported hi-color
 *                 DAC found, determine DAC command register value and
 *                 format the DAC section of the mode in the PMI file.
 *
 *                 S3 implementation of the Brooktree 485 RAMDAC is unique.
 *                 Bits 0 and 1 of CRT[55] controls the left 2 bits of the
 *                 RS 3:2 value and the right 2 bitse of the RS1:0 value is assigned
 *                 such that
 *                              00 = register 3C8
 *                              01 = register 3C9
 *                              02 = register 3C6
 *                              03 = register 3C7
 *
 *                 The 4 nibbles of the RS value determines a specific
 *                 Internal Register of the BT485 RAMDAC.
 *                 See the BT485 databook.
 *
 * INPUT         = Chipinfo and wFlag. If wFlag reset, no actual hardware is
 *                 read.
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID WriteDACParameters(
  INT Adapter,                                                  /*          */
  INT Chip,                                                     /*          */
  PCHIPHEADER pChipHdr,
  USHORT wFlag)                                                 /*          */
{
  USHORT usParamIndex;                                          /*          */
  PSSVGADACINFO psSVGADacInfo;                                  /*          */

  if( sDACINFO.DACFamily != Weitek_BT485DAC )                   /*          */
  {                                                             /*          */
    psSVGADacInfo = &asSVGADacInfo [sDACINFO.DACFamily];        /*          */
    if (wFlag == SET_DAC)
    {
      GetDACParameters( Adapter,                                /*          */
                        Chip,                                   /*          */
                        sDACINFO.DACFamily,                     /*          */
                        aulScratchRegs );                       /*          */
      if( sDACINFO.DACFamily == BT485_DAC )                     /*          */
      {
        /***
         ***  #9 BIOS sets       value in CR1 of Brooktree DAC
         ***  so we will adjust it now
         ***/
        if( (sOEM.Manufacturer == NUMBER9_MANUFACTURER)
            && (Chip == S3_86C928_CHIP)                        /*@V3.0YEE04*/
            && (pChipHdr->usVESAModeNumber == VESA_640_480_64K))/*          */
          aulScratchRegs [0x01] |= 0x08; /* set RGB=5:6:5 */
      }
    }
    else                  /* RESET_DAC */
    {
      /* Right now we do not get here */                        /*          */
      /* If someone wants a RESET_DAC, */                       /*          */
      /* I suggest we get the dac info during generatecleanup *//*          */
      /* and then format it here */                             /*          */
      for( usParamIndex = 0;                                    /*          */
           usParamIndex < psSVGADacInfo->usDacParamCount;       /*          */
           usParamIndex++ )                                     /*          */
        aulScratchRegs [usParamIndex] = 0;                      /*          */
      if( psSVGADacInfo->pRegDataDacProgram ==                  /*          */
            aRegDataDacSGSThomson )                             /*          */
        aulScratchRegs [0x03] = 0x02;                           /*          */
    }
    FormatParameters( psSVGADacInfo->usDacParamCount,           /*          */
                      aulScratchRegs );                         /*          */
  }
}
/*****************************************************************************
 *
 * FUNCTION NAME = WriteDACInfo()
 *
 * DESCRIPTION   = Depending on the bitsperpixel, and if a supported hi-color
 *                 DAC found, determine DAC command register value and
 *                 format the DAC section of the mode in the PMI file.
 *
 *
 * INPUT         = Chipheader and wFlag. If wFlag reset, no actual hardware is
 *                 read.
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID WriteDACInfo(                                              /*          */
  INT Adapter,                                                  /*          */
  INT Chip,                                                     /*          */
  PCHIPHEADER pChipHdr,                                         /*          */
  USHORT wFlag )
{

//if( !(pChipHdr->bModeAttributes & GRAPHICS_MODEATTR)          /*          */
//    && (wFlag & SET_DAC) )                                    /*          */
//  return;                   /* no processing for text modes *//*          */
  /*
  ** Execute the enable sequence.
  */
  WriteComment(1, &comments[COMMENT_HICOLOR]);
  WriteDACParameters( Adapter,                                  /*          */
                      Chip,                                     /*          */
                      pChipHdr,
                      wFlag );                                  /*          */
  if (TSENGDiamondW32 && ((pChipHdr->bBitsPerPixel > 8) ||
      (pChipHdr->usBytesPerScanLine == 132)))                   /*            */                                          /*           */
    fprintf(textfile,"call pfnPMIFixupClock;\n");               /*           */
  fprintf(textfile,"ProgramDAC;\n");

  /*
  ** Call refresh utility after program DAC values                          
  */
  if ((sOEM.Manufacturer == CIRRUS_MANUFACTURER) ||             /*          */
      ((sSVGA.AdapterType == S3_ADAPTER) &&                     /*          */
//@V3.0YEE02    ((sDACINFO.DACFamily == S3SDAC_DAC) ||          /*          */
       (sOEM.Manufacturer == LACUNA_MANUFACTURER)))             /*          */
     fprintf(textfile,"call pfnPMISetMonitorTimings;\n");       /*          */

}
/*****************************************************************************
 *
 * FUNCTION NAME = WriteDACFunction()
 *
 * DESCRIPTION   = Formats the [ProgramDAC] function
 *                 without writing the actual [ProgramDAC] header
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID WriteDACFunction(VOID)                                     /*          */
{
  BYTE          Data;
  PREGDATA      pRegData;
  REGDATA RegData[2] =                          /*            */
    { {PMICMD_REGOP,NONE,NONE,0x01,0x00,WRITEONLY_DATA,(PBYTE) &Data},
      {PMICMD_REGOP,NONE,NONE,0x01,0x01,WRITEONLY_DATA,(PBYTE) &Data}};
  CHAR szTempBuffer[256];
  CHAR *pTempBuffer = &szTempBuffer[0];
  BOOL fRS2, fRS3, fForce;                                      /*          */
  PSSVGADACINFO psSVGADacInfo;                                  /*          */

  if( sDACINFO.DACFamily == Weitek_BT485DAC )                   /*          */
  {                                   /*            */
    /*
    **   Notes on Brooktree 485 DAC on the Weitek adapter:
    **   CR0 = 80h for all modes
    **   CR2 = 32h for all modes
    **   Use CR3 to set 2x clock if running > 67.5 MHz (R0 in PMI file)
    **   Set CR1 according to pixel color depth (R1 in PMI file)
    */
    strcpy(szTempBuffer,"r255 set by pfnPMISetMonitorTimings as clock doubling flag.");
    WriteComment(1, &pTempBuffer);
    Data = 0x00;
    WriteCmd(&RegData[0]);            /* set CR1 of Brooktree DAC */
    fprintf(textfile,"if (r255 >= 1) goto NoDoubling\n");
    Data = 0x08;
    WriteCmd(&RegData[0]);            /* set CR1 of Brooktree DAC */
    fprintf(textfile,"NoDoubling:\n");
    fprintf(textfile,"if (BitsPerPixel > 8) goto HiColor\n");
    Data = 0x40;
    WriteCmd(&RegData[1]);            /* set CR2 of Brooktree DAC */
    fprintf(textfile,"goto SetDAC\n");
    fprintf(textfile,"HiColor:\n");
    fprintf(textfile,"if (BitsPerPixel > 16) goto TrueColor\n");
    Data = 0x30;
    WriteCmd(&RegData[1]);            /* set CR2 of Brooktree DAC */
    fprintf(textfile,"goto SetDAC\n");
    fprintf(textfile,"TrueColor:\n");
    Data = 0x30;
    WriteCmd(&RegData[1]);            /* set CR2 of Brooktree DAC */
    fprintf(textfile,"SetDAC:\n");
  }
  /* Force RS3:2 commands for first output */                   /*          */
  fForce = TRUE;                                                /*          */
  fRS2 = fRS3 = FALSE;                                          /*          */
  psSVGADacInfo = &asSVGADacInfo [sDACINFO.DACFamily];          /*          */
  for( pRegData = psSVGADacInfo->pRegDataDacProgram;            /*          */
       pRegData->Command != PMICMD_NONE;                        /*          */
       pRegData++ )                                             /*          */
  {                                                             /*          */
    if( pRegData->Command != PMICMD_REGOP )                     /*          */
    {                                                           /*          */
      /* Always set IPF when needed, even if already set */     /*          */
      if( fRS2                                                  /*          */
          || (pRegData->R.PortIO.Flags & RS2)                   /*          */
          || fForce )                                           /*          */
      {                                                         /*          */
        if( (fRS2 != (BOOL) !!(pRegData->R.PortIO.Flags & RS2)) /*          */
            || fForce )                                         /*          */
        {                                                       /*          */
          fRS2 = (BOOL) !!(pRegData->R.PortIO.Flags & RS2);     /*          */
          WriteCmds(                                            /*          */
            (fRS2                                               /*          */
             ? psCurAdapterInfo->pRegDataSVGADacRS2Set          /*          */
             : psCurAdapterInfo->pRegDataSVGADacRS2Clear) );    /*          */
        }                                                       /*          */
        WriteCmds(                                              /*          */
          (fRS2                                                 /*          */
           ? psSVGADacInfo->pRegDataDacIPFSet                   /*          */
           : psSVGADacInfo->pRegDataDacIPFClear) );             /*          */
      }                                                         /*          */
      if( (fRS3 != (BOOL) !!(pRegData->R.PortIO.Flags & RS3))   /*          */
          || fForce )                                           /*          */
      {                                                         /*          */
        fRS3 = (BOOL) !!(pRegData->R.PortIO.Flags & RS3);       /*          */
        WriteCmds(                                              /*          */
          (fRS3                                                 /*          */
           ? psCurAdapterInfo->pRegDataSVGADacRS3Set            /*          */
           : psCurAdapterInfo->pRegDataSVGADacRS3Clear) );      /*          */
      }                                                         /*          */
      fForce = FALSE;                                           /*          */
    }                                                           /*          */
    WriteCmd( pRegData );                                       /*          */
  }                                                             /*          */
  fprintf( textfile,                                            /*          */
           "\n" );                                              /*          */
}

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

INT WriteSetMode(
  INT Adapter,                                                  /*          */
  INT Chip,                                                     /*          */
//@V3.0YEE02 USHORT usMode,
  PCHIPINFO ChipInfo )
{
  USHORT        HiColorMode;
  PREGDATA      pRegData = ChipInfo->pRegData;
  PCHIPHEADER   pChipHdr = ChipInfo->pChipHdr;
  USHORT        Addr6845;                                       /*          */

  fprintf(textfile, "[SetMode]\n\n");
  if(sAdapter.FormatSectionFlag & CALL_SET_MODE)                /*          */
  {
    fprintf(textfile, "call pfnPMISetMode;\n\n");
    return 0;
  }

  /*JWK10 did not work when AFTER command sequence! */
    if (TSENGDiamondW32)                                        /*JWK10*/
    {
       if (ChipInfo->Int10Mode > 0x12)                          /*          */
          fprintf(textfile,"call pfnPMISetMonitorTimings;\n");     /*          */
//                    DIA_WriteClockStream(textfile,
//                                    pChipHdr->usXResolution,
//                                    pChipHdr->usYResolution,
//                                    pChipHdr->bBitsPerPixel);
    }




//WriteDACInfo( Adapter,                                        /*          */
//              Chip,                                           /*          */
//              pChipHdr,                                       /*          */
//              RESET_DAC );                                    /*          */
  HiColorMode =                                                 /*          */
    (pChipHdr->bBitsPerPixel > 8)                               /*          */
    || ((pChipHdr->usVESAModeNumber == VESA_1280_1024_256)      /*          */
        && (sDACINFO.DACFamily > HICOLOR_DAC)
        && (sDACINFO.DACFamily <= BT485_DAC));                  /*          */

  /* write hicolor setmode section */                           /*          */

  /*
  ** Modifications to the sequence in the chipdata.c
  */
  /*             start
  **  There is a     in the S3 chip.  For SVGA graphic modes:
  **  Before setting Bits 2,3 of 3C2 = 11b, set:
  **    Bits 4,5 of CR5C = 0
  **    CR42 = 0
  **    Bit 7 of CR11 = 0
  **    CR0 = 5F
  */
  if (Adapter == S3_ADAPTER)
  {
    if ((ChipInfo->Int10Mode > 0x100) &&                        /*          */
        ((MiscOutRegData & 0x0c) == 0x0c))                      /*          */
    {
      Addr6845 = MONO_INDEXPORT + ((MiscOutRegData & 0x01) << 5);

      if (sOEM.Manufacturer == LACUNA_MANUFACTURER)
        fprintf(textfile, "rmwbi(0x%03x, 0x%03x, 0x5c, 0xcf, 0x00);\n",
                Addr6845, Addr6845+1);

      fprintf(textfile, "outb(0x%03x, 0x42);\n", Addr6845);
      fprintf(textfile, "outb(0x%03x, 0x00);\n", Addr6845+1);
      fprintf(textfile, "rmwbi(0x%03x, 0x%03x, 0x11, 0x7f, 0x00);\n",
                Addr6845, Addr6845+1);                          /*          */
      fprintf(textfile, "outb(0x%03x, 0x00);\n", Addr6845);     /*          */
      fprintf(textfile, "outb(0x%03x, 0x5F);\n", Addr6845+1);   /*          */
    }
  }                                                             /*           end */
  /*
  ** Write the sequence as specified in the chipdata.c
  */
  while( pRegData->Command != PMICMD_NONE )
  {
    switch( pRegData->Command )
    {
      case PMICMD_READB:
      case PMICMD_READW:
      case PMICMD_READDW:
      case PMICMD_WRITEB:
      case PMICMD_WRITEW:
      case PMICMD_WRITEDW:
        WriteComment(1, &comments[COMMENT_SETMEMORYREGS]);      /*          */
        break;
      case PMICMD_REGOP:                                        /*          */
        /* Do not generate comments for regops */               /*          */
        break;                                                  /*          */
      default:
        if( (pRegData->R.PortIO.IndexPort & 0x03f8) == 0x02e8 ) /*          */
          WriteComment(1, &comments[COMMENT_SETENHANCED]);      /*          */
        else                                                    /*          */
          switch( pRegData->R.PortIO.IndexPort )
          {
            case MISCOUTPUTREG_WRITE :
            case MISCOUTPUTREG_READ :                           /*          */
              WriteComment(1, &comments[COMMENT_SETMISCOUTPUT]);/*          */
              break;
            case  CRT_INDEXPORT :
            case  CRT_DATAPORT :                                /*          */
              WriteComment( 1, &comments [COMMENT_SETCRT] );    /*          */
              /* unprotect CRT regs 1-7   */
              if( (pRegData->Command == PMICMD_BOUTB)           /*          */
                  && (pRegData->R.PortIO.StartIndex < 0x11) )   /*          */
              {                                                 /*          */
                EmitCmd( PMICMD_OUTB,                           /*          */
                         0x00,
                         psCurAdapterInfo->                     /*          */
                           pusfnSVGAAdjustedPort( 0x03d4 ),     /*          */
                         0x11 );                                /*          */
                EmitCmd( PMICMD_OUTB,                           /*          */
                         0x00,                                  /*          */
                         psCurAdapterInfo->                     /*          */
                           pusfnSVGAAdjustedPort( 0x03d5 ),     /*          */
                         0x0e );                                /*          */
              }                                                 /*          */
              break;
            case  GDC_INDEXPORT :
            case  GDC_DATAPORT :                                /*          */
              WriteComment( 1, &comments [COMMENT_SETGDC] );    /*          */
              break;
            case  SEQ_INDEXPORT :
            case  SEQ_DATAPORT :                                /*          */
              WriteComment(1, &comments [COMMENT_SETSEQUENCER]);/*          */
              break;
            case  ATC_INDEXPORT :
            case  ATC_DATAPORT :                                /*          */
              WriteComment(1, &comments[COMMENT_SETATC]);       /*          */
              break;
            case  MC_SETUPREG:
            case  MC_POS3REG:
              if (sOEM.Manufacturer != ORCHID_MANUFACTURER)     /*          */
                 break;
              WriteComment(1, &comments[COMMENT_SETPOS]);       /*          */
              break;
            default :                                           /*          */
              WriteComment(1, &comments[COMMENT_SETOTHER]);     /*          */
              break;                                            /*          */
          }
    }
    /*
    ** Generate appropriate commands into file from current RegData entry.
    */

    WriteCmd(pRegData);

    pRegData++;

  }
  /*
  ** Format the call to IBMGPMI to program the external clock.
  */
  if( (sOEM.Manufacturer == DIAMOND_MANUFACTURER)               /*          */
      && (((Adapter == TSENG_ADAPTER) && (Chip == TSENG_ET4000_CHIP))                            /*          */
          || (Adapter == WESTERNDIG_ADAPTER)) )                 /*          */
  {
    fprintf(textfile, "call pfnPMISetMonitorTimings;\n");       /*          */
  }
//jwkxxx  else   /* in case manufacturer not set, ie DiamondW32 but not in IBMGPMI (stealth) */
//jwkxxx  {
//jwkxxx    if (TSENGDiamondW32)                                        /*JWK10*/
//jwkxxx    {
//jwkxxx          DIA_WriteClockStream(textfile,
//jwkxxx                          pChipHdr->usXResolution,
//jwkxxx                          pChipHdr->usYResolution,
//jwkxxx                          pChipHdr->bBitsPerPixel);
//jwkxxx    }
//jwkxxx  }

    /* For Thinkpad systems only:  need additional fixups         @V3.0YEE07*/
    if  (sOEM.Manufacturer == THINKPAD_MANUFACTURER)            /*@V3.0YEE09*/
      ThinkpadModeFixup(pChipHdr);                              /*@V3.0YEE09*/

//if (HiColorMode)                                              /*          */
    WriteDACInfo( Adapter,                                      /*          */
                  Chip,                                         /*          */
                  pChipHdr,                                     /*          */
                  SET_DAC );                                    /*          */
  return (0);
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = FindCleanupData()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

PREGDATA FindCleanupData(INT Adapter,INT Chip)
{
  PREGDATA pCleanData = NULL;  /*            */

  switch(Adapter)
  {
    case DEFAULT_ADAPTER:
      pCleanData = VGACleanup;
      break;
    case ATI_ADAPTER:
      if( Chip <= ATI_28800_CHIP )                              /*          */
        pCleanData = ATICleanup;
      else if( Chip <= ATI_68800_CHIP )                         /*          */
        pCleanData = ATIMach32Cleanup;                          /*          */
      else
        pCleanData = ATIMach64Cleanup;
      break;
    case CIRRUS_ADAPTER:
      pCleanData = CirrusCleanData;
      break;
    case IBM_ADAPTER:
      pCleanData = IBMCleanData;
      break;
    case S3_ADAPTER:
      pCleanData = S3CleanData;
      break;
    case TSENG_ADAPTER:
      if( Chip >= TSENG_ET4000W32_CHIP )
        pCleanData = TsengET4000W32CleanData;
      else
        pCleanData = TsengET4000CleanData;
      break;
    case VIDEO7_ADAPTER:
      pCleanData = Video7CleanData;
      break;
    case WESTERNDIG_ADAPTER:
      switch (Chip)                                             /*          */
      {                                                         /*          */
        case  WESTERNDIG_PVGA1A_CHIP :                          /*          */
        case  WESTERNDIG_WD9000_CHIP :                          /*          */
        case  WESTERNDIG_WD9011_CHIP :                          /*          */
        case  WESTERNDIG_WD9030_CHIP :                          /*          */
        case  WESTERNDIG_WD9031_CHIP :                          /*          */
        default:                                                /*          */
          /* Desktop */                                         /*          */
          pCleanData = WDCleanData1;                            /*          */
          break;                                                /*          */
        case  WESTERNDIG_WD9024_CHIP :                          /*          */
        case  WESTERNDIG_WD9026_CHIP :                          /*          */
        case  WESTERNDIG_WD9027_CHIP :                          /*          */
          /* LCD/Laptop/Flat Panel */                           /*          */
          pCleanData = WDCleanData2;                            /*          */
          break;                                                /*          */
        case  WESTERNDIG_WD9033_CHIP :                          /*          */
          /* Desktop */                                         /*          */
          pCleanData = WDCleanData3;                            /*          */
          break;                                                /*          */
      }
      break;
  }
  return( pCleanData );
}

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

VOID WriteCleanup(                                              /*          */
  INT Adapter,
  INT Chip,
  PCHIPHEADER pChipHdr )                                        /*          */
{
  PREGDATA pCleanData;                                          /*          */

  pCleanData = FindCleanupData( Adapter, Chip );                /*          */

  fprintf(textfile, "[Cleanup]\n");                             /*          */
  WriteCmds( pCleanData );                                      /*          */

//@V3.0YEE10  ThinkpadCleanup();                                /*@V3.0YEE09*/

  /*** include the DAC section into cleanup to reset to VGA ***             */
//WriteDACParameters(pChipHdr, RESET_DAC);                      /*          */
  WriteDACParameters( Adapter,                                  /*          */
                      Chip,                                     /*          */
                      pChipHdr,
                      SET_DAC);                                 /*          */
  WriteDACFunction();                                           /*          */
}
/*****************************************************************************
 *
 * FUNCTION NAME = WriteClockFunction()
 *
 * DESCRIPTION   = If clock chip present, write
 *                 specific function body
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/
VOID  WriteClockFunction(INT Adapter,OEMINFO sOEM)
{
  PREGDATA pRegData;                       /*            */
  switch( Adapter )
  {
    case WEITEK_ADAPTER:
      switch( sOEM.Manufacturer )
      {
        case  DIAMOND_MANUFACTURER :
          fprintf(textfile,"[ProgramClock]\n");
          WriteCmdSection( &ICDesign1 [0][0] );
          break;
      }
      break;                                       /*           start*/
    case S3_ADAPTER:
      if ((sSVGA.ChipType == S3_86C864_CHIP) ||
          (sSVGA.ChipType == S3_86C964_CHIP))
      {
         switch (sDACINFO.DACFamily)
         {
           case S3SDAC_DAC:
             fprintf(textfile,"[ProgramClock]\n");
             pRegData = &ICDesign1[S3SDACClk][0];
             WriteCmdSection(pRegData);
           break;
         }
      }
      break;                                       /*           end  */
  }
}
/*****************************************************************************
 *
 * FUNCTION NAME = WriteClockModeSection()                     
 *
 * DESCRIPTION   = If clock chip present, write
 *                 specific mode function call.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/
VOID  WriteClockModeSection(INT ModeIndex,INT Adapter,OEMINFO sOEM)
{
  BYTE Data;
  PREGDATA pS3RegData;
  REGDATA S3RegData[4] =
    { {PMICMD_REGOP,NONE,NONE,0x01,0x00,WRITEONLY_DATA,(PBYTE) &Data},
      {PMICMD_REGOP,NONE,NONE,0x01,0x01,WRITEONLY_DATA,(PBYTE) &Data},
      {PMICMD_REGOP,NONE,NONE,0x01,0x02,WRITEONLY_DATA,(PBYTE) &Data},
      {PMICMD_REGOP,NONE,NONE,0x01,0x03,WRITEONLY_DATA,(PBYTE) &Data} };
  USHORT i = 0;

  LockPushState( Adapter,                                       /*          */
                 sSVGA.ChipType,                                /*          */
                 aulRelockInfo );                               /*          */
  switch(Adapter)
  {
   case S3_ADAPTER:
     if ((sSVGA.ChipType == S3_86C864_CHIP) ||
         (sSVGA.ChipType == S3_86C964_CHIP))
     {
        switch (sDACINFO.DACFamily)
        {
           case S3SDAC_DAC:
             WriteComment(1, &comments[COMMENT_CLOCK_CHIP]);
             pS3RegData = &ICDesign1[S3SDACClk][0];
             while (pS3RegData->Command != PMICMD_NONE)
             {
               switch (pS3RegData->Command)
               {
                 case PMICMD_INB:
                 case PMICMD_RMWBI:
                   DoCmd( pS3RegData,
                          aulScratchRegs );                     /*          */
                   break;
                 case PMICMD_OUTB:
                   if ((pS3RegData->R.PortIO.IndexPort !=  CRT_INDEXPORT) &&
                       (pS3RegData->R.PortIO.IndexPort !=  CRT_DATAPORT)  &&
                       (pS3RegData->R.PortIO.Flags & WRITEREG_DATA))
                   {
                      Data = InpDelay( pS3RegData->R.PortIO.IndexPort );
                      WriteCmd(&S3RegData[i]);
                      i++;
                   }
                   else            /* CRT_INDEX/DATA PORT */
                     DoCmd( pS3RegData,
                            aulScratchRegs );                   /*          */
                   break;
               }                   /*end switch pS3RegData*/
               pS3RegData++;
             }                     /* endwhile ()         */
           fprintf(textfile,"ProgramClock;\n");
           break;
        }                          /*end switch DACINFO   */
     }                             /*end 864/964 test     */
     break;                        /*end S3 adapter test  */
  }
  LockPopState( Adapter,                                        /*          */
                sSVGA.ChipType,                                 /*          */
                aulRelockInfo );                                /*          */
}
/*****************************************************************************
 *
 * FUNCTION NAME = IsVesaBIOS(long *)
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

INT IsVesaBIOS(PULONG pulMemorySize, USHORT far * * pusSupportedModes)
{
  static union REGS regs;
  static struct SREGS sregs;
  SVESAVGAINFOBLOCK svgainfo = { 0 } ;                          /*          */
  PSVESAVGAINFOBLOCK p = &svgainfo;                             /*          */

  strcpy( sAdapter.szRevision, "UNKNOWN" );                     /*          */
  regs.x.ax = 0x4f00;
  regs.x.di = OFFSETOF(p);
  sregs.es = SEGMENTOF(p);
  int86x(VBIOS, &regs, &regs, &sregs);

  if( (regs.x.ax != 0x004F)
      || !svgainfo.TotalMemory
      || strncmp( svgainfo.VESASignature, "VESA", 4 ) )         /*          */
    return (0);
  strcpy( sAdapter.szRevision, svgainfo.OEMStringPtr );         /*          */

  /*!! OK which version had this first?                     */  /*          */
  /*!! The original one does NOT according to */                /*          */
  /*!! Richard P. Ferraro                            */         /*          */
  /*!! "Programmer's Guide to the EGA and VGA Cards" */         /*          */
  /*!! WD indicates version 0x0102 and they set a size" */      /*          */
  *pulMemorySize =                                              /*          */
    ((svgainfo.VESAVersion >= 0x0100)                           /*          */
       /* 64Kbyte blocks: */                                    /*          */
     ? (svgainfo.TotalMemory * 0x10000L)                        /*          */
     : sSVGA.Memory);                   /* Use our detection */ /*          */

  /*
  ** Set pointer to supported modes.
  */
  *pusSupportedModes = svgainfo.VideoModePtr;

  return(1);
}

/*****************************************************************************
 *
 * FUNCTION NAME = SetVideoMode()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 ****************************************************************************/

INT SetVideoMode(USHORT Mode,INT Adapter,INT cols, INT BitsPerPixel) /*          */
{
  static union REGS regs;               /* sw interrupt registers           */
  BOOL fModeSupported;
  PUSHORT pusMode;                                              /*          */

  if( Mode == MODE_NOT_SUPPORTED )      /* set mode only if supp            */
    return( FALSE );
  if( Mode >= 0x100 )                   /* VESA-style setmode *//*          */
  {
    /* First check supported mode list */                       /*          */
    /* In case BIOS crashes on unsupported modes! */            /*          */
    fModeSupported = fVesaBIOS                                  /*          */
                     && !!pusSupportedModes;                    /*          */
    if( fModeSupported )                                        /*          */
      for( pusMode = pusSupportedModes;                         /*          */
           !(fModeSupported = (*pusMode == Mode))               /*          */
           && (*pusMode != 0xffff);                             /*          */
           pusMode++ )                                          /*          */
      { /* Keep searching */ }                                  /*          */
    if( fModeSupported )                                        /*          */
    {                                                           /*          */
      regs.x.ax = 0x4f02;               /* VESA-style setmode */
      regs.x.bx = Mode;
      int86(VBIOS, &regs, &regs);       /* set mode via int 10*/
      fModeSupported = (BOOL) (regs.x.ax == 0x004f);            /*          */
    } /* endif mode is in list */                               /*          */
    if( fModeSupported )                                        /*          */
    {
      regs.x.ax = 0x4f03;               /* Issue 4f03 and retrieve current mode */
      regs.x.bx = 0x0000;               /* In case no 0x4f03! *//*          */
      int86(VBIOS, &regs, &regs);       /* this should not change registers */
      fModeSupported =
        (BOOL) ((regs.x.ax == 0x004f)                           /*          */
                && (regs.x.bx == Mode));                        /*          */
    } /* endif mode set succeeds */
  }
  else                                  /* NOT Vesa mode: */    /*          */
  {
    regs.h.ah = 0x00;                   /* set up for setmode bios call     */
    regs.h.al = (BYTE) Mode;
    switch( Adapter )                   /* In case unusual:   *//*          */
    {
      case TSENG_ADAPTER:
        if( BitsPerPixel > 8 )
        {
          regs.x.ax = 0x10F0;           /* set up for setmode bios call     */
          if (BitsPerPixel > 16)
          {
            regs.h.bl = 0xff;           /* set RGB 24 bpp */
            regs.h.bh = (BYTE) Mode;
          }
          else
          {
            regs.h.bh = 0;
            regs.h.bl = (BYTE) Mode;
          }
        }
        break;
      case VIDEO7_ADAPTER :
        regs.x.ax = 0x6f05;             /* set up for setmode bios call     */
        regs.h.bl = (BYTE) Mode;
        break;
      default:
        break;
    }
    int86(VBIOS, &regs, &regs);         /* set mode via int 10*/
    fModeSupported =                    /* set default value */ /*          */
      (BOOL) ((pBiosData[0x4a] == (UCHAR)cols)                  /*          */
              && (pBiosData[0x49] == (UCHAR) Mode));            /*          */
    switch (Adapter)
    {
      case ATI_ADAPTER:
      case IBM_ADAPTER:
      case VIDEO7_ADAPTER:
        /* Check columns only. Mode not reliable. */
        fModeSupported =                                        /*          */
          (BOOL) (pBiosData[0x4a] == (UCHAR)cols);
        break;
      case TSENG_ADAPTER:
        if( BitsPerPixel > 8 )                                  /*          */
        {
          fModeSupported = (BOOL) (regs.x.ax == 0x0010);        /*          */
          if( fModeSupported                                    /*          */
              && (BitsPerPixel == 16) )                         /*          */
          {
            regs.x.ax = 0x10F2;        /* set up for set high color format */
            regs.x.bx = 0x0002;        /* set 5/6/5 format */
            int86(VBIOS, &regs, &regs);
            fModeSupported = (BOOL) (regs.x.ax == 0x0010);      /*          */
          }
        }
        /* else default return */                               /*          */
        break;
      default:                                                  /*          */
        break;                                                  /*          */
    } /* endswitch */
  }
  return( fModeSupported );                                     /*          */
}
/*****************************************************************************
 *
 * FUNCTION NAME = ReadMMIORegister()
 *
 * DESCRIPTION   = If there is a way of reading the memory mapped hardware
 *                 in REAL mode, this function will have the knowledge of
 *                 how to generate the address and return the data.
 *
 * INPUT         = REGDATA *
 * OUTPUT        = Source field of the REGDATA is set.
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/
VOID  ReadMMIORegister(
  REGDATA *RegData,
  ULONG ulMMIOBaseAddress )                                     /*          */
{
   /*
   ** This is just a sample code. In REAL mode, physical addresses beyond
   ** 1MB can not be accessed, so this code is just demonstrating what is the
   ** expected funcionality. On adapter basis, real mode addresses are
   ** generated usually by combining address bus bits and an IO port for
   ** the highest 8 bits.
   */
   VOID *Destination = (PVOID) (sAdapter.pDecSection            /*          */
                                  [RegData->R.MMIO.Destination]
                                    .RegisterOffset +
                                ulMMIOBaseAddress);             /*          */
   if( RegData->Command == PMICMD_WRITEB )
      RegData->R.MMIO.Source = (BYTE) *((BYTE *) Destination);
   else if( RegData->Command == PMICMD_WRITEW )
      RegData->R.MMIO.Source = (USHORT) *((USHORT *) Destination);
   else
      RegData->R.MMIO.Source = (ULONG) *((ULONG *) Destination);
}
/*****************************************************************************
 *
 * FUNCTION NAME = ReadAllMMIORegisters()
 *
 * DESCRIPTION   = If there is a way of reading the memory mapped hardware
 *                 in REAL mode, this function will have the knowledge of
 *                 how to generate the address and return the data.
 *
 * INPUT         = REGDATA *
 * OUTPUT        = Data array of the REGDATA is set.
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/
VOID ReadAllMMIORegisters(
  REGDATA *RegData,
  ULONG ulMMIOBaseAddress )                                     /*          */
{
  ULONG pbData,k;
  VOID *pSource;
  /*
  ** MMIO_READWRITE_ALL is used when the entire declaration section
  ** needs to be read from the hardware and stored in pData.
  ** Developer must make sure that pData has enough room to fit
  ** all the required register data.
   ** This is just a sample code. In REAL mode, physical addresses beyond
   ** 1MB can not be accessed, so this code is just demonstrating what is the
   ** expected funcionality. On adapter basis, real mode addresses are
   ** generated usually by combining address bus bits and an IO port for
   ** the highest 8 bits.
  */
  pbData = (ULONG) &RegData->Data[0];
  for( k = 0;
       sAdapter.pDecSection[k].RegisterName != NULL;            /*          */
       k++ )
  {
    pSource = (VOID *) (sAdapter.pDecSection[k].RegisterOffset +/*          */
                        ulMMIOBaseAddress);                     /*          */
    if( RegData->Command == PMICMD_WRITEB )                     /*          */
       (BYTE) *((BYTE *) (pbData + k)) = (BYTE) *((BYTE *) pSource);
    else if( RegData->Command == PMICMD_WRITEW )
       (USHORT) *((USHORT *) (pbData+k*2)) = (USHORT) *( (USHORT *) pSource);
    else
       (ULONG) *((ULONG *) (pbData+k*4)) = (ULONG) *( (ULONG *) pSource);
  }
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = ModifyCmd()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID ModifyCmd(
  PCHIPHEADER pChipHdr,
  PREGDATA pRegData )
{
  USHORT IndexPort;
  USHORT DataPort;
  BYTE   *pbData;
  BYTE bSaveIndex;                                              /*          */
  USHORT usIndex;                                               /*          */
  USHORT usLastEntry;                                           /*          */

  IndexPort = pRegData->R.PortIO.IndexPort;
  DataPort = pRegData->R.PortIO.DataPort;
  pbData = pRegData->Data;                                      /*          */
  if( pRegData->R.PortIO.Flags & EXECUTE_CMD )                  /*          */
    DoCmd( pRegData,                                            /*          */
           aulScratchRegs );                                    /*          */
  if( pRegData->R.PortIO.Flags & READWRITE_DATA )               /*          */
  {                                                             /*          */
    switch( pRegData->Command )                                 /*          */
    {                                                           /*          */
      case PMICMD_WRITEB:                                       /*          */
      case PMICMD_WRITEW:
      case PMICMD_WRITEDW:
        /*
        ** If MMIO write operation needs data to be read from
        ** the hardware following a mode set,
        ** flag READWRITE_DATA will be used.
        ** Valid with WRITEx were source is an immediate
        ** value and destination a hardware register.
        */
        if( (pRegData->R.MMIO.MemFlags & MMIO_SRC_IMMEDIATE)
            && (pRegData->R.MMIO.MemFlags & MMIO_DST_VARIABLE) )
          if( pRegData->R.MMIO.MemFlags & READWRITE_DATA )
            ReadMMIORegister( pRegData,
                              sAdapter.ulMMIOBaseAddress);      /*          */
          else if( (pRegData->R.MMIO.MemFlags & MMIO_READWRITE_ALL)
                   && pRegData->Data )
            ReadAllMMIORegisters( pRegData,
                                  sAdapter.ulMMIOBaseAddress);  /*          */
        break;                                                  /*          */
      case PMICMD_OUTB:                                         /*          */
        *pbData = InpDelay( IndexPort );                        /*          */
        break;                                                  /*          */
      case PMICMD_OUTW:                                         /*          */
        *(PUSHORT) pbData = InpwDelay( IndexPort );             /*          */
        break;                                                  /*          */
      case PMICMD_BOUTB:                                        /*          */
        usLastEntry  = pRegData->R.PortIO.StartIndex +          /*          */
                         pRegData->R.PortIO.NumEntries;         /*          */
        if( IndexPort == ATC_INDEXPORT )                        /*          */
          InpDelay( INPSTATUSREG1 );                            /*          */
        bSaveIndex = InpDelay( IndexPort );                     /*          */
        for( usIndex = pRegData->R.PortIO.StartIndex;           /*          */
             usIndex < usLastEntry;                             /*          */
             usIndex++ )                                        /*          */
        {
          if( IndexPort == ATC_INDEXPORT )                      /*          */
            InpDelay( INPSTATUSREG1 );                          /*          */
          OutpDelay( IndexPort,                                 /*          */
                     (BYTE) usIndex );                          /*          */
          *pbData++ = InpDelay( DataPort );                     /*          */
        }
        if( IndexPort == ATC_INDEXPORT )                        /*          */
          InpDelay( INPSTATUSREG1 );                            /*          */
        OutpDelay( IndexPort,                                   /*          */
                   bSaveIndex );                                /*          */
        break;                                                  /*          */
      case PMICMD_RMWBI:                                        /*          */
        if( IndexPort == ATC_INDEXPORT )                        /*          */
          InpDelay( INPSTATUSREG1 );                            /*          */
        bSaveIndex = InpDelay( IndexPort );                     /*          */
        if( IndexPort == ATC_INDEXPORT )                        /*          */
          InpDelay( INPSTATUSREG1 );                            /*          */
        OutpDelay( IndexPort,                                   /*          */
                   (BYTE) pRegData->R.RMW.Index );              /*          */
        *pbData = InpDelay( DataPort );                         /*          */
        /* Do not and with mask until outputting.          */   /*          */
        /* That way we can look at the WHOLE current value */   /*          */
        /* whereever else that may be desired.             */   /*          */
        /* This IS needed by WD!                           */   /*          */
        /*        & ~pRegData->R.RMW.ANDMask;              */   /*          */
        if( IndexPort == ATC_INDEXPORT )                        /*          */
          InpDelay( INPSTATUSREG1 );                            /*          */
        OutpDelay( IndexPort,                                   /*          */
                   bSaveIndex );                                /*          */
        break;                                                  /*          */
      case PMICMD_RMWBN:                                        /*          */
        *pbData = InpDelay( IndexPort );                        /*          */
        /* Do not and with mask until outputting.          */   /*          */
        /* That way we can look at the WHOLE current value */   /*          */
        /* whereever else that may be desired.             */   /*          */
        /* This IS needed by WD!                           */   /*          */
        /*        & ~pRegData->R.RMW.ANDMask;              */   /*          */
        break;                                                  /*          */
      case PMICMD_RMWWN:                                        /*          */
        *(PUSHORT)pbData = InpwDelay( IndexPort );              /*          */
        /* Do not and with mask until outputting.          */   /*          */
        /* That way we can look at the WHOLE current value */   /*          */
        /* whereever else that may be desired.             */   /*          */
        /* This IS needed by WD!                           */   /*          */
        /*        & ~pRegData->R.RMW.ANDMask;              */   /*          */
        break;                                                  /*          */
    } /* end switch */                                          /*          */
  } /* end if */                                                /*          */
}

/*****************************************************************************
 *
 * FUNCTION NAME = SetupHardware()
 *
 * DESCRIPTION   = Set video mode and prepare for reading.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0 if success
 * RETURN-ERROR  = 1 if failure
 *
 ****************************************************************************/

INT SetupHardware(
  PCHIPINFO ChipInfo,
  INT Adapter,
  INT Chip )
{
  USHORT i;
  PCHIPHEADER   pChipHdr = ChipInfo->pChipHdr;
  USHORT usMode;
  PSSVGADACINFO psSVGADacInfo;                                  /*          */

  /***  we don't support these hi-color modes when a Brooktree 485            */ /*            */
  /***  DAC is present, so don't put the entry in the PMI file                */
  /***  Note that this is only valid for 928 S3 boards              @V3.0YEE04*/

  psSVGADacInfo = &asSVGADacInfo [sDACINFO.DACFamily];            /*          */
  if (((ChipInfo->Int10Mode == VESA_800_600_64K) ||   /*800x600x64K           */
       (ChipInfo->Int10Mode == VESA_640_480_16M)) &&  /*640x480x16M           */
      (((Chip == S3_86C928_CHIP) &&                               /*@V3.0YEE04*/
        ((sDACINFO.DACFamily == BT485_DAC) ||       /*          *//*          */
         (sOEM.Manufacturer == NUMBER9_MANUFACTURER)))))         /*           */
    return (1);

  /*** We don't support AT&T DAC on number 9 in 640x480x64K                   */
  /*** and 800x600x64K. 800x600x64K is covered above.                         */

  if( (ChipInfo->Int10Mode == VESA_640_480_64K)                 /*          */
      && ((psSVGADacInfo->pszDacManufacturer == szATT)          /*          */
          || (psSVGADacInfo->pszDacManufacturer == szWinbond))  /*          */
      && ((sOEM.Manufacturer == NUMBER9_MANUFACTURER) &&        /*          */
          (Chip == S3_86C928_CHIP)))                            /*@V3.0YEE03*/
    return (1);

  /***  we won't support any hi-color/true color modes on the                 */
  /***  Winsprint 900 adapters because they use prototype 928                 */
  /***  chips and prototype BT485 DACs.  This was on recommendation           */
  /***  from Joanne at Artist Graphics.                                       */

  if ((pChipHdr->bBitsPerPixel > 8) &&
      (sOEM.Manufacturer == ARTIST_MANUFACTURER))               /*          */
     return (1);

  if (Adapter == TSENG_ADAPTER                                                     /*JWK08*/
      && !((sOEM.Manufacturer == DIAMOND_MANUFACTURER) && (Chip == TSENG_ET4000_CHIP))/*V2.2SENJA*/
      && (pChipHdr->bModeAttributes & GRAPHICS_MODEATTR)                           /*JWK08*/
      && (sAdapter.RefreshTable))                                  /*JWK10*/
  {
      if (TsengSetVerticalRefreshRate(pChipHdr->usXResolution, ChipInfo->Refresh, pChipHdr->bBitsPerPixel,TSENG_CHECK_LIMITS) == REFRESH_DISABLED)  /*JWK10 */
      {
          return(1);
      }
  }


  /*** If there is 1MB memory on the 864 adapter, generate                    */
  /*** 640x480x24bpp mode, using S3 mode 212 versus VESA mode 112             */
//           deleted
//if ((Adapter == S3_ADAPTER) &&                                  /*          */
//    (Chip == S3_86C864_CHIP) &&                                 /*          */
//    (sSVGA.Memory == 0x100000) &&                               /*          */
//    (ChipInfo->Int10Mode == VESA_640_480_16M))                  /*          */
//{                                                               /*          */
//   ChipInfo->Int10Mode = S3_640_480_24bpp;                      /*          */
//   pChipHdr->usVESAModeNumber = S3_640_480_24bpp;               /*          */
//   pChipHdr->ulPageLength = 92160;                              /*          */
//   pChipHdr->ulSaveSize = 92160;                                /*          */
//   pChipHdr->bBitsPerPixel = 24;                                /*          */
//}                                                               /*          */
  if (TSENGDiamondW32)
  {
    /*
    ** If Diamond Stealth, don't use VESA modes                     
    ** Limit 16bpp & 24bpp refresh to 60.
    ** Don't support 24bpp > 640 if not 1702 dac, since
    ** we can't program the clock with the common code.
    */
    if ((pChipHdr->bBitsPerPixel == 24) && (pChipHdr->usXResolution > 720) &&
       (sDACINFO.DACFamily == SGS1700_DAC))
       return 1;

    pChipHdr->usVESAModeNumber = 0x0;                         /*            */

    if(pChipHdr->bBitsPerPixel > 8)                              /*          */
    {                                                            /*          */
      if (ChipInfo->Refresh > 60)                                 /*          */
        return (1);                                               /*          */
      else                                                        /*          */
        SetVideoMode(TEXTMODE, 0, 0, 0);                          /*          */
    }                                                            /*          */
  }


  /* Since internal display does not support high res */        /*          */
  /* Mode information for it might not be right! */             /*          */
  /* Also it might auto switch display to external only! */     /*          */
  /* Like Toshiba T4600C!                                */     /*          */
  /* Fail mode if not settable on internal panel                  @V3.0YEE07*/

  if (sOEM.Manufacturer == THINKPAD_MANUFACTURER)
  {
     if (((CRTRegData [0x32] & 0x30) != 0x20) &&  /* Internal */
         (pChipHdr->usXResolution > ThinkpadMaxLCDRes()))
       return( 1 );
  }
  else
    if( (sSVGA.AdapterType == WESTERNDIG_ADAPTER)                 /*          */
        && ((sSVGA.ChipType == WESTERNDIG_WD9024_CHIP)            /*          */
            || (sSVGA.ChipType == WESTERNDIG_WD9026_CHIP)         /*          */
            || (sSVGA.ChipType == WESTERNDIG_WD9027_CHIP))        /*          */
        && ((CRTRegData [0x32] & 0x30) != 0x20)     /* Internal *//*          */
        && ( (((CRTRegData [0x33] & 0x90) == 0x10) &&   /*1280 LCD  @V3.0YEE07*/
              (pChipHdr->usXResolution > 1280)) ||                /*@V3.0YEE07*/
             (((CRTRegData [0x33] & 0x90) == 0x80) &&   /*1024 LCD  @V3.0YEE07*/
              (pChipHdr->usXResolution > 1024)) ||                /*@V3.0YEE07*/
             (((CRTRegData [0x33] & 0x90) == 0x90) &&   /*800 LCD   @V3.0YEE07*/
              (pChipHdr->usXResolution > 800)) ||                 /*@V3.0YEE07*/
             (((CRTRegData [0x33] & 0x90) == 0x00) &&   /*640 LCD   @V3.0YEE07*/
              (pChipHdr->usXResolution > 720)) ))     /* @V3.0YEE07           */
      return( 1 );                                                /*          */

  /* The Chrontel DACs are identified but 1280x1024 and */      /*          */
  /* HI-COLOR modes are not supported.  Disable generation. */  /*          */
                                                                /*          */
  if( (psSVGADacInfo->pszDacManufacturer == szChrontel)         /*          */
      && ((pChipHdr->usXResolution >= 1280)                     /*          */
          || (pChipHdr->bBitsPerPixel > 8)) )                   /*          */
    return( 1 );                                                /*          */

  /*
  ** Try the VESA mode number (if any) first.
  ** If the VESA mode number fails,
  ** then try the private number.
  */

  usMode = (pChipHdr->usVESAModeNumber                          /*          */
            ? pChipHdr->usVESAModeNumber                        /*          */
            : ChipInfo->Int10Mode);                             /*          */
  if( SetVideoMode( usMode,                                     /*          */
                    Adapter,
//                              pChipHdr->usBytesPerScanLine,
                    ((pChipHdr->bModeAttributes & GRAPHICS_MODEATTR) ?
                      (pChipHdr->usXResolution/8) :     /*            */
                      pChipHdr->usBytesPerScanLine),
                    pChipHdr->bBitsPerPixel) )                  /*          */
    /* Remember what worked for PMI file info */                /*          */
    ChipInfo->Int10Mode = usMode;                               /*          */
  else
    if( (usMode == ChipInfo->Int10Mode)                         /*          */
        || !SetVideoMode( ChipInfo->Int10Mode,                  /*          */
                          Adapter,                              /*          */
//                        pChipHdr->usBytesPerScanLine,
                    ((pChipHdr->bModeAttributes & GRAPHICS_MODEATTR) ?
                      (pChipHdr->usXResolution/8) :     /*            */
                      pChipHdr->usBytesPerScanLine),
                          pChipHdr->bBitsPerPixel) )            /*          */
      return( 1 );

  if (Adapter == TSENG_ADAPTER                                  /*JWK10*/
      && (!((sOEM.Manufacturer == DIAMOND_MANUFACTURER) && (Chip == TSENG_ET4000_CHIP)))
      && (ChipInfo->Refresh)
      && (ChipInfo->Refresh != TSENG_REFRESH_UNKNOWN) /*JWK26*/
      && (ChipInfo->Refresh != TSENG_REFRESH_ANY)     /*JWK26*/
      && (sAdapter.RefreshTable)
      && (pChipHdr->bModeAttributes & GRAPHICS_MODEATTR))       /*JWK26*/
  {
      if (TsengGetVerticalRefreshRate(pChipHdr->usXResolution,0) != ChipInfo->Refresh)  /*JWK10 Tseng may have reduced */
      {                                                                               /* due to hardware limitations */
          return (1);  /* fail if required refresh rate not set */
      }
  }

                                                /* unlock registers         */
  LockPushState( Adapter,                                       /*          */
                 Chip,                                          /*          */
                 aulRelockInfo );                               /*          */
                                                /* read Misc Output Reg     */
  MiscOutRegData = InpDelay( MISCOUTPUTREG_READ );              /*          */
                                                /* read the registers       */
  for( i = 0;
       ChipInfo->pRegData [i].Command != PMICMD_NONE;
       i++ )
    ModifyCmd( ChipInfo->pChipHdr,                              /*          */
               &ChipInfo->pRegData [i] );                       /*          */
                                       /* re-enable video     */
  InpDelay( INPSTATUSREG1 );           /* set flip-flop       *//*          */
  OutpDelay( ATC_INDEXPORT,                                     /*          */
             0x20 );                   /* video on            *//*          */

  LockPopState( Adapter,                                        /*          */
                Chip,                                           /*          */
                aulRelockInfo );                                /*          */
  return (0);

}

/*****************************************************************************
 *
 * FUNCTION NAME = GetInterlaceMode()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0 = interlaced
 *                 1 = non-interlaced
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

USHORT GetInterlaceMode(INT Adapter, INT Chip)
{
  switch (Adapter)
  {
    case VIDEO7_ADAPTER :
      return ((SEQRegData[0xE0]&0x01) ? INTERLACED : NONINTERLACED);

    case TRIDENT_ADAPTER:
      return ((CRTRegData[0x1E]&0x04) ? INTERLACED : NONINTERLACED);

    case TSENG_ADAPTER:
      return ((CRTRegData[0x35]&0x80) ? INTERLACED : NONINTERLACED);

    case WESTERNDIG_ADAPTER:
      return ((CRTRegData[0x2D]&0x20) ? INTERLACED : NONINTERLACED);

    case ATI_ADAPTER:
      return ((ATIRegData[0xBE]&0x02) ? INTERLACED : NONINTERLACED);

    case IBM_ADAPTER:
      return INTERLACED;

    case CIRRUS_ADAPTER:
      return ((CRTRegData[0x1A]&0x01) ? INTERLACED : NONINTERLACED);

    case S3_ADAPTER:
      return ((CRTRegData[0x42]&0x20) ? INTERLACED : NONINTERLACED);

    case DEFAULT_ADAPTER:
      return (INTERLACED);

    default:
      return (INTERLACED);
  }
}

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

VOID PostProcessModeSet(
  INT Adapter,
  INT Chip,
  PCHIPINFO ChipInfo )                                          /*          */
{
  INT i;
  BYTE bSaveReg;                                                /*          */
  PCHIPHEADER   pChipHdr = ChipInfo->pChipHdr;

  SEQRegData [0x00] = 0x00;  /* force sequencer into reset state            */
  CRTRegData [0x03] |= 0x80; /* this bit normally reserved and must be set  */
  CRTRegData [0x0b] &= ~ 0xe0; /* zero out any cursor skew                  */
  MiscOutRegMask = MiscOutRegData;                              /*          */

  usInterlaceMode = GetInterlaceMode(Adapter, Chip);  /*           V2.2SEN02*/

  switch (Adapter)
  {
    case  ATI_ADAPTER :                                         /*          */
      MiscRegData [0x42] &= ~ 0x0010;   /* Disable mem bndry */ /*          */
      break;                                                    /*          */
    case  CIRRUS_ADAPTER :              /*             */  /*            */
      if (!(GDCRegData[6] & 0x01))      /* If a text mode, reset SRF bit5 and */
      {                                 /* set bit6 to ensure proper font loading */
        SEQRegData [0x0f] &= ~ 0x20;
        SEQRegData [0x0f] |= 0x40;
      }
      if (sSVGA.Memory > 0x100000)      /* more than 1MB VRAM *//*          */
        SEQRegData[0xF] |= 0x80;        /* enable rest of VRAM*//*          */
      break;
    case  IBM_ADAPTER :               /* @            */
      for( i = 0;
           ChipInfo->pRegData[i].Command != PMICMD_NONE;        /*          */
           i++ )
      {

        if ((ChipInfo->pRegData[i].R.PortIO.IndexPort&0xff00) == XGAOPMODE_WRITE)
        {
          /* This really just sets the bit patterns in the 0x0070 position */
          ChipInfo->pRegData[i].R.PortIO.IndexPort |=           /*          */
            XGAInstance;                                        /*          */
          /* ChipInfo->pRegData[i].R.PortIO.IndexPort &= 0x000f;/*          */
          /* ChipInfo->pRegData[i].R.PortIO.IndexPort += XGAInstance;       */

          if( (ChipInfo->pRegData[i].R.PortIO.DataPort & 0xff00)
              == XGAOPMODE_WRITE )
          {
            ChipInfo->pRegData[i].R.PortIO.DataPort |=          /*          */
              XGAInstance;                                      /*          */
            /* ChipInfo->pRegData[i].R.PortIO.DataPort &= 0x000f;/*          */
            /* ChipInfo->pRegData[i].R.PortIO.DataPort += XGAInstance;      */
          }
        }
      }
      /*
      **            If a graphics mode, do post processing
      */
      if (GDCRegData[6] & 0x01)
      {
        CRTRegData[17] = 0x2c;          /* IBMSVGA specific reg values */
        CRTRegData[3]  = 0x02;
        CRTRegData[20] = 0xc0;
      }
      break;
    case  S3_ADAPTER :                  /*             */
      /* Set 64K aperture address to a0000 since it is not always
      ** set by the hardware.                                                    
      ** GIFTEST needs linear addressing bit turned on.  However,                
      ** Lacuna BIOS may intialize it as off, so be aware for lacuna!!           */  /* V2.1CTW01 */
      CRTRegData[0x58] &= 0xFC;         /* set 64K aperture                      */

      if ((ChipInfo->Int10Mode == VESA_1280_1024_256) &&             /*          */
          (sDACINFO.DACFamily == BT485_DAC))      /*          *//*          */
        CRTRegData[0x58] |= 0x10;       /* make sure linear addr on              */

      CRTRegData[0x59] = 0x00;          /* set 64K aperture=a0000                */
      CRTRegData[0x5A] = 0x0a;          /* set 64K aperture=a0000                */

      /* Disable Brooktree hardware cursor for hi-color modes *//*          */
      if ((sDACINFO.DACFamily == BT485_DAC)      /*           *//*          */
          && ( Chip == S3_86C928_CHIP)                          /* @V3.0YEE04*/
          && ((pChipHdr->bBitsPerPixel > 8)
              || (ChipInfo->Int10Mode == VESA_1280_1024_256)))  /*          */
        CRTRegData[0x45] |= 0x20;                               /*          */

      /*
      ** Note on logical line length:
      ** Linear access logical line length is controlled by CRT 13.
      ** Engine access logical line length is controlled by CRT 50, bits 6,5
      ** We will leave CRT 13 as the BIOS setss it to be the same as
      ** horizontal for dumb frame buffer protect mode apps.
      ** We will set the accelerated length to 1024 for the PM driver, which
      ** then will have to explicitelly modify the linear access one if
      ** needed.                                Senja
      ** Note on linear addressing:
      ** Linear addressing should be left enabled. Most apps are to be assumed
      ** as dumb-frame ones, requiring direct linear access to the VRAM.
      ** Apps which are using the accelerator are to disable the linear addressing
      ** explicitelly before performing the pixel transfer ops.
      ** Chips older than 928 have a silicon bug: if linear addressing left enabled
      ** while engine in use, FIFO's are not available. If linear access performed
      ** with addressing disabled, image appears jaggy.
      */
      CRTRegData[0x40] |= 0x01;        /* enable enhanced register access  */
      CRTRegData[0x51] &= 0xCF;        /* reset extended log line len bits */
      CRTRegData[0x43] &= 0xFB;        /* reset extended log line len bits */

      switch (ChipInfo->Int10Mode)
      {
        case 0x101:
          CRTRegData[0x13] = 0x50;     /* use 640 logical line linear     */
          CRTRegData[0x50] &= 0x3F;    /* use 1024 logical line acceler   */
          break;
        case 0x103:
          CRTRegData[0x13] = 0x64;     /* use 800 logical line linear     */
          CRTRegData[0x50] &= 0x3F;    /* use 1024 logical line acceler   */
          break;
        case VESA_1280_1024_256:       /* case 107                        */
          CRTRegData[0x13] = 0xa0;     /* use 1280 packed pixel           */
          CRTRegData[0x51] &= 0x8F;    /* disable split transfers         */
          CRTRegData[0x50] &= 0x0F;    /* use 1280 logical line accel     */
          CRTRegData[0x50] |= 0xC0;    /* use 1280 logical line accel     */
          break;
        case VESA_640_480_64K:         /* case 111                         */
          CRTRegData[0x13] =  0xA0;    /* use 2*640 logical line linear    */
          CRTRegData[0x50] &= 0x0F;    /* use 640 pix logical line accel*/
          CRTRegData[0x50] |= 0x50;    /* 2 bytes per pixel                */
          break;
        case VESA_800_600_64K:         /* case 114                         */
        case BTS3_800_600_64K:         /* S3 with BT485                    */
          CRTRegData[0x13] =  0xC8;    /* use 2*800 logical line linear    */
          CRTRegData[0x50] &= 0x0F;    /* use 800 pixels logical line accel*/
          CRTRegData[0x50] |= 0x90;    /* 2 bytes per pixel                */
          break;
        case VESA_1024_768_64K:        /* case 117                         */
          CRTRegData[0x13] =  0x00;    /* 2*1024 logical line linear       */
          CRTRegData[0x51] |= 0x10;    /* 2*1024 logical line linear       */
          CRTRegData[0x50] &= 0x0F;    /* use 1024 pixels logical line acel*/
          CRTRegData[0x50] |= 0x10;    /* 2 bytes per pixel                */
          break;
        case VESA_640_480_16M:         /* case 112  logical line tweak     */
        case BTS3_640_480_16M:         /* S3 with BT485                    */
          CRTRegData[0x13] =  0x00;    /* 2*1024 logical line linear       */
          CRTRegData[0x51] |= 0x10;    /* 2*1024 logical line linear       */
          CRTRegData[0x50] &= 0x0F;    /* use 640 pixels logical line accel*/
          CRTRegData[0x50] |= 0x40;    /* 1byte  per pixel                 */
          break;
      }

      /**
       **   Set bits 0-6 of CR6C with the byte mode value so that            
       **   the S3 BIOS knows which video mode to hibernate/suspend
       **   Only done for Mach5 systems so we don't clobber this reg
       **   on other 864 BIOS.
       **/
      if (sOEM.ManufacturerData == Mach5)
      {
         if (ChipInfo->Int10Mode >= 0x100)
         {
           for (i = 0; i < (INT)NUM_S3ENTRIES; i++)   /* search thru table */
           {
              if (ChipInfo->Int10Mode == S3ModeTable[i].VesaMode)
              {
                 bSaveReg = S3ModeTable[i].NativeMode;
                 break;
              }
           }
         }
         else
           bSaveReg = (BYTE)ChipInfo->Int10Mode;

         CRTRegData[0x6C] &= 0x80;         /* don't touch bit 7 */
         CRTRegData[0x6C] |= bSaveReg;     /* set S3 byte mode value */
      }
      break;
    case  TRIDENT_ADAPTER :
      SEQRegData [0x00] = 0x01;                                 /*          */
      break;                                                    /*          */
    case  TSENG_ADAPTER :
      /* For HiColor modes: */                                  /*          */
      MiscOutRegMask = (BYTE) (MiscOutRegData & ~ 0x88);        /*          */
      if( Chip == TSENG_ET4000_CHIP )                           /*          */
      {
        /*           
        ** If this is not the Orchid MC adapter, don't process the MC regs.
        */
        if (sOEM.Manufacturer != ORCHID_MANUFACTURER)           /*          */
          for( i = 0;
               ChipInfo->pRegData[i].Command != PMICMD_NONE;    /*          */
               i++ )
            if ((ChipInfo->pRegData[i].R.PortIO.IndexPort == MC_POS3REG) ||
                (ChipInfo->pRegData[i].R.PortIO.IndexPort == MC_SETUPREG))
              ChipInfo->pRegData[i].Command = PMICMD_NONE;
        else                                          /*            */
        {
          /*
          ** Modify the POS commands,
          ** Slot number needs to be writen to 96h
          ** Read 103 and use it as the OR mask for rmwbi(103):
          ** clock bits. rmwbi used in case that some of the bits
          ** need to be masked out.
          */
          MiscRegData [0x00] = (BYTE)(sOEM.ManufacturerData | 0x08);
          /*
          ** Select the slot and read the POS3
          */
          bSaveReg = InpDelay( MC_SETUPREG );                   /*          */
          OutpDelay( MC_SETUPREG,                               /*          */
                     MiscRegData [0x00] );
          MiscRegData [0x01] = InpDelay( MC_POS3REG );          /*          */
          OutpDelay( MC_SETUPREG,                               /*          */
                     bSaveReg );                                /*          */
        }
        if ((pChipHdr->bBitsPerPixel > 8) &&
            (sDACINFO.DACFamily == SC15025_DAC))                /*          */
          SEQRegData[0x07] &= 0xBF;  /* force mclk/2 for hicolor modes on Orchid */
      }
      else   /* not et4000 JWK06 */
      {
        if( Chip >= TSENG_ET4000W32_CHIP )      /* if accellerator */
        {

        /* JWK06
        **
        ** we must present a consistant video memory mapping and accelerator
        ** enable/disable strategy to apps.  Some BIOS's use different strategies,
        ** some dont set the accellerator registers at all, as a mode set does
        ** NOT REALLY imply enabling or disabling the accelerator. Apps are free
        ** to set these values to something else after a mode set, we just
        ** always want to start at the same place.
        **
        ** we will do the following ....
        **
        ** ALWAYS disable linear addressing mode, we do not support this addressing method
        ** ALWAYS unlock DAC and CRTC0-7,35
        **
        ** if text mode,  disable accelerator, set Video mapping to B8000
        **
        ** if Graphics mode,
        **       if 16 colors (vga), disable accelerator, set Video Mapping to A000
        **       if >=256 colors (svga), enable acellerator, set Acellerator mapping to B8000
        **                                                   set Video Mapping to A0000
        */

            CRTRegData[0x36] &= ~0x10;    /* ALWAYS disable system linear map */
            CRTRegData[0x11] &= ~0x80;    /* ALWAYS turn off CRTC protection bit */
            ATCRegData[0x16] &= ~0x03;    /* ALWAYS turn off DAC protection bits */

            if (pChipHdr->bModeAttributes & GRAPHICS_MODEATTR) /* if graphics */
            {
                if ((pChipHdr->bBitsPerPixel == 24)  /* svga graphics 16m 640x480 */
          //JWK28  && ( (ChipInfo->Int10Mode == 0x2e) || (ChipInfo->Int10Mode == 112) ))               //JWK28 is 0x112
                   && ( (ChipInfo->Int10Mode == 0x2e) || (ChipInfo->Int10Mode == VESA_640_480_16M) ))  //JWK28
                {
                    CRTRegData[0x13] =   0xf0;    /* make sure set to 240 */
                    CRTRegData[0x3f] &= ~0x80;    /* fix for genoa to run in dos */
                }

                if ((pChipHdr->bBitsPerPixel == 24)  /* svga graphics 16m 800x600 */       /*JWK28*/
                   && ( (ChipInfo->Int10Mode == 0x30) || (ChipInfo->Int10Mode == VESA_800_600_16M) ))
                {
                    CRTRegData[0x13] =   0x2c;    /* make sure set to 300 */
                    CRTRegData[0x3f] |=  0x80;    /* fix for genoa to run in dos */
                }

                if (pChipHdr->bBitsPerPixel > 4)  /* svga graphics */
                {
                    CRTRegData[0x36] |=  0x28;    /* enable  accellerator*/
                    GDCRegData[0x06] &= ~0x0c;    /* set SVGA A000  clear 3:2 */
                    GDCRegData[0x06] |=  0x04;    /* set SVGA A000  set 3:2 -> 01  */
                }
                else                              /* vga graphics */
                {
                    CRTRegData[0x36] &= ~0x28;    /* disable  accellerator*/
                    GDCRegData[0x06] &= ~0x0c;    /* set SVGA A000  clear 3:2 */
                    GDCRegData[0x06] |=  0x04;    /* set SVGA A000  set 3:2 -> 01  */
                }
            }
            else                              /* text mode */
            {
                CRTRegData[0x36] &= ~0x28;    /* disable  accellerator*/
              //GDCRegData[0x06] &= ~0x0c;    /* set VGA B8000  clear 3:2 */
                GDCRegData[0x06] |=  0x0c;    /* set VGA B8000  set 3:2 -> 11  */
            }

            GetTSENGBaseMMIO();

          //if (TSENGEMRBase) sAdapter.ulMMIOBaseAddress = TSENGEMRBase;
            if (TSENGVGABase) ChipInfo->pChipHdr->ulBufferAddress = TSENGVGABase;

          //if (TSENGMMUBase) ChipInfo->pChipHdr->ulBufferAddress = TSENGMMUBase;
          //if (TSENGMMUApertureSize) ChipInfo->pChipHdr->ulApertureSize = TSENGMMUApertureSize;

        }
      }
      break;
    case  VIDEO7_ADAPTER :
      switch (Chip)
      {
        case  VIDEO7_HT205_CHIP :
        case  VIDEO7_HT208_CHIP :
        case  VIDEO7_HT209_CHIP :
          if( !(GDCRegData [0x06] & 0x01) /* if its text mode               */
              && (SEQRegData [0x01] & 0x01))
          {                            /* 8-dot wide clocks                 */
            SEQRegData[0xfd] = 0x02;   /* always 2 for text                 */
          }
          break;
      }
      break;
    case  WEITEK_ADAPTER :
      if (sOEM.Manufacturer == DIAMOND_MANUFACTURER)            /*          */
      {
        SEQRegData[0x12] &= 0xC;
        if (pChipHdr->bBitsPerPixel <= 4)                       /*          */
          SEQRegData[0x12] = VIPER_VGAENABLE;     //enable VGA
        else                    //disable VGA and map the MMIO
        {
          ULONG Xbytes;
          SEQRegData[0x12] = VIPER_MMIO_ADDR_BITS | VIPER_VGADISABLE;
          /* setup all the immediate data for sysconfig and wmin.max */
          Xbytes = pChipHdr->usXResolution*(pChipHdr->bBitsPerPixel>>3);
          Viper.Clip = Xbytes<<16 | (sAdapter.ulTotalMemory >> Xbytes);
          if (pChipHdr->bBitsPerPixel == 8)
          {
            if (pChipHdr->usXResolution == 640)
            {
              Viper.SysConfig = 0x563000;
            }
            else if (pChipHdr->usXResolution == 800)
            {
              Viper.SysConfig = 0x587000;
            }
            else if (pChipHdr->usXResolution == 1024)
            {
              Viper.SysConfig = 0x603000;
            }
            else
            {
              Viper.SysConfig = 0x683000;
            }
          }
          else if (pChipHdr->bBitsPerPixel == 16)
          {
            if (pChipHdr->usXResolution == 640)
            {
              Viper.SysConfig = 0x683000;
            }
            else if (pChipHdr->usXResolution == 800)
            {
              Viper.SysConfig = 0x6ab000;
            }
            else if (pChipHdr->usXResolution == 1024)
            {
              Viper.SysConfig = 0x703000;
            }
          }else if (pChipHdr->bBitsPerPixel == 24)
          {
            if (pChipHdr->usXResolution == 640)
            {
              Viper.SysConfig = 0x7a3000;
            }
            else if (pChipHdr->usXResolution == 800)
            {
              Viper.SysConfig = 0x7cf000;
            }
          }
        }
      }
      break;
    case WESTERNDIG_ADAPTER :
      /* Force 25Mhz clock for 1st MiscOut entry  */            /*          */
      /* which is set correctly at end of setmode */            /*          */
      MiscOutRegMask = (BYTE) (MiscOutRegData & ~ 0x0c);        /*          */
      /* Prevent read/write offset enable as default for mode *//*@V3.0MNH01*/
      SEQRegData [0x11] &= ~ 0x80;                              /*@V3.0MNH01*/
      /* 132 text modes need VRAM in 8 bit mode */
      /* otherwise, the font may be corrupted at loading */
      /* Must be allowed for WD9031 & greater for other modes *//*          */
      /*!! Does this fix work at all? */                        /*          */
      if( (pChipHdr->usXResolution > 720)                       /*          */
          && !(GDCRegData [0x06] & 0x01) /* Text Mode */        /*          */
          && (Chip <= WESTERNDIG_WD9031_CHIP) )                 /*          */
      {
        GDCRegData [0x0b] &= ~ 0x04;
        /* On Westinghouse 90c11, Write buffer should */        /*          */
        /* Write buffer should be disabled 3c5,11(2). */        /*          */
        /* Causes font corruption in 132 modes */               /*          */
        if( Chip == WESTERNDIG_WD9011_CHIP )                    /*          */
          SEQRegData [0x11] &= ~ 0x04;                          /*          */
      }
      if( (Chip == WESTERNDIG_WD9024_CHIP)                      /*          */
          || (Chip == WESTERNDIG_WD9026_CHIP)                   /*          */
          || (Chip == WESTERNDIG_WD9027_CHIP) )                 /*          */
        if( pChipHdr->usXResolution <= 720 )                    /*          */
          /* Force external like clocking */                    /*          */
          SEQRegData [0x31] |= 0x08;                            /*          */
      if( Chip >= WESTERNDIG_WD9031_CHIP )                      /*          */
        /* Force memory organization */                         /*          */
        /* So PM driver "has enough memory" for 640x480 */      /*          */
        /* Otherwise int/ext/sim hot keys may chg it! */        /*          */
        /* Except that dual panel 16-bit */                     /*          */
        /* STNs (Super Twisted Nematic) must be */              /*          */
        /* only 1/2M organization in order to function at all *//*          */
        /* But do not limit for external only (non-STN) modes *//*          */
        if( pChipHdr->usXResolution <= 720 )                    /*          */
        {                                                       /*          */
          GDCRegData [0x0b] |= 0x80;    /* 1/2 M+ */            /*          */
          if( ((sSVGA.ChipType == WESTERNDIG_WD9024_CHIP)       /*          */
               || (sSVGA.ChipType == WESTERNDIG_WD9026_CHIP)    /*          */
               || (sSVGA.ChipType == WESTERNDIG_WD9027_CHIP))   /*          */
              && ((CRTRegData [0x33] & 0x60) == 0x60) )/* STN *//*          */
            GDCRegData [0x0b] &= ~ 0x40;/* 1/2 M EXACTLY */     /*          */
        }                                                       /*          */
        else                                                    /*          */
          GDCRegData [0x0b] |= 0xc0;    /* 1M+ */               /*          */

      /* Turn hardware cursor on (off screen) */                /*          */
      /* Except on mono panels where it does not work right */  /*          */
      /* Except on 800x600 flat panel where it doesn't work right @V3.0YEE07*/
      /* at 640x480 or text modes                                 @V3.0YEE07*/
      MiscRegData [2*0x20 + 0x00] = 0x00; /* Low byte */        /*          */
      MiscRegData [2*0x20 + 0x01] =       /* High byte */       /*          */
        ((((Chip == WESTERNDIG_WD9024_CHIP)                     /*          */
           || (Chip == WESTERNDIG_WD9026_CHIP)                  /*          */
           || (Chip == WESTERNDIG_WD9027_CHIP))                 /*          */
          && (!(CRTRegData [0x3e] & 0x20) || /* mono */         /*          */
              ((ThinkpadMaxLCDRes() == 800) && /* 800x600 panel   @V3.0YEE07*/
               (!(pChipHdr->bModeAttributes & GRAPHICS_MODEATTR) || /*@V3.0YEE07*/
                (pChipHdr->usXResolution == 640)))))            /*@V3.0YEE07*/
         ? (BYTE) 0x02                                          /*          */
         : (BYTE) 0x0a);                                        /*          */
      /* Only 16 bit pathway for WD C33 */                      /*          */
      MiscRegData [2*0x50 + 0x00] &= ~ 0x08; /* Low byte */     /*          */
      MiscRegData [2*0x52 + 0x00] &= ~ 0x08; /* Low byte */     /*          */
//    if( (Chip == WESTERNDIG_WD9024_CHIP)                      /*@V3.0MNH01*/
//        || (Chip == WESTERNDIG_WD9026_CHIP)                   /*@V3.0MNH01*/
//        || (Chip == WESTERNDIG_WD9027_CHIP) )                 /*@V3.0MNH01*/
//      CRTRegData [0x30] =             /* Enable LP counter  *//*@V3.0MNH01*/
//        (((CRTRegData [0x33] & 0x60) == 0x60) /*Dual 16b STN*//*@V3.0MNH01*/
//         ? (BYTE) 0x40                                        /*@V3.0MNH01*/
//         : (BYTE) 0x00);                                      /*@V3.0MNH01*/
      break;
  }
}

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

VOID FixInstance(INT Adapter,INT Chip,PCHIPINFO ChipInfo)
{
  INT i;
  PREGDATA pCleanData = NULL;



  switch (Adapter)
  {
    case  TSENG_ADAPTER :


      if ( sAdapter.usBusType != MCA_BUS)    /* was check if not orchid */
      {
          for (i = 0; ChipInfo->pRegData[i].Command != PMICMD_NONE; i++)
          {
              if ((ChipInfo->pRegData[i].R.PortIO.IndexPort == MC_POS3REG)
                   || (ChipInfo->pRegData[i].R.PortIO.IndexPort == MC_SETUPREG))
              {
                  ChipInfo->pRegData[i].Command = PMICMD_NONE;
              }
          }
      }

      switch (Chip)
      {
        case TSENG_ET3000_CHIP :
        case TSENG_ET4000_CHIP :
          break;


        default:                         /*jwk05*/
        case TSENG_ET4000W32_CHIP :
        case TSENG_ET4000W32I_CHIP :
        case TSENG_ET4000W32IB_CHIP :
        case TSENG_ET4000W32IC_CHIP :
        case TSENG_ET4000W32PA_CHIP :
        case TSENG_ET4000W32PB_CHIP :
        case TSENG_ET4000W32PC_CHIP :
        case TSENG_ET4000W32ID_CHIP :                           /*          */
        case TSENG_ET4000W32PD_CHIP :                           /*          */
        case TSENG_ET4000W32PX_CHIP :   /*JWK23*/
          for( i = 0;
               ChipInfo->pRegData[i].Command != PMICMD_NONE;    /*          */
               i++)
          {
            if ( (ChipInfo->pRegData[i].R.PortIO.IndexPort == TSENG_BASE_INDEX))
               ChipInfo->pRegData[i].R.PortIO.IndexPort |= (TSENGInstance << 4);
            if ( (ChipInfo->pRegData[i].R.PortIO.DataPort == TSENG_BASE_DATA))
               ChipInfo->pRegData[i].R.PortIO.DataPort |= (TSENGInstance << 4);
          }

          if (pCleanData = FindCleanupData( Adapter, Chip ))
          {
              while( pCleanData->Command != PMICMD_NONE )
              {
                  if (pCleanData->R.RMW.IndPort == TSENG_BASE_INDEX)
                      pCleanData->R.RMW.IndPort |= (TSENGInstance << 4);

                  if (pCleanData->R.RMW.DPort == TSENG_BASE_DATA)
                      pCleanData->R.RMW.DPort |= (TSENGInstance << 4);

                  pCleanData++;
              }
          }
          break;
      }
  }
}

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

VOID GenerateCleanup(
  INT Adapter,
  INT Chip,
  PCHIPHEADER pChipHdr )                                        /*          */
{
  PREGDATA pCleanData;                                          /*          */

  pCleanData = FindCleanupData( Adapter, Chip );                /*          */
  switch (Adapter)
  {
    case  ATI_ADAPTER :
      if (Chip == ATI_18800_CHIP)                               /*          */
        while( pCleanData->Command != PMICMD_NONE )             /*          */
        {                                                       /*          */
          if( (pCleanData->R.PortIO.IndexPort == ATI_INDEXPORT) /*          */
              && (pCleanData->R.PortIO.StartIndex == 0xb0) )    /*          */
            pCleanData->R.RMW.ANDMask = 0xc1;                   /*          */
          pCleanData++;                                         /*          */
        }                                                       /*          */
      break;                                                    /*          */
    case IBM_ADAPTER:
      while( pCleanData->Command != PMICMD_NONE )               /*          */
      {
        pCleanData->R.RMW.IndPort |= XGAInstance;               /*          */
        pCleanData->R.RMW.DPort  |= XGAInstance;                /*          */
        pCleanData++;
      }
      break;
    case CIRRUS_ADAPTER:
    case S3_ADAPTER:
    case TRIDENT_ADAPTER:
    case TSENG_ADAPTER:
    case VIDEO7_ADAPTER:
    case WESTERNDIG_ADAPTER:
      break;                                                    /*          */
  }
  SetVideoMode(TEXTMODE, 0, 0, 0);                              /*          */
  LockPushState( Adapter,                                       /*          */
                 Chip,                                          /*          */
                 aulRelockInfo );                               /*          */
  pCleanData = FindCleanupData( Adapter, Chip );                /*          */
  if( pCleanData )                                              /*          */
    for( ;                                                      /*          */
         pCleanData->Command != PMICMD_NONE;                    /*          */
         pCleanData++ )                                         /*          */
      ModifyCmd( pChipHdr,                                      /*          */
                 pCleanData );                                  /*          */
  pCleanData = FindCleanupData( Adapter, Chip );                /*          */
  switch (Adapter)                                              /*          */
  {
    case CIRRUS_ADAPTER:
    case IBM_ADAPTER:
    case S3_ADAPTER:
    case TRIDENT_ADAPTER:
    case TSENG_ADAPTER:
    case VIDEO7_ADAPTER:
    default:                                                    /*          */
      break;                                                    /*          */
    case WESTERNDIG_ADAPTER:                                    /*          */
      if( Chip >= WESTERNDIG_WD9031_CHIP )                      /*          */
        /* Force 1M(+) memory organization */                   /*          */
        /* So PM driver "has enough memory" for 640x480 */      /*          */
        /* Otherwise int/ext/sim hot keys may chg it! */        /*          */
        /* Except that dual panel 16-bit */                     /*          */
        /* STNs (Super Twisted Nematic) must be */              /*          */
        /* only 1/2M organization in order to function at all *//*          */
        /* But do not limit for external only (non-STN) modes *//*          */
        if( pChipHdr->usXResolution <= 720 )                    /*          */
        {                                                       /*          */
          GDCRegData [0x0b] |= 0x80;    /* 1/2 M+ */            /*          */
          if( ((sSVGA.ChipType == WESTERNDIG_WD9024_CHIP)       /*          */
               || (sSVGA.ChipType == WESTERNDIG_WD9026_CHIP)    /*          */
               || (sSVGA.ChipType == WESTERNDIG_WD9027_CHIP))   /*          */
              && ((CRTRegData [0x33] & 0x60) == 0x60) )/* STN *//*          */
            GDCRegData [0x0b] &= ~ 0x40;/* 1/2 M EXACTLY */     /*          */
        }                                                       /*          */
        else                                                    /*          */
          GDCRegData [0x0b] |= 0xc0;    /* 1M+ */               /*          */
      /* Turn hardware cursor on (off screen) */                /*          */
      /* Except on mono panels where it does not work right */  /*          */
      /* Except on 800x600 flat panel where it doesn't work right @V3.0YEE07*/
      MiscRegData [2*0x20 + 0x00] = 0x00; /* Low byte */        /*          */
      MiscRegData [2*0x20 + 0x01] =       /* High byte */       /*          */
        ((((Chip == WESTERNDIG_WD9024_CHIP)                     /*          */
           || (Chip == WESTERNDIG_WD9026_CHIP)                  /*          */
           || (Chip == WESTERNDIG_WD9027_CHIP))                 /*          */
          && (!(CRTRegData [0x3e] & 0x20) || /* mono */         /*          */
              (ThinkpadMaxLCDRes() == 800))) /* 800x600 panel*/ /*@V3.0YEE07*/
         ? (BYTE) 0x02                                          /*          */
         : (BYTE) 0x0a);                                        /*          */
      /* Only 16 bit pathway for WD C33 */                      /*          */
      MiscRegData [2*0x50 + 0x00] &= ~ 0x08; /* Low byte */     /*          */
      MiscRegData [2*0x52 + 0x00] &= ~ 0x08; /* Low byte */     /*          */
//    if( (Chip == WESTERNDIG_WD9024_CHIP)                      /*@V3.0MNH01*/
//        || (Chip == WESTERNDIG_WD9026_CHIP)                   /*@V3.0MNH01*/
//        || (Chip == WESTERNDIG_WD9027_CHIP) )                 /*@V3.0MNH01*/
//      CRTRegData [0x30] =             /* Enable LP counter  *//*@V3.0MNH01*/
//        (((CRTRegData [0x33] & 0x60) == 0x60) /*Dual 16b STN*//*@V3.0MNH01*/
//         ? (BYTE) 0x40                                        /*@V3.0MNH01*/
//         : (BYTE) 0x00);                                      /*@V3.0MNH01*/
      break;                                                    /*          */
  }
  LockPopState( Adapter,                                        /*          */
                Chip,                                           /*          */
                aulRelockInfo );                                /*          */
}


//          
/****************************************************************************
 *
 *      A text screen is shown containing a table of display resolutions
 *      and refresh rates.
 *
 *      The user selects the required refresh rate which corresponds to
 *      the attached monitor.
 *
 *      TSENG_ADAPTERS:
 *      The actions required here are to set bits in the BIOS data
 *      area bytes at 40:88h and 89h
 *
 *      This forces subsequent mode sets to use the appropriate refresh rate.
 *      ie. the same response as typing VMODE <Key> (see Key below)
 *
 *
 *      Below a sample of something like the expected display...
 *
 *      HorzxVert@Ref  Key    OEM Horiz Freq*
 *      -------------------------------------
 *      640x480@60Hz   60HZ      31.5KHz
 *      640x480@72Hz   72HZ      37.8KHz
 *
 *      800x600@56Hz    35K      35.5KHz
 *      800x600@60Hz    38K      38.0KHz
 *      800x600@72Hz    48K      48.4KHz
 *
 *      1024x768@43Hz   45M      35.5KHz
 *      1024x768@60Hz   65M      49.0KHz
 *      1024x768@70Hz   72M      56.5KHz
 *
 *      Enter the desired mode key (60HZ,72HZ,35K,38K,48K,45M,65M,72M):
 *
 *                              Cirrus support
 *      A text screen is shown containing a table of monitor choices and
 *      and their refresh rates.
 *
 *      The user selects the required refresh rate which corresponds to
 *      the attached monitor.
 *
 *      The actions required here is to issue extended BIOS call AH=12, BL=2
 *      to set the monitor type. This facilitates proper refresh programming by the
 *      BIOS. If not done, VESA function 3 to query the current mode will also
 *      fail.
 *
 *      This forces subsequent mode sets to use the appropriate refresh rate.
 *      ie. the same response as typing VMODE <Key> (see Key below)
 *
 *
 *      Below a sample of something like the expected display...
 *
 *      Monitor type   Key       OEM Horiz Freq*
 *      -------------------------------------
 *      VGA             0        31.5KHz
 *      8514 compatible 1        31.5KHz - 35.5KHz(interlaced)
 *      SVGA compatible 2        31.5KHz - 35.1KHz
 *      Extended SVGA   3        31.5KHz - 35.5KHz
 *      Multifrequency  4        31.5KHz - 37.8KHz
 *      Extended multif 5        31.5KHz - 48.0KHz
 *      Super multif    6        31.5KHz - 56.0KHz
 *      Ext super multif 7       31.5KHz - 64.0KHz
 *
 *      Enter the desired monitor key (0,1,2,3,4,5,6,7):
 ****************************************************************************/

VOID    DisplayMonitors(INT Adapter)
{
  INT i, j;
  CHAR * * p;

  if (Adapter == TSENG_ADAPTER)
  {
    if (TSENGDiamondW32)
    {
      p = TsengMessageDiamondW32;
      j = usSizeTsengMessageDiamondW32;
    }
    else
    {
      p = TsengMessage;
      j = usSizeTsengMessage;
    }
  }
  else if (Adapter == CIRRUS_ADAPTER)
  {
    p = CirrusMessage;
    j = sizeof(CirrusMessage)/sizeof(CHAR *);
  }

  for (i=0; i<j; i++)
    printf("%s\n", p[i]);
}

VOID    DisplayChoices(INT Adapter, INT Resolution)
{

  if (Adapter == TSENG_ADAPTER)
  {
    printf("%s\n", TsengRefreshChoices[Resolution]);
  }

}

VOID    DisplayMonitorChoice(INT Adapter)
{

  if (Adapter == TSENG_ADAPTER)
  {
      if (TSENGDiamondW32)                                    /*JWK10*/
      {                                                       /*JWK10*/
          printf("%s\n", TsengMonitorChoices[2]);             /*JWK10*/
      }                                                       /*JWK10*/
      else
      {
          if (TSENGBIOSMonitorSupport)                        /*JWK08*/
          {                                                   /*JWK08*/
              printf("%s\n", TsengMonitorChoices[1]);         /*JWK08*/
          }                                                   /*JWK08*/
          else                                                /*JWK08*/
          {                                                   /*JWK08*/
              printf("%s\n", TsengMonitorChoices[0]);         /*JWK08*/
          }
      }
  }
}

/*****************************************************************************
 *
 * FUNCTION NAME = getmonitorindex()
 *
 * DESCRIPTION   = Display text file and get user response or return default.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

INT     getmonitorindex(INT Adapter)
{
  INT     i,inpvalue, rc = 0, inpvalid = 0;
  UINT    j;
  CHAR    inpstr[256];
  UCHAR   bTemp;
  USHORT  CableType;



  if (SetDefaultMonitor)                                //          
  {
      if (Adapter == TSENG_ADAPTER)
      {
          outp(0x3bf, 0x03);  /* unlock */
          outp(0x3b8, 0xa0);
          outp(0x3d8, 0xa0);

          CableType = TsengGetMonitorCableType();    /* translate monID bits to monitor type */

          if (TSENGDiamondW32)  /* we can assume better monitor than Value Point */  /*JWK10*/
          {                                                                          /*JWK10*/
              /* store the monitor type in CRTC31 */                                     /*JWK10*/
              outp(CRT_INDEXPORT, 0x31);                                               /*JWK10*/
              bTemp = (UCHAR)inp(CRT_DATAPORT);                                        /*JWK10*/
              bTemp &= ~0x0f;                                                          /*JWK10*/
              bTemp |=  ((CableType-1) & 0x0f);                        /*JWK10*/
              outp(CRT_DATAPORT, bTemp);                                               /*JWK10*/
          }                                                                          /*JWK10*/

          TSENGMonitorRefresh[0]=pMonitorTable[CableType].VRefr[MON_INDEX_640];         /*JWK10*/
          TSENGMonitorRefresh[1]=pMonitorTable[CableType].VRefr[MON_INDEX_800];         /*JWK10*/
          TSENGMonitorRefresh[2]=pMonitorTable[CableType].VRefr[MON_INDEX_1024];        /*JWK10*/
          TSENGMonitorRefresh[3]=pMonitorTable[CableType].VRefr[MON_INDEX_1280];        /*JWK10*/
          TSENGMonitorRefresh[4]=CableType; /*JWK10*/
          strcpy(pszMonitorBuffer,&pMonitorTable[TSENGMonitorRefresh[4]].name[0]);  /*JWK26*/

          /*JWK22  if new monitor selection allows, increase pmi refresh entries */

          for (i=0;i<4;i++)
          {
              if ( (TSENGMonitorRefresh[i] > TSENGMaxMonitorRefresh[i])
                && (TSENGMonitorRefresh[i] != REFRESH_DISABLED)
                && (TSENGMonitorRefresh[i] != NO_REFRESH) )
              {
                  TSENGMaxMonitorRefresh[i] = TSENGMonitorRefresh[i];
              }

          }

          return TRUE;         /* must be non-zero */
      }
      else if (Adapter == CIRRUS_ADAPTER)
         return DEFAULT_CIRRUS_MONITOR;
  }

  switch(Adapter)
  {
    case TSENG_ADAPTER:


          outp(0x3bf, 0x03);  /* unlock */
          outp(0x3b8, 0xa0);
          outp(0x3d8, 0xa0);
          CableType = TsengGetMonitorCableType();    /* translate monID bits to monitor type */

          while ( !inpvalid )
          {
              DisplayMonitors(Adapter);
              DisplayMonitorChoice(Adapter);

              if (gets(inpstr))
              {
                  strupr(inpstr);
                  for (j=1; !inpvalid && j<usSizeMonitorTable; j++)
                  {
                      if ( !strcmp(inpstr, pMonitorTable[j].name) )
                      {
                          inpvalid = TRUE;

                          if (TSENGDiamondW32)
                          {
                              /* save selection */
                              outp(CRT_INDEXPORT, 0x31);                                               /*JWK10*/
                              bTemp = (UCHAR)inp(CRT_DATAPORT);                                        /*JWK10*/
                              bTemp &= ~0x0f;                                                          /*JWK10*/
                              bTemp |=  ((j-1) & 0x0f);                        /*JWK10*/
                              outp(CRT_DATAPORT, bTemp);                                               /*JWK10*/
                          }
                      }
                  }
              }
          }
          j--; /* correct for post incr in for loop */  /*JWK08/
               /* j has offset to MONITOR choice */

          TSENGMonitorRefresh[4] = j;
          strcpy(pszMonitorBuffer,&pMonitorTable[TSENGMonitorRefresh[4]].name[0]);  /*JWK26*/

          if (!strcmp(inpstr, "CUSTOM"))
          {
          //JWK26 to allow any name, and any refresh rate
          //JWK26
          //JWK26    for (i=0,inpvalid=0;i<4;i++,inpvalid=0)  /* for each possible resolution */
          //JWK26    {
          //JWK26        while ( !inpvalid )
          //JWK26        {
          //JWK26
          //JWK26            DisplayMonitors(Adapter);
          //JWK26            DisplayChoices(Adapter,i);
          //JWK26
          //JWK26            if (gets(inpstr))
          //JWK26            {
          //JWK26                strupr(inpstr);
          //JWK26                for (j=0; !inpvalid && j<usSizeTSENGresponsedata; j++)
          //JWK26                {
          //JWK26                    if ( (TSENGresponsedata[j].TsengFrequency[i] != 0xff) && (!strcmp(inpstr, TSENGresponsedata[j].response))  )
          //JWK26                    {
          //JWK26                        inpvalid = TRUE;
          //JWK26                        TSENGMonitorRefresh[i] = TSENGresponsedata[j].frequency[i];
          //JWK26                        rc = TRUE;
          //JWK26                    }
          //JWK26                }
          //JWK26            }
          //JWK26        }
          //JWK26    }

              printf("\nEnter Monitor Name:\n");

              if (gets(inpstr))
              {
                  strcpy(pszMonitorBuffer,inpstr);  /*JWK26*/
              }

              for (i=0,inpvalid=0;i<4;i++,inpvalid=0)  /* for each possible resolution */
              {
                  while ( !inpvalid )
                  {
                      DisplayChoices(Adapter,i);

                      if (gets(inpstr))
                      {
                          strupr(inpstr);
                          if (!strcmp(inpstr, "NONE"))
                          {
                              inpvalid = TRUE;
                              TSENGMonitorRefresh[i] = REFRESH_DISABLED;
                              rc = TRUE;
                          }
                          else
                          {
                              inpvalue = atoi(inpstr);
                              if ( (inpvalue > 0) && (inpvalue <= 255) )
                              {
                                  inpvalid = TRUE;
                                  TSENGMonitorRefresh[i] = inpvalue;
                                  rc = TRUE;
                              }
                          }
                      }
                  }
              }
          }
          else
          {
              for (i=0;i<4;i++)
              {
                  TSENGMonitorRefresh[i] = pMonitorTable[j].VRefr[i];
              }
              rc = TRUE;
          }

          /*JWK22  if new monitor selection allows, increase pmi refresh entries */

          for (i=0;i<4;i++)
          {
              if ( (TSENGMonitorRefresh[i] > TSENGMaxMonitorRefresh[i])
                && (TSENGMonitorRefresh[i] != REFRESH_DISABLED)
                && (TSENGMonitorRefresh[i] != NO_REFRESH) )
              {
                  TSENGMaxMonitorRefresh[i] = TSENGMonitorRefresh[i];
              }

          }


      break;

    case CIRRUS_ADAPTER:

      while ( !inpvalid )
      {
          DisplayMonitors(Adapter);
          if (gets(inpstr))
          {
              strupr(inpstr);
              rc = atoi(inpstr);
              if ((rc >= 0) && (rc <= 7))
                inpvalid = 1;
          }
      }

      break;

  }
  return(rc);
}

/*****************************************************************************
 *
 * FUNCTION NAME = CrtlCHandler()
 *
 * DESCRIPTION   = Replacement Control-C and Control-Break handler.
 *                  Note: no function body is required.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/


VOID    _interrupt _far CrtlCHandler()
{
}

/*****************************************************************************
 *
 * FUNCTION NAME = SetupMonitor()
 *
 * DESCRIPTION   = This either displays monitor selection table or sets default
 *                 monitor for the adapter.
 *
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID    SetupMonitor(VOID)                                      /*          */
{
  INT     rc;
  static union REGS regs;               /* sw interrupt registers            */

                                        /* if unsupported adapter, return */
//JWK24   if( (sSVGA.AdapterType != TSENG_ADAPTER)
//JWK24     //JKW02 need on all chip types!!! || (sSVGA.ChipType != TSENG_ET4000_CHIP))               /*          */
//JWK24        && (sSVGA.AdapterType != CIRRUS_ADAPTER) )
//JWK24     return;
//JWK24
//JWK24  if( (sOEM.Manufacturer )                                       /*          */
//JWK24     && (!TSENGDiamondW32) )   /*JWK22*/
//JWK24   {
//JWK24     /*this here is generic support only*/                       /*          */
//JWK24     return;                                                     /*          */
//JWK24   }

//JWK24 allow STB if tseng & oem                              //JWK24
                                                              //JWK24
   switch (sSVGA.AdapterType)                                 //JWK24
   {                                                          //JWK24
       case TSENG_ADAPTER:                                    //JWK24
                                                              //JWK24
           if( (sOEM.Manufacturer)                            //JWK24
             && (!TSENGDiamondW32)                            //JWK24
             && (!strstr(sAdapter.szRevision, "STB")) )       //JWK24
           {                                                  //JWK24
               return;                                        //JWK24
           }                                                  //JWK24
                                                              //JWK24
       break;                                                 //JWK24
                                                              //JWK24
                                                              //JWK24
       case CIRRUS_ADAPTER:                                   //JWK24
                                                              //JWK24
           if(sOEM.Manufacturer)                              //JWK24
           {                                                  //JWK24
               return;                                        //JWK24
           }                                                  //JWK24
                                                              //JWK24
       break;                                                 //JWK24
                                                              //JWK24
       default:                                               //JWK24
           return;                                            //JWK24
       break;                                                 //JWK24
                                                              //JWK24
                                                              //JWK24
   }                                                          //JWK24
                                                              //JWK24
                                                              //JWK24


  _dos_setvect(0x1b, CrtlCHandler);        /* hook these to prevent    */
  _dos_setvect(0x23, CrtlCHandler);        /* breaking out             */


  /* set a starting point for the monitor type */
  if (rc = getmonitorindex(sSVGA.AdapterType))                  /*          */
  {                                        /* print text, get response */
    if (sSVGA.AdapterType == TSENG_ADAPTER)                     /*          */
    {
       /* may be reduced if unable to set requested rate, or disabled */
       //JWK10 will set before BIOS setmode call TSENGMonitorRefresh[0]=TsengSetVerticalRefreshRate(640,   TSENGMonitorRefresh[0], 0,2); /*JWK10*/
       //JWK10 will set before BIOS setmode call TSENGMonitorRefresh[1]=TsengSetVerticalRefreshRate(800,   TSENGMonitorRefresh[1], 0,2); /*JWK10*/
       //JWK10 will set before BIOS setmode call TSENGMonitorRefresh[2]=TsengSetVerticalRefreshRate(1024,  TSENGMonitorRefresh[2], 0,2); /*JWK10*/
       //JWK10 will set before BIOS setmode call TSENGMonitorRefresh[3]=TsengSetVerticalRefreshRate(1280,  TSENGMonitorRefresh[3], 0,2); /*JWK10*/

       TsengSetVerticalRefreshRate(640,   TSENGMonitorRefresh[0], 0, TSENG_FIND_CLOSEST); /*JWK26*/
       TsengSetVerticalRefreshRate(800,   TSENGMonitorRefresh[1], 0, TSENG_FIND_CLOSEST); /*JWK26*/
       TsengSetVerticalRefreshRate(1024,  TSENGMonitorRefresh[2], 0, TSENG_FIND_CLOSEST); /*JWK26*/
       TsengSetVerticalRefreshRate(1280,  TSENGMonitorRefresh[3], 0, TSENG_FIND_CLOSEST); /*JWK26*/
    }
    else if (sSVGA.AdapterType == CIRRUS_ADAPTER) /*          *//*          */
    {
      regs.h.ah = 0x12;
      regs.h.al = (BYTE) rc;
      regs.x.bx = 0x00A2;
      int86(VBIOS, &regs, &regs);    /* Set monitor type */
    }
  }
}
/*****************************************************************************
 *
 * FUNCTION NAME = SVGADacGetCmd()
 *
 * DESCRIPTION   = Gets DAC Cmd Register
 *
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BYTE SVGADacGetCmd( void )                                      /*          */
{
  BYTE bCmd;

  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS2Set,              /*          */
          aulScratchRegs );                                     /*          */
  DoCmds( aRegDataDacHiColorIPFSet,                             /*          */
          aulScratchRegs );                                     /*          */
  bCmd = InpDelay( DAC_PIXELMPORT );                            /*          */
  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS2Clear,            /*          */
          aulScratchRegs );                                     /*          */
  DoCmds( aRegDataDacHiColorIPFClear,                           /*          */
          aulScratchRegs );                                     /*          */
  return( bCmd );                                               /*          */
}
/*****************************************************************************
 *
 * FUNCTION NAME = SVGADacPutCmd()
 *
 * DESCRIPTION   = Puts DAC Cmd Register
 *
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID SVGADacPutCmd( BYTE bCmd )                                 /*          */
{
  DoCmds( aRegDataDacHiColorIPFSet,                             /*          */
          aulScratchRegs );                                     /*          */
  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS2Set,              /*          */
          aulScratchRegs );                                     /*          */
  OutpDelay( DAC_PIXELMPORT,                                    /*          */
             bCmd );
  DoCmds( aRegDataDacHiColorIPFClear,                           /*          */
          aulScratchRegs );                                     /*          */
  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS2Clear,            /*          */
          aulScratchRegs );                                     /*          */
}
/*            start */
/*****************************************************************************
 *
 * FUNCTION NAME = SVGADacIsBrooktree()                                     
 *
 * DESCRIPTION   = If Brooktree DAC identified, return TRUE.
 *                 This is specific for the BT485 RAMDAC used by S3
 *                 because in order to get to the DAC, specific
 *                 S3 registers must be manipulated.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 1
 * RETURN-ERROR  = 0
 *
 ****************************************************************************/

BYTE SVGADacIsBrooktree( VOID )                                 /*@V3.0YEE04*/
{
  BYTE bId;

  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS2Clear,            /*          */
          aulScratchRegs );                                     /*          */
  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS3Clear,            /*          */
          aulScratchRegs );                                     /*          */
  OutpDelay( DAC_PIXELMPORT,                                    /*          */
             0xff );
  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS3Set,              /*          */
          aulScratchRegs );                                     /*          */
  /*
  ** Read the ID
  */
  bId = InpDelay( DAC_PIXELMPORT );     /* get Status Reg ID */ /*          */
  DoCmds( psCurAdapterInfo->pRegDataSVGADacRS3Clear,            /*          */
          aulScratchRegs );                                     /*          */
  /*
  **  TI Viewpoint 3025 CLOCKDAC exists on S3 964.                @V3.0YEE04
  **  Accessing this DAC requires setting RS4 which is            @V3.0YEE04
  **  really turning off bit 5 of CR5C                            @V3.0YEE04
  */

  if ((sSVGA.ChipType == S3_86C964_CHIP) && (bId != 0xff))      /*@V3.0YEE04*/
  {                                                             /*@V3.0YEE04*/
     DoCmds(aRegDataS3DacRS2Set, aulScratchRegs);               /*@V3.0YEE04*/
     DoCmds(aRegDataS3DacRS4Set, aulScratchRegs);               /*@V3.0YEE04*/
     OutpDelay(DAC_PIXELMPORT, 0x3F);                           /*@V3.0YEE04*/
     bId = InpDelay(DAC_READPORT);      /* get Status Reg ID      @V3.0YEE04*/
     DoCmds(aRegDataS3DacRS4Clear, aulScratchRegs);             /*@V3.0YEE04*/
     DoCmds(aRegDataS3DacRS2Clear, aulScratchRegs);             /*@V3.0YEE04*/
     if (bId == 0x25)                                           /*@V3.0YEE04*/
       return (TI3025_DAC);             /* it's a TI3025 CLOCKDAC @V3.0YEE04*/
     else                                                       /*@V3.0YEE04*/
       return (BT485_DAC);              /* OK, it's Brooktree   /*@V3.0YEE04*/
  }
  else
  {
    if (bId != 0xff)                                            /*@V3.0YEE04*/
       return (BT485_DAC);              /* it's a BT 485 RAMDAC!! @V3.0YEE04*/
     else                                                       /*@V3.0YEE04*/
       return (DEFAULT_DAC);            /* default dac          /*@V3.0YEE04*/
  }
}
/*****************************************************************************
 *
 * FUNCTION NAME = SVGADacIsATT()                                           
 *
 * DESCRIPTION   = Differentiate between AT&T and Winbond
 *                 by writing all 24 bits to the palette and reading them
 *                 back.  Winbond does not support this mode.
 *                 Choose index 3F in the palette which represents white
 *                 for less visual effect when writing 24 bits.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 1 = AT&T
 * RETURN-       = 0 = Winbond
 *
 ****************************************************************************/

BOOL SVGADacIsATT( VOID )
{
  BYTE bPalette;
  USHORT i;
  BYTE saveRGB [3];
  BYTE bCmd;

  /***  save current palette values at 3F  **/
  OutpDelay( DAC_READPORT,                                      /*          */
             0x3f );
  for( i = 0;
       i < 3;
       i++)
    saveRGB [i] = InpDelay( DAC_DATAPORT );                     /*          */
  bCmd = SVGADacGetCmd();               /* current DAC value*/  /*          */

  SVGADacPutCmd( 0x02 );                /* set 8-bit output */  /*          */

  /***  write 24 bits to palette  **/
  OutpDelay( DAC_WRITEPORT,                                     /*          */
             0x3f );                    /* set index 3f in palette  */
  for( i = 0;
       i < 3;
       i++)
    OutpDelay( DAC_DATAPORT,                                    /*          */
               0xff );                  /* write ff     */

  /***  read back palette  **/
  bPalette = 0xff;
  OutpDelay( DAC_READPORT,                                      /*          */
             0x3f );                    /* set index 3f in palette  */
  for( i = 0;
       i < 3;
       i++)
    bPalette &= InpDelay( DAC_DATAPORT );                       /*          */

  SVGADacPutCmd( bCmd );                /* restore DAC Cmd */   /*          */

  /***  restore palette  **/
  OutpDelay( DAC_WRITEPORT,                                     /*          */
             0x3f );                    /* set index 3f in palette  */
  for( i = 0;
       i < 3;
       i++)
    OutpDelay( DAC_DATAPORT,                                    /*          */
               saveRGB [i] );           /* restore to 3f*/
  return( (BOOL) (bPalette == 0xff) );  /* it's AT&T                */
}

/*****************************************************************************
 *
 * FUNCTION NAME = SVGADacGetHighColorType()
 *
 * DESCRIPTION   = Identifies DAC and returns one of the following:
 *                    0  Unsupported DAC
 *                    1  Generic 44 pin DAC
 *                    2  Brooktree 485
 *                    3  Brooktree 485 (used by Viper)
 *                    4  Sierra
 *                    5  AT&T
 *                    6  Music
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0-5 Supported DAC
 *
 ****************************************************************************/

INT SVGADacGetHiColorType( VOID )
{
  USHORT i;
  BYTE bId;                                                     /*          */
  BYTE bCmd;                                                    /*          */
  INT iDacIndex;                                                /*          */
  BOOL fIPFCycles;                                              /*          */
  UCHAR x, x1;                                                  /*@V3.0YEE04*/

  /* this is for those S3 805/928 boards that are used with the   @V3.0YEE04*/
  /* S3 GENDAC which is programmed like SDAC used on 864          @V3.0YEE04*/
  if ((sSVGA.AdapterType == S3_ADAPTER) &&
      (sSVGA.ChipType <= S3_86C928_CHIP))
  {
    DoCmds(aRegDataS3DacSetCR55, aulScratchRegs);

    /*
    ** Read the ID
    */
    outp(DAC_READPORT,0x07);                                                /* set index = 7              */

    x  = (UCHAR) inp(DAC_DATAPORT);                                 /* read M value               */
    x1 = (UCHAR) inp(DAC_DATAPORT);                    /* read N1 & N2 value         */

    DoCmds(aRegDataS3DacResetCR55, aulScratchRegs);

    if ((x == 0x71) && ( x1 == 0x29))
    {
     /*
     ** Read command register 4 times
     */
     for(i=0;i<4;i++) x = (UCHAR) inp(DAC_PIXELMPORT);
     if ( x != 0x70)
       return( S3SDAC_DAC );           /* it's S3 SDAC   */
    }
  }                                    /* @V3.0YEE04     */

  /*!!This routine should restore the state! */                 /*          */
  /*!!In particular the index registers! */                     /*          */
  SVGADacPutCmd( 0x00 );                                        /*          */
  OutpDelay( DAC_PIXELMPORT,                                    /*          */
             0xff );                                            /*          */
  DoCmds( aRegDataDacHiColorIPFClear,                           /*          */
          aulScratchRegs );                                     /*          */
  /* Note the id is the 4th time here, not the 5th! */
  for( i = 0;
       i < 4;
       i++ )
    bId = InpDelay( DAC_PIXELMPORT );                           /*          */
  if( bId == 0x44 )                                             /*          */
    return( MU9C9910_DAC );                                     /*          */
  else if( bId == 0x70 )                                        /*          */
    return( S3SDAC_DAC );           /* it's S3 SDAC   */        /*          */
  else if( bId == 0x73 )                                        /*@V3.0YEE02*/
    return( S3SDAC_DAC );           /* it's S3 SDAC   */        /*@V3.0YEE02*/
  else if( bId == 0x82 )                                        /*          */
    return( MU9C4910_DAC );                                     /*          */
  else if( bId == 0x88 )                                        /*          */
    return( MU9C4870_DAC );                                     /*          */
  else if( bId == 0x8E )
    return( MU9C1880_DAC );         /* also Diamond SS2410 */   /*          */
  else if( bId == 0xb1 )                                        /*          */
    return( ICS5342_DAC );          /* it's ICS5342   */        /*          */
  else if( bId == 0xb3 )                                        /*          */
    return( CH8391_DAC );           /* Chrontel CH8391 */       /*          */

  /*
  ** Read command register 2 more times
  */
  for( i = 0;
       i < 2;
       i++ )
    bId = InpDelay( DAC_PIXELMPORT );                           /*          */
  if( bId == 0x84 )                 /* ATT498/499/409 */        /*          */
  {
    if (InpDelay(DAC_PIXELMPORT) == 0x09)     /* device id reg    @V3.0YEE12*/
      return(ATT409_DAC);           /* it's AT&T 409  */        /*@V3.0YEE12*/
    return(ATT498_DAC);             /* it's AT&T      */        /*          */
  }

  /*
  ** Read command register 4 times
  */
  for( i = 0;                                                   /*          */
       i < 4;                                                   /*          */
       i++ )                                                    /*          */
    bId = InpDelay( DAC_PIXELMPORT );                           /*          */

  if( bId == 0xff )                 /* InMos IMSG173 */         /*          */
    return( IMSG173_DAC );          /*                     */   /*          */

  /* Test for IPF cycle vs. IPF unlock */                       /*          */
  /* Some IPFs stay on until an out or access to other addr   *//*          */
  /* Others cycle thru IPF off 4 times and on once            *//*          */
  DoCmds( aRegDataDacHiColorIPFClear,                           /*          */
          aulScratchRegs );                                     /*          */
  for( i = 0;                                                   /*          */
       i < 9;                                                   /*          */
       i++ )                                                    /*          */
    bId = InpDelay( DAC_PIXELMPORT );                           /*          */
  OutpDelay( DAC_PIXELMPORT, 0xff);                             /*          */
  DoCmds( aRegDataDacHiColorIPFClear,                           /*          */
          aulScratchRegs );                                     /*          */
  for( i = 0;                                                   /*          */
       i < 9;                                                   /*          */
       i++ )                                                    /*          */
    bId = InpDelay( DAC_PIXELMPORT );                           /*          */
  bId = InpDelay( DAC_PIXELMPORT );                             /*          */
  fIPFCycles = bId                                              /*          */
               && (bId == SVGADacGetCmd());                     /*          */

  /*
  ** Looking for Sierra 15025
  */
  bCmd = SVGADacGetCmd();                                       /*          */
  SVGADacPutCmd( (BYTE) (bCmd | 0x10) );                        /*          */
  OutpDelay( DAC_READPORT,                                      /*          */
             0x09 );                /* read special register  */
  bId = InpDelay( DAC_WRITEPORT );                              /*          */

  iDacIndex = HICOLOR_DAC;          /* In case not set        *//*          */
  if( bId == 0x53 )                 /* it's Sierra            */
    iDacIndex = SC15025_DAC;                                    /*          */
  else
  {
    /* Test for SGS Thomson: */                                 /*          */
    SVGADacPutCmd( 0x10 );                                      /*          */
    /* Do not set RS2, just set IPF */                          /*          */
    DoCmds( aRegDataDacHiColorIPFSet,                           /*          */
            aulScratchRegs );                                   /*          */
    InpDelay( DAC_PIXELMPORT );     /* Skip command */          /*          */
    OutpDelay( DAC_PIXELMPORT,                                  /*          */
               0x00 );              /* Index low */             /*          */
    OutpDelay( DAC_PIXELMPORT,                                  /*          */
               0x00 );              /* Index high */            /*          */
    bId = InpDelay( DAC_PIXELMPORT );                           /*          */
    if( bId == 0x44 )               /* SGS Thomson! */          /*          */
    {                                                           /*          */
      bId = InpDelay( DAC_PIXELMPORT );                         /*          */
      switch( bId )                                             /*          */
      {                                                         /*          */
        case 0x00:                                              /*          */
        default:                                                /*          */
          iDacIndex = SGS1700_DAC;                              /*          */
          break;                                                /*          */
        case 0x02:                                              /*          */
          iDacIndex = SGS1702_DAC;                              /*          */
          break;                                                /*          */
        case 0x03:                                              /*          */
          /* Documentation for SGS1705 says it returns 0x03!? *//*          */
          iDacIndex = SGS1703_DAC;                              /*          */
          break;                                                /*          */
      } /* endswitch */                                         /*          */
    }                                                           /*          */
    else                                /* NOT SGS Thomson */   /*          */
    {
      SVGADacPutCmd( 0xe0 );                                    /*          */
      if( SVGADacGetCmd() == 0xe0 )                             /*          */
      {
        SVGADacPutCmd( 0x60 );
        if( SVGADacGetCmd() == 0x00 )   /* Instead of 0x60 */   /*          */
        {                                                       /*          */
          SVGADacPutCmd( 0x02 );                                /*          */
          if( SVGADacGetCmd() == 0x02 )                         /*          */
            /* !fIPFCycles */                                   /*          */
            iDacIndex = ATT490_DAC;
          else                                                  /*          */
            iDacIndex = ATT493_DAC;                             /*          */
        }                                                       /*          */
        else                            /* ATT491/Winbond     *//*          */
        {                                                       /*          */
          if( SVGADacIsATT() )          /*                    *//*          */
            iDacIndex = ATT491_DAC;     /* it's AT&T          *//*          */
          else                                                  /*          */
            if( fIPFCycles )                                    /*          */
//            iDacIndex = ATT492_DAC;                           /*          */
//            /* ATT492 gets here! */   /* ATT                *//*          */
//            /* W82C490 gets here! */  /* Winbond            *//*          */
              iDacIndex = HICOLOR_DAC;  /* generic            *//*          */
            else                                                /*          */
              /* SC11483 gets here! */  /* Sierra             *//*          */
              iDacIndex = HICOLOR_DAC;  /* generic            *//*          */
        }                                                       /*          */
      }                                                         /*          */
      else                                                      /*          */
        iDacIndex = ATT497_DAC;                                 /*          */
    }                                                           /*          */
  }                                                             /*          */
  return( iDacIndex );                                          /*          */
}

/*****************************************************************************
 *
 * FUNCTION NAME = SVGADacGetType()
 *
 * DESCRIPTION   = Identifies DAC and returns one of the following:
 *                    0  Unsupported DAC
 *                    1  Generic 44 pin DAC
 *                    2  Brooktree 485
 *                    3  Brooktree 485 (used by Viper)
 *                    4  Sierra
 *                    5  AT&T
 *                    6  Music
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0-5 Supported DAC
 *
 ****************************************************************************/

INT SVGADacGetType( VOID )                                      /*          */
{
  BYTE bPixelMask, bNewPixelMask;
  BYTE bCmd, bNewCmd;
  BYTE bId;                                                     /*          */
  BYTE bAccess;                                                 /*          */
  INT iDacIndex;

  /* First get current values to save */                        /*          */
  DoCmds( aRegDataDacHiColorIPFClear,                           /*          */
          aulScratchRegs );                                     /*          */
  bPixelMask = InpDelay( DAC_PIXELMPORT );                      /*          */
  /* If no Hi Color DAC then bCmd == bPixelMask! */
  bCmd = SVGADacGetCmd();
  SVGADacPutCmd( 0x00 );

  /*JWK12  mask off two low order bits of the command register
  **       setting these bits on Music 9910 put it into a dormant state (power management bits),
  **       turning off the clock and allowing the DRAM to go to mush.
  **       Symptom: font trashed (sometimes)
  */

  /* Now do usual test */                                       /*          */
  SVGADacPutCmd( (BYTE) (~bPixelMask & 0xfc) );                 /*JWK12*/
  bNewPixelMask = InpDelay( DAC_PIXELMPORT );                   /*          */
  /* Now see if at least some command bits change: */
  SVGADacPutCmd( (BYTE) (~bCmd & 0xfc) );                       /*JWK12*/
  bNewCmd = SVGADacGetCmd();                                    /*JWK12*/

  iDacIndex = (((bNewPixelMask == bPixelMask)
                && (bNewCmd != bCmd))   /* Have Hi-COLOR DAC */
               ? SVGADacGetHiColorType()
               : DEFAULT_DAC );         /* Just std VGA DAC */

  /* Special MUSIC     check */                                 /*          */
  /* Note the id is the 5th time here, not the 4th! */          /*          */
  /* some MUSIC 1880's (and possibly other MUSIC DAC's) */      /*          */
  /* have an IPF counter that does NOT work as documented. */   /*          */
  /* Cycle is normally 5 long, but doing an IN 3C8 */           /*          */
  /* causes the first one afterwards to stretch to 6! */        /*          */
  /* This also means it needs different programming */          /*          */
  if( iDacIndex == DEFAULT_DAC )                                /*          */
  {                                                             /*          */
    /* Guarantee pixel mask not equal to expected id */         /*          */
    DoCmds( aRegDataDacHiColorIPFClear,                         /*          */
            aulScratchRegs );                                   /*          */
    OutpDelay( DAC_PIXELMPORT,                                  /*          */
               0xff );                                          /*          */
    DoCmds( aRegDataDacHiColorIPFClear,                         /*          */
            aulScratchRegs );                                   /*          */
    bId = 0xff;                                                 /*          */
    for( bAccess = 0;                                           /*          */
         (bAccess < 5) && (bId == 0xff);                        /*          */
         bAccess++ )                                            /*          */
      bId = InpDelay( DAC_PIXELMPORT );                         /*          */
    if( (bAccess == 5)                                          /*          */
        && ((bId == 0x8E )                                      /*          */
            || (bId == 0x82)                                    /*          */
            || (bId == 0x88)) )                                 /*          */
    {                                                           /*          */
      iDacIndex = MU9CBUG_DAC;                                  /*          */
      /* If found, return without restoring bCmd == bId!   */   /*          */
      /* Otherwise it ends up as the pixel mask!           */   /*          */
      bCmd = bPixelMask;                                        /*          */
    }                                                           /*          */
  }                                                             /*          */

  /* Restore original Hi Color DAC mask */
  SVGADacPutCmd( 0x00 );
  OutpDelay( DAC_PIXELMPORT,                                    /*          */
             bPixelMask );
  /* If no Hi Color DAC then restores Pixel Mask! */
  SVGADacPutCmd( bCmd );                /* Restore orig cmd */
  return( iDacIndex );
}

/*****************************************************************************
 *
 * FUNCTION NAME = CirrusDacGetType()
 *
 * DESCRIPTION   = Identifies DAC and returns one of the following:
 *                    0  Unsupported DAC
 *                    1  Generic 44 pin DAC
 *                    2  Brooktree 485
 *                    3  Brooktree 485 (used by Viper)
 *                    4  Sierra
 *                    5  AT&T
 *                    6  Music
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0-5 Supported DAC
 *
 ****************************************************************************/

INT CirrusDacGetType( VOID )                                    /*          */
{
  INT iDacIndex;                                                /*          */

  /* Tests same as Winbond! */                                  /*          */
//iDacIndex = SVGADacGetType();
//if( iDacIndex == HICOLOR_DAC )                                /*          */
//  /* All Cirrus VGAs have a TRUE-COLOR DAC built in! */       /*          */
    iDacIndex = CIRRUS_DAC;                                     /*          */
  return( iDacIndex );                                          /*          */
}

/*****************************************************************************
 *
 * FUNCTION NAME = S3DacGetType()
 *
 * DESCRIPTION   = Identifies DAC and returns one of the following:
 *
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0-5 Supported DAC
 *
 ****************************************************************************/

int S3DacGetType( void )                                        /*          */
{
  BYTE bId;                                                     /*@V3.0YEE04*/

  /*!! Should be same as SVGADacGetType */                      /*          */
  /*!! if it checked for Brooktree too */                       /*          */
  bId = SVGADacIsBrooktree();                                   /*          */
  if (bId == DEFAULT_DAC)                                       /*@V3.0YEE04*/
    return (SVGADacGetType());                                  /*@V3.0YEE04*/

  return(bId);                                                  /*@V3.0YEE04*/
}

/*****************************************************************************
 *
 * FUNCTION NAME = TsengDacGetType()
 *
 * DESCRIPTION   = Identifies DAC and returns one of the following:
 *                    0  Unsupported DAC
 *                    1  Generic 44 pin DAC
 *                    2  Brooktree 485
 *                    3  Brooktree 485 (used by Viper)
 *                    4  Sierra
 *                    5  AT&T
 *                    6  Music
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0-5 Supported DAC
 *
 ****************************************************************************/

INT TsengDacGetType( VOID )                                     /*          */
{
  INT iDacIndex=0;                                              /*          */
  static union REGS regs;

  /*******  (info from tseng)
  *;Get DAC type:
  *; [called via int 10 with AH=010, AL=0F1]
  *; ret AL=010, AH=0, BL=DAC type
  *; DAC types:
  *;  0=normal
  *;  1=Sierra SC11481,SC11486,SC11488
  *;  2=Sierra SC11485,SC11487,SC11489
  *;  3=AT&T ATT20C491,ATT20C490, Winbond W82C490
  *;  4=Cirrus CL-GD5200 [ACUMOS ADAC1]
  *;  5=Sierra SC15025,SC15026,SC15020,SC15021
  *;  6=INMOS IMS G173/4 (Rev C)
  *;  7=Music MU9C1880
  *;  8=Music MU9C4910,MU9C9910
  *;  9=Brooktree Bt481A
  *;  0A..n=other hicolor DAC types to be specified
  *; (types>=1 can do 5r/5g/5b fmt; types>=2 can do 5r/6g/5b fmt + single
  *;  edge clocking; types>=3 except 7 can do 8r/8g/8b fmt; types 5,7,9 can do
  *;  8b/8g/8r fmt)
  *; 16-bit DAC types:
  *;  20h=SGS-Thomson STG 1700
  *;  21h=Sierra SC15021
  *;  22h=AT&T ATT20C498
  *;  23h=ICS ICS5341
  *;  24h=SGS-Thomson STG 1702/1703
  *;  25h=Chrontel CH8398
  *;
  ********/


//JWK10 corrupts genoa screen  iDacIndex = SVGADacGetType();         /* default DAC test   *//*          */
  if( iDacIndex <= HICOLOR_DAC )                                /*          */
  {
    regs.x.ax = 0x10F1;                 /* getDAC type        */
    regs.x.bx = 0x0000;
    int86(0x10, &regs, &regs);
    if(regs.x.ax == 0x0010)
    {
      DoCmds( aRegDataDacHiColorIPFClear,                       /*          */
              aulScratchRegs );                                 /*          */
      /*!!Recode this switch as a table */                      /*          */
      switch (regs.h.bl)
      {
        case 0x03: /* ATT491_DAC */     /* default DAC test   *//*          */
        case 0x07: /* MU9C1880_DAC */   /* default DAC test   *//*          */
        case 0x08: /* MU9C4910_DAC */   /* default DAC test   *//*          */
        case 0x20: /* SGS1700_DAC */    /* default DAC test   *//*          */
        case 0x24: /* SGS1702_DAC */    /* default DAC test   *//*          */
        case 0x22: /* ATT498_DAC */     /* default DAC test   *//*          */
          break;
        case 0x01:
        case 0x02:
        case 0x05:
          return(SC15025_DAC);
        case 0x04:
          return(CIRRUS_DAC);
        case 0x06:
          return(IMSG173_DAC);
        case 0x09:
          return(BT481_DAC);                                    /*          */
        case 0x21:
          return(SC15025_DAC);
        case 0x23:
          return(ICS5341_DAC);
        case 0x25:
          return(CH8398_DAC);
      }
    }
  }
  /* if not identified, fall thru to other tests */
  return( SVGADacGetType() );           /* default DAC test */
}
                                                                /*          */
/*****************************************************************************
 *
 * FUNCTION NAME = WDDacGetType()
 *
 * DESCRIPTION   = Identifies DAC and returns one of the following:
 *                    0  Unsupported DAC
 *                    1  Generic 44 pin DAC
 *                    2  Brooktree 485
 *                    3  Brooktree 485 (used by Viper)
 *                    4  Sierra
 *                    5  AT&T
 *                    6  Music
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0-5 Supported DAC
 *
 ****************************************************************************/

INT WDDacGetType( VOID )                                        /*          */
{
  INT iDacIndex;

  iDacIndex = SVGADacGetType();
  if( ( iDacIndex == DEFAULT_DAC )
      && ( sSVGA.ChipType == WESTERNDIG_WD9024_CHIP ) )
    iDacIndex = WD90C24_DAC;
  return( iDacIndex );
}

/*****************************************************************************
 *
 * FUNCTION NAME = WeitekDacGetType()
 *
 * DESCRIPTION   = Identifies DAC and returns one of the following:
 *                    0  Unsupported DAC
 *                    1  Generic 44 pin DAC
 *                    2  Brooktree 485
 *                    3  Brooktree 485 (used by Viper)
 *                    4  Sierra
 *                    5  AT&T
 *                    6  Music
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0-5 Supported DAC
 *
 ****************************************************************************/

INT WeitekDacGetType( VOID )                                    /*          */
{
  /*!!Is this really a special DT DAC? */                       /*          */
  /*!!Or are we just trying to indicate that is accessed */     /*          */
  /*!!Through different ports than usual? */                    /*          */
  return( Weitek_BT485DAC );
}

/*****************************************************************************
 *
 * FUNCTION NAME = SVGAEditTables()
 *
 * DESCRIPTION   = Edits sATIAdapterInfo depending upon chiptype
 *                 Default routine for no editting
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 ****************************************************************************/

VOID SVGAEditTables( VOID )                                     /*          */
{
}

/*****************************************************************************
 *
 * FUNCTION NAME = IdentifyDAC()
 *
 * DESCRIPTION   = If the adapter supports a Hi-color mode, attempt to
 *                 identify the DAC. Fill the sDACINFO structure with the
 *                 identified DAC family and a specific chip type if needed.
 *                 A chip belongs to a family if it is programmed in the same
 *                 fashion as other chips in the family (but with different
 *                 values). Currently, there is not need for the specific chip
 *                 type, the field is for future expansion.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = VOID
 * RETURN-ERROR  = VOID
 *
 ****************************************************************************/

VOID IdentifyDAC(
  INT Adapter,
  INT Chip )                                                    /*          */
{
  USHORT i;                                                     /*          */
  USHORT Mode;
  BOOL HiColorSupported;                                        /*          */
  PSSVGADACINFO psSVGADacInfo;                                  /*          */

  HiColorSupported = FALSE;                                     /*          */
  if (!fVesaBIOS)               /* BIOS is not VESA compliant */
    switch(Adapter)
    {
      case TSENG_ADAPTER:                                       /*          */
        /* proprietary hi-color setmode */                      /*          */
        /* 640 x 480 x 64K              */                      /*          */
        HiColorSupported =                                      /*          */
          (BOOL) SetVideoMode( 0x2e,                            /*          */
                               Adapter,                         /*          */
                               80,                              /*          */
                               16 );                            /*          */
        break;

      default:
        break;
    }                                                           /*          */
  else
    for( i = 0;
         !HiColorSupported                                      /*          */
         && (Mode = pusSupportedModes [i])
         && (Mode != 0xffff);
         i++)
      if (((Mode >= VESA_640_480_32K)  &&
           (Mode <= VESA_1280_1024_64K)) ||                     /*          */
          (Mode == BTS3_800_600_64K)    ||                      /*          */
          (Mode == BTS3_640_480_16M))                           /*          */
      {
        /*
        ** Set the mode. If successful, try to identify the Hi-color DAC
        ** If not successful, try other Hi-Color modes listed.
        */
        HiColorSupported =                                      /*          */
          (BOOL) SetVideoMode( Mode,                            /*          */
                               Adapter,                         /*          */
                               80,      /* Dummy */             /*          */
                               16 );    /* Dummy */             /*          */
      }
//if (HiColorSupported)                                         /*          */
//{
    LockPushState( Adapter,                                     /*          */
                   Chip,                                        /*          */
                   aulRelockInfo );                             /*          */
    sDACINFO.DACFamily = psCurAdapterInfo->pifnSVGADacGetType();/*          */
    LockPopState( Adapter,                                      /*          */
                  Chip,                                         /*          */
                  aulRelockInfo );                              /*          */
    psSVGADacInfo = &asSVGADacInfo [sDACINFO.DACFamily];        /*          */
    strcpy( sAdapter.szDACString,                               /*          */
            psSVGADacInfo->pszDacName );                        /*          */
    strcat( sAdapter.szDACString,                               /*          */
            " " );                                              /*          */
    strcat( sAdapter.szDACString,                               /*          */
            psSVGADacInfo->pszDacManufacturer );                /*          */
//}
  SetVideoMode(TEXTMODE, 0, 0, 0);
}
/*            end */

/*****************************************************************************
 *
 * FUNCTION NAME = SetGetBankUpdate()
 *
 * DESCRIPTION   = Update the SetBank and GetBank commands in chipdata.c
 *                 based on the hardware information.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

INT SetGetBankUpdate(INT Adapter, INT Chip)  /*            */
{
  switch (Adapter) {
  case IBM_ADAPTER:
     IBMGetBankCmd[0].R.PortIO.IndexPort |= XGAInstance;
     IBMSetBankCmd[1].R.PortIO.IndexPort |= XGAInstance;
     break;
  case S3_ADAPTER:
     /*
      * Check if extended registers are used?
      */
     break;
  default:
     break;
  } /* endswitch */

  return (0);
}


/****************************************************************           
 *
 * FUNCTION NAME = WriteSetGetBank()
 *
 * DESCRIPTION   = Write the setbank and getbank routines to PMI file
 *
 * INPUT         = ChipInfo : array of mode information
 *                 usNumModes : number of modes
 * OUTPUT        = output the bank routines to PMI file
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

#define MAX_BANK_ROUTINES 10

VOID WriteSetGetBank(PCHIPINFO ChipInfo, INT Adapter, INT Chip)
{
   USHORT i, usModeNum, usNumBankRoutines;
   CHAR BankRoutineTable[MAX_BANK_ROUTINES][28];
   PREGDATA pCmd;
   BOOL fNew;

   SetGetBankUpdate (Adapter, Chip);

   /* set bank */
   usNumBankRoutines = 0;

   /* search the whole ChipInfo structure */
   for (usModeNum = 0; usModeNum < usNumModes; usModeNum++)
   {
      if (ChipInfo[usModeNum].pSetBank == NULL)
         continue;
      fNew = TRUE;

      /* search the table for printed routines */
      for (i = 0; i < usNumBankRoutines; ++i)

         /* bank routine has been printed? */
         if (!strcmp (ChipInfo[usModeNum].pSetBank->szBankRoutineName,
                                                  BankRoutineTable[i]))
         {
            fNew = FALSE;
            break;
         }

         if (fNew)
         {
           strcpy (BankRoutineTable[usNumBankRoutines++],
                   ChipInfo[usModeNum].pSetBank->szBankRoutineName);

           fprintf (textfile, "[%s]\n",
                          ChipInfo[usModeNum].pSetBank->szBankRoutineName);

           pCmd = ChipInfo[usModeNum].pSetBank->pBankRoutine;

           if (pCmd)
             while( pCmd->Command != PMICMD_NONE )
             {
               WriteCmd (pCmd);
               pCmd++;
             }
           fprintf(textfile, "\n");
         } /* if */

   } /* for ModeNum */

   /* get bank */
   usNumBankRoutines = 0;

   /* search the whole ChipInfo structure */
   for (usModeNum = 0; usModeNum < usNumModes; usModeNum++)
   {

      if (ChipInfo[usModeNum].pGetBank == NULL)
         continue;
      fNew = TRUE;

      /* search the table for printed routines */
      for (i = 0; i < usNumBankRoutines; ++i)

         /* bank routine has been printed? */
         if (!strcmp (ChipInfo[usModeNum].pGetBank->szBankRoutineName,
                                                  BankRoutineTable[i]))
         {
            fNew = FALSE;
            break;
         }

         if (fNew)
         {
            strcpy (BankRoutineTable[usNumBankRoutines++],
                    ChipInfo[usModeNum].pGetBank->szBankRoutineName);

            fprintf (textfile, "[%s]\n",
                           ChipInfo[usModeNum].pGetBank->szBankRoutineName);

            pCmd = ChipInfo[usModeNum].pGetBank->pBankRoutine;

            if (pCmd)
              while( pCmd->Command != PMICMD_NONE )
              {
                WriteCmd (pCmd);
                pCmd++;
              }
            fprintf(textfile, "\n");
         } /* if */

   } /* for ModeNum */


}

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

VOID WriteDeclarationSection(VOID)                              /*          */
{
  USHORT i;
  if (sAdapter.usSizeDeclarations)
  {
      fprintf(textfile, "[Declarations]\n\t");
      for (i=0;i<sAdapter.usSizeDeclarations;i++)
        fprintf(textfile, "\n\t%s =MMIO{0x%08lx}",sAdapter.pDecSection[i].RegisterName,
                          sAdapter.pDecSection[i].RegisterOffset);
      fprintf(textfile,"\n");
  }
  return;
}
/*****************************************************************************
 *
 * FUNCTION NAME = BiosSetMode()            @V3.0YEE02
 *
 * DESCRIPTION   = Call Bios to set the mode then print in PMI file.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0 if success
 * RETURN-ERROR  = 1 if failure
 *
 ****************************************************************************/

INT BiosSetMode(PCHIPINFO ChipInfo, INT Adapter, INT Chip )
{
  PCHIPHEADER   pChipHdr = ChipInfo->pChipHdr;
  USHORT j,k,RateIndex;

  if (!SetupHardware(ChipInfo, sSVGA.AdapterType, sSVGA.ChipType))
  {
     /* crowd pleaser and test of mode set */
     /* hey, we could adjust the monitor here too! */

     if (fDebug) ShowYourStuff( ChipInfo, sSVGA.AdapterType, sSVGA.ChipType); /*JWK10*/


     /* for tseng, keep track of successfull graphic setmodes */
     /* we only want to set a refresh rate 1 time */

     if ((sSVGA.AdapterType == TSENG_ADAPTER)                        /*JWK26*/
          && (pChipHdr->bModeAttributes & GRAPHICS_MODEATTR)         /*JWK26*/
          && (ChipInfo->Refresh) )                                   /*JWK26*/
     {                                                               /*JWK26*/

         switch(pChipHdr->usXResolution)                 /*JWK26*/
         {                                                           /*JWK26*/
              case 640:                                              /*JWK26*/
              default:
                        j=0;                                         /*JWK26*/
                                                                     /*JWK26*/
                        break;                                       /*JWK26*/
                                                                     /*JWK26*/
              case 800:                         /* 800x600 */        /*JWK26*/
                        j=1;                                         /*JWK26*/
                                                                     /*JWK26*/
                        break;                                       /*JWK26*/
                                                                     /*JWK26*/
              case 1024:                        /* 1024x768 */       /*JWK26*/
                        j=2;                                         /*JWK26*/
                                                                     /*JWK26*/
                        break;                                       /*JWK26*/
                                                                     /*JWK26*/
              case 1280:                        /* 1280x1024 */      /*JWK26*/
                        j=3;                                         /*JWK26*/
                                                                     /*JWK26*/
                        break;                                       /*JWK26*/
         }                                                           /*JWK26*/

         /*
         ** convert the refresh rate into an index
         ** we will use as index into other data as well
         **
         **      0=0
         **      1=43
         **      2=56
         **      3=60
         **      4=70
         **      5=72
         **      6=75
         **      7=90
         **      8=unknown
         */
                              /*JWK26*/
         switch(TsengGetVerticalRefreshRate(pChipHdr->usXResolution,0))                             /*JWK26*/
         {
               case 0:
                        RateIndex=0;

                break;

              case 43:
                        RateIndex=1;

                break;

              case 56:
                        RateIndex=2;

                break;

              case 60:
                        RateIndex=3;

                break;

              case 70:
                        RateIndex=4;

                break;

              case 72:
                        RateIndex=5;

                break;

              case 75:
                        RateIndex=6;

                break;

              case 90:
                        RateIndex=7;

                break;

              default:
                        RateIndex=8;

                break;


         }



         k = (pChipHdr->bBitsPerPixel)/8;            /*JWK26*/
                                                                 /*JWK26*/
         (TSENGRefreshFlags[j][k][RateIndex])++;
         (TSENGRefreshFlags[j][k][8])++;                         /* flag any */

     }

     PostProcessModeSet( sSVGA.AdapterType,
                         sSVGA.ChipType,
                         ChipInfo );                     /*          */
     WriteModeInfo(ChipInfo);    /* modeinfo section */  /*          */
     if (ChipInfo->pSetBank)
     {
       fprintf (textfile, "[SetBank]\n");  /* set/get banks routine names */
       fprintf (textfile, "%s\;\n\n", ChipInfo->pSetBank->szBankRoutineName);
     }
     if (ChipInfo->pGetBank)
     {
       fprintf (textfile, "[GetBank]\n");
       fprintf (textfile, "%s\;\n\n", ChipInfo->pGetBank->szBankRoutineName);
     }
     /* hardware setmode section */
     WriteSetMode( sSVGA.AdapterType,                      /*          */
                   sSVGA.ChipType,                         /*          */
//@V3.0YEE02       i,
                   ChipInfo );
//           WriteClockModeSection(i,sSVGA.AdapterType,sOEM);   /* clock setmode section            */
     if( !((sSVGA.AdapterType == WEITEK_ADAPTER)           /*          */
           && (pChipHdr->bBitsPerPixel >= 8)) )            /*          */
     {                                                     /*          */
       /*
       ** Re-enable the video, setmode is complete.
       */
       EmitCmd( PMICMD_INB,
                0x00,
                psCurAdapterInfo->                         /*          */
                  pusfnSVGAAdjustedPort( 0x3da ) );        /*          */
       EmitCmd( PMICMD_OUTB,
                0x00,
                psCurAdapterInfo->                         /*          */
                  pusfnSVGAAdjustedPort( 0x3c0 ),          /*          */
                0x20 );
       fprintf(textfile, "\n");
     }
     return (0);                         /* setmode OK */
  }
  return (1);                            /* setmode failed */
}
/*****************************************************************************
 *
 * FUNCTION NAME = ProcessChipset()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

INT ProcessChipset(OEMSVGAINFO sSVGA, BOOL fGeneric)
{
  USHORT i,j,usModeSet=0;                                       /*@V3.0YEE02*/
  PCHIPINFO ChipInfo = NULL;
  CHAR tmp_fname[_MAX_PATH];
  BYTE SaveCR5B, SaveCR52;                                      /*@V3.0YEE11*/

  /* moved IdentifyDAC routine because SetupChipInfo                        */
  /* needs DAC type for S3 864 refresh utility                              */
  /* Always try to ID the DAC */                                /*          */
  IdentifyDAC( sSVGA.AdapterType,
               sSVGA.ChipType );                                /*          */

  if ((sOEM.Manufacturer != NUMBER9_MANUFACTURER) &&            /*@V3.0YEE04*/
      ((sSVGA.AdapterType == S3_ADAPTER) &&                     /*          */
       (sSVGA.ChipType == S3_86C864_CHIP)))                     /*@V3.0YEE04*/
     sOEM.Manufacturer = S3_MANUFACTURER;                       /*          */

  if (ChipInfo = SetupChipInfo(sSVGA.AdapterType, sSVGA.ChipType, fGeneric))

    if ((sSVGA.AdapterType == IBM_ADAPTER) && !fVesaBIOS)
    {
       return ERROR_NUM_NEEDVESA;

    }
    else
    {
      /*
      ** Setup default monitor for the os2 configuration.
      ** Write the default into the video.cfg
      */
      if (DisplayMonitorTable || SetDefaultMonitor)
      {                                                         /*          */
        remove(VIDEOCFGFName);                                  /*          */
        SetupMonitor();
      }                                                         /*          */
      GetCurrentMonitorSelection( sSVGA.AdapterType,            /*          */
                    sSVGA.ChipType );                           /*          */

      /* Save refresh rates done after SetupMonitor to preserve new monitor settings on exit */   /*JWK26*/
      /* if monitor option was not selected, saves entry monitor settings */

      SaveEntryRefreshRates(sSVGA.AdapterType,sSVGA.ChipType);  /* JWK26 */


      strcpy(tmp_fname, PMIFName);
      *strrchr(tmp_fname, '.') = '\0';
      strcat(tmp_fname, ".tmp");

      textfile = fopen(tmp_fname, "w");

      /*
      ** Write PMI banner
      */
      WriteFileHeader();
      /* Identify adapter and chipset immediately */            /*          */
      /* Now BVH & VVID can use it for lock data&cleanup data *//*          */
      /*
      ** Write [Hardware] section
      */
      WriteHeader(ChipInfo->pChipHdr);             /* adapter, chipset */
      /*
      ** If memory mapped, write the register declaration part and
      ** determine the memory map address and any other adapter specifics.
      */
      WriteDeclarationSection();                                /*          */
      WriteLockData(sSVGA.AdapterType, sSVGA.ChipType);
      GenerateCleanup( sSVGA.AdapterType,
                       sSVGA.ChipType,
                       ChipInfo->pChipHdr );                    /*          */
      WriteCleanup(sSVGA.AdapterType,
                   sSVGA.ChipType,
                   ChipInfo->pChipHdr);                         /*          */
      fprintf( textfile,                                        /*          */
               "[ProgramDAC]\n" );                              /*          */
      WriteDACFunction();                                       /*          */
//           WriteClockFunction(sSVGA.AdapterType,sOEM);   /*                      */
      WriteSetGetBank(ChipInfo, sSVGA.AdapterType, sSVGA.ChipType);          /*            */
      ProcessTrapRegs(ChipInfo);       /* trapregs section */

      if (!GenerateRefresh)            /* @V3.0YEE02 */
      {
         Refresh[0] = 75;
         Refresh[1] = 75;
         Refresh[2] = 43;
      }

      for (i = 0; i < usNumModes; i++)
      {
        if ((ChipInfo[i].pChipHdr->ulSaveSize <=                /*          */ /*JWK10*/
                   sSVGA.Memory)                                /*          */
             && ((ChipInfo[i].pChipHdr->bBitsPerPixel <= 8)     /*          */
                 || (sDACINFO.DACFamily != DEFAULT_DAC)) )      /*          */
        {
          /* Setup default refresh values for 50Mhz which means:  @V3.0YEE02
          **          640x480 8bpp @ 75Hz
          **          800x600 8bpp @ 75Hz
          **         1024x640 8bpp @ 43Hz
          ** Right now only supported for S3864 & S3964
          */
//3.0YEE03   if ((sDACINFO.DACFamily == S3SDAC_DAC) &&
          if ((sSVGA.AdapterType == S3_ADAPTER) &&
              ((sSVGA.ChipType == S3_86C864_CHIP) ||
               (sSVGA.ChipType == S3_86C964_CHIP)) &&
              (ChipInfo[i].pChipHdr->bBitsPerPixel >= 8))
          {
             switch (ChipInfo[i].pChipHdr->usXResolution)
             {
                case 640:
                  MaxRefresh = Refresh [0];
                  break;
                case 800:
                  MaxRefresh = Refresh [1];
                  break;
                case 1024:
                  MaxRefresh = Refresh [2];
                  break;
                case 1280:
                  MaxRefresh = Refresh [3];
                  break;
                case 1600:
                  MaxRefresh = Refresh [4];
                  break;
             }

             if (MaxRefresh !=-1)             /* go ahead and generate mode */
             {
                /* for hi-color modes, 50MHz limits to 60Hz */
                if ((!GenerateRefresh) &&
                    (ChipInfo[i].pChipHdr->bBitsPerPixel > 8))
                   MaxRefresh = 60;

                for (j = 0; j<MAX_REFRESHTABLE_ENTRIES; j++)
                {
                  if ((ChipInfo[i].pChipHdr->usXResolution == sAdapter.RefreshDynamic[j].usXRes) &&
                      (sAdapter.RefreshDynamic[j].usVertRefresh <= MaxRefresh))
                  {
                     while (sAdapter.RefreshDynamic[j].usVertRefresh != -1)
                     {
                        MaxRefresh = sAdapter.RefreshDynamic[j].usVertRefresh;
                        LockPushState( sSVGA.AdapterType,
                                       sSVGA.ChipType,
                                       aulRelockInfo );
                        outp(CRT_INDEXPORT,0x5B);
                        SaveCR5B = (BYTE)inp(CRT_DATAPORT);  /* @V3.0YEE11 */
                        outp(CRT_DATAPORT, sAdapter.RefreshDynamic[j].CR5B);
                        outp(CRT_INDEXPORT,0x52);
                        SaveCR52 = (BYTE)inp(CRT_DATAPORT);  /* @V3.0YEE11 */
                        outp(CRT_DATAPORT, sAdapter.RefreshDynamic[j].CR52);
                        LockPopState(sSVGA.AdapterType,
                                     sSVGA.ChipType,
                                     aulRelockInfo );

                        BiosSetMode(&ChipInfo[i], sSVGA.AdapterType, sSVGA.ChipType);

                        /* restore CR52 and CR5B              @V3.0YEE11 */
                        LockPushState( sSVGA.AdapterType,
                                       sSVGA.ChipType,
                                       aulRelockInfo );
                        outp(CRT_INDEXPORT,0x5B);
                        outp(CRT_DATAPORT,SaveCR5B);
                        outp(CRT_INDEXPORT,0x52);
                        outp(CRT_DATAPORT,SaveCR52);
                        LockPopState(sSVGA.AdapterType,
                                     sSVGA.ChipType,
                                     aulRelockInfo );

                        j += 1;                /* go to next refresh entry  */
                     }                         /* endwhile VertRefresh != -1*/
                     break;
                  }
                }

                usModeSet++;
             }                                 /* end MaxRefresh != -1      */
          }                                    /* end S3 864 SDAC processing*/
          else
            if (!BiosSetMode(&ChipInfo[i], sSVGA.AdapterType, sSVGA.ChipType))/*@V3.0YEE02*/
              usModeSet++;
        }
      }
      fclose(textfile);

      RestoreEntryRefreshRates(sSVGA.AdapterType,sSVGA.ChipType);         /* JWK26 */

      if (usModeSet)
      {
        remove(PMIFName);
        rename(tmp_fname, PMIFName);
      }
      else
        remove(tmp_fname);

      /* Now cleanup SVGA registers in case BIOS does NOT! */   /*          */
      GenerateCleanup( sSVGA.AdapterType,                       /*          */
                       sSVGA.ChipType,                          /*          */
                       ChipInfo->pChipHdr );                    /*          */
      LockPushState( sSVGA.AdapterType,                         /*          */
                     sSVGA.ChipType,                            /*          */
                     aulRelockInfo );                           /*          */
      DoCmds( FindCleanupData( sSVGA.AdapterType,               /*          */
                               sSVGA.ChipType ),                /*          */
              aulScratchRegs );                                 /*          */
      LockPopState( sSVGA.AdapterType,                          /*          */
                    sSVGA.ChipType,                             /*          */
                    aulRelockInfo );                            /*          */
    }                                                           /*          */
  SetVideoMode(TEXTMODE, 0, 0, 0);

  if (!usModeSet)
    return ERROR_NUM_UNSUPPORTED;
  else
    return (0);
}

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

INT ParmType(CHAR *v)
{
  CHAR s[MAX_PARMLEN];

  if (!v)
    return (PARM_NONE);

  if (strlen(v) > MAX_PARMLEN-1)
    return (PARM_BAD);

  strcpy(s, v);
  strupr(s);

  if (!strcmp(s, PMI_DELETE))
    return (PARM_DELETE);
  else
    if (!strcmp(s, PMI_CREATE))
      return (PARM_CREATE);
    else
      if (!strcmp(s, PMI_STATUS))
        return (PARM_STATUS);
      else
        if (!strcmp(s, PMI_DOS))
          return (PARM_DOS);
        else
          if (!strcmp(s, PMI_INIT))
             return (PARM_INIT);
          else
            if (!strcmp(s, PMI_GENERIC))
               return (PARM_GENERIC);
            else
              if (!strcmp(s, PMI_MONITOR))                      /*          */
              {
                DisplayMonitorTable = 1;
                return (PARM_CREATE);
              }
              else
                if( !strcmp( s, PMI_INSTALL ) )                 /*          */
                  return( PARM_INSTALL );                       /*          */
                else                                            /*          */
                  if( !strcmp( s, PMI_DEBUG ) )                 /*          */
                    return( PARM_DEBUG );                       /*          */
                  else                                          /*@V3.0YEE02*/
                    if( !strcmp( s, PMI_REFRESH ) )             /*@V3.0YEE02*/
                      return( PARM_REFRESH );                   /*@V3.0YEE02*/
                  else                                          /*          */
                    return (PARM_BAD);
}

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

INT get_dos_version(VOID)
{
  INT version;
  /*!! This call does not work correctly */                     /*          */
  /*!! for MS-DOS versions below 5.0!    */                     /*          */
  /*!! for IBM DOS version 4.0 a 42=0x2a is returned */         /*          */
  _asm
  {
    mov ax, 3306h       ;get TRUE version
    int 21h             ;
    mov version, bx     ;BH = Minor version, BL = Major version
  }
  return (version&0xff);
}

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

CHAR GetBootDrive(VOID)
{
  CHAR drive;
  _asm
  {
    mov ax, 3305h       ;
    int 21h             ;
    add dl, 'a' - 1     ;
    mov drive, dl       ;
  }
  return (drive);
}

//          
/*****************************************************************************
 *
 * FUNCTION NAME = QueryAdapter()
 *
 * DESCRIPTION   = Calls SCREEN$ PDD to obtain OEM SVGA information. It sets global structure.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 1
 * RETURN-ERROR  = 0
 *
 ****************************************************************************/

USHORT QueryAdapter(OEMSVGAINFO * psSVGA)
{
  static union REGS regs;               /* sw interrupt registers            */
  static struct SREGS sregs;
  INT    hScreenHandle;
  unsigned OpenMode = O_RDONLY;
  OEMSVGAINFO  far *p = psSVGA;
  OEMINFO      far *p1= &sOEM;

  if (_dos_open(SCREENDD_NAME, OpenMode, &hScreenHandle))
     return 0;

  regs.x.ax = 0x440C;                                   //generic IOCTL
  regs.x.bx = hScreenHandle;                            //handle
  regs.x.cx = 0x8000|SCREENDD_SVGA_ID;                           //function and category
  regs.x.dx = OFFSETOF(p);
  sregs.ds =  SEGMENTOF(p);
  int86x(0x21, &regs, &regs, &sregs);
  if(regs.x.cflag & 0x1)
  {
     _dos_close(hScreenHandle);
     return 0;               //if carry flag set, IOCTL failed
  }
  else
  {
     /*
     ** Get Manufacturer info, if any.
     */
     regs.x.ax = 0x440C;                                   //generic IOCTL
     regs.x.bx = hScreenHandle;                            //handle
     regs.x.cx = 0x8000|SCREENDD_SVGA_OEM;                          //function and category
     regs.x.dx = OFFSETOF(p1);
     sregs.ds =  SEGMENTOF(p1);
     sOEM.OEMLength = 10;                                     // structure is 10 bytes long
     int86x(0x21, &regs, &regs, &sregs);                   //we don't care if this fails.
  }
  _dos_close(hScreenHandle);
  return(1);
}

/*****************************************************************************
 *
 * FUNCTION NAME = WriteVideoCFGFile()
 *
 * DESCRIPTION   = Create VIDEO.CFG file and format monitor name and mode caps.
 *
 * NOTE:        If file already exists, it is not created. If DisplayMonitorTable
 *              or SetDefaultMonitor parameters were issued, the file was already
 *              removed and new parameters setup.
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID  WriteVideoCFGFile(VOID)                                   /*          */
{
  CHAR szTempBuffer[256];
  CHAR szOEMString[128];
  CHAR *pTempBuffer = &szTempBuffer[0];                         /*          */
  CHAR *p;                                                      /*          */
  USHORT i = 0;

  if (!access(VIDEOCFGFName,0))
  {
    /*
    ** Open and read the file until Adapter section OEMString is loaded in.
    ** If it belongs to a different adapter, discard it. Else, return.
    */
    textfile = fopen(VIDEOCFGFName, "r");
    if (!textfile) return;              //in case access returned bogus info
    fread((void *) &szTempBuffer[0],1,256,textfile);
    fclose(textfile);
    if (!(p = strstr(szTempBuffer,"[Adapter]")))
    {   //bad file. remove it and format it again
      remove(VIDEOCFGFName);
    }
    else if (!(p = strstr(p,"OEMString")))
    {   //bad file. remove it and format it again
      remove(VIDEOCFGFName);
    }
    else
    {
      if (p = strchr(p,'"'))
      {
        CHAR *p2;
        //find the end of the string
        p2 = strchr(&p[1],'"');
        p2[0]=0;
        strncpy(szOEMString,&p[1],128);
        if (!strcmp(sAdapter.szOEMString,szOEMString))
           return;     /* Configuration file for this adapter alredy set */
      }
    }
    fclose(textfile);
    remove(VIDEOCFGFName);
  }
  if (!sAdapter.RefreshTable)
     return;            //no refresh info for this adapter available. Don't bother
                        //formatting the CFG file.
  textfile = fopen(VIDEOCFGFName, "w");
  if (!textfile) return;              //in case access returned bogus info
  strcpy(szTempBuffer,CONFIG_HEADER);
  WriteComment(1, &pTempBuffer);

  if (sAdapter.MonitorName[0] == 0x0)             //monitor name not set yet
  {
     strcpy(&sAdapter.MonitorName[0],"OTHER");         //will override later on for select adapters
     switch(sSVGA.AdapterType)
     {
       case CIRRUS_ADAPTER:
         /*
         ** issue int 10, function 12,9a to get current refresh settings
         */
         break;
       case TSENG_ADAPTER:
         /*
         ** read BIOS data area and hardware and get the bits
         */
         break;
       case S3_ADAPTER:
         /*
         ** read scratch register for Number 9.
         */
       default:
         break;
    }
  }
  fprintf(textfile,"[Adapter]\nOEMString = \"%s\"\n",sAdapter.szOEMString);
  fprintf(textfile,"[Monitor]\nOEMString = \"%s\"\n",sAdapter.MonitorName);

  /*  if svga on refresh was issued and this is not a DDC monitor @V3.0YEE02
  **  use default refresh values of 100 to force BVH to issue the
  **  highest possible refresh rate for the mode set.
  **  This is to avoid an additional reboot.
  */
  if ((GenerateRefresh) &&
      ((sAdapter.MonitorName[0] != 'D') &&
       (sAdapter.MonitorName[1] != 'D') &&
       (sAdapter.MonitorName[2] != 'C')))
  {
     for (i=0; i<5; i++)
     {
       if (Refresh[i] != -1)
         sAdapter.RefreshTable[i].DefaultVRefresh = 100;
     }
     i = 0;                   /* reinitialize counter */
  }

  while(i < MAX_REFRESH_MODES && sAdapter.RefreshTable[i].usYResolution)
  {
    if (sAdapter.RefreshTable[i].DefaultVRefresh != REFRESH_DISABLED)  /*JWK10*/  /*JWK18*/
    {
        fprintf(textfile,"[ModeInfo]\n");
        fprintf(textfile,"\tXResolution             = %d\n",sAdapter.RefreshTable[i].usXResolution);
        fprintf(textfile,"\tYResolution             = %d\n",sAdapter.RefreshTable[i].usYResolution);
        fprintf(textfile,"\tVerticalRefresh         = %d\n",sAdapter.RefreshTable[i].DefaultVRefresh);
        if (sAdapter.RefreshTable[i].usXResolution == 640 ||
            sAdapter.RefreshTable[i].usXResolution == 1024)
        {
          fprintf(textfile,"\tVPolarityPositive       = 0\n");
          fprintf(textfile,"\tHPolarityPositive       = 0\n\n");
        }
        else
        {
          fprintf(textfile,"\tVPolarityPositive       = 1\n");
          fprintf(textfile,"\tHPolarityPositive       = 1\n\n");
        }
    }
    i++;
  }
  fclose(textfile);
}

/*****************************************************************************
 *
 * FUNCTION NAME = ErrorExit()
 *
 * DESCRIPTION   = Displays error message and exits to DOS.
 *
 * INPUT         = Error code
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID ErrorExit(INT iErrorCode)
{
  printf(USAGE);
  if (iErrorCode)
    printf(ERROR_MSG_HEADER, errors[iErrorCode-1]);

  pBiosData[0x88] = EntryBIOSData88;
  pBiosData[0x89] = EntryBIOSData89;

  exit(iErrorCode);
}

/*****************************************************************************
 *
 * FUNCTION NAME = PrintStatus()
 *
 * DESCRIPTION   =
 *
 * INPUT         = Error code
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PrintStatus(PCHIPINFO pChipInfo, BOOL fGeneric)
{
  PCHIPHEADER pChipHdr;
  USHORT i, far *pusModes;
  CHAR s[80];
  PSSVGADACINFO psSVGADacInfo;                                  /*          */

  /*!!Should sSVGA stuff here be refering to sAdapter instead?*//*          */
  printf( STATUS_TEXT,                                          /*          */
          pszAdapter,                                           /*          */
          pszChipset,                                           /*          */
          sSVGA.Memory );                                       /*          */
  LockPushState( sSVGA.AdapterType,                             /*          */
                 sSVGA.ChipType,                                /*          */
                 aulRelockInfo );                               /*          */
  sDACINFO.DACFamily = psCurAdapterInfo->pifnSVGADacGetType();  /*          */
  LockPopState( sSVGA.AdapterType,                              /*          */
                sSVGA.ChipType,                                 /*          */
                aulRelockInfo );                                /*          */
  psSVGADacInfo = &asSVGADacInfo [sDACINFO.DACFamily];          /*          */
  printf( "DacType: %s %s",                                     /*          */
          psSVGADacInfo->pszDacName,                            /*          */
          psSVGADacInfo->pszDacManufacturer );                  /*          */
  if (pChipInfo)
  {

    if (sSVGA.AdapterType == TSENG_ADAPTER)    /*JWK10 for debugdata*/
    {
        TsengGetMonitorCableType();
        printf( "\nMonitorCableData: 0x%03x\n", MonitorCableData);
    }
    printf(SUPPORTED_MODES);

    for (i = 0; i < usNumModes; i++)
    {
      /* Just display the ones we have enough memory for */     /*          */
      /* We could also limit them to 16/256/text modes   */     /*          */
      /* if we just have std DAC */                             /*          */
      if( (pChipInfo->pChipHdr->ulSaveSize <= sSVGA.Memory)     /*          */
          && ((pChipInfo->pChipHdr->bBitsPerPixel <= 8)         /*          */
              || (sDACINFO.DACFamily != DEFAULT_DAC)) )         /*          */
      {
          if (pChipInfo->Refresh)                               /*JWK10*/
          {                                                     /*JWK10*/
              if (  (pChipInfo->Refresh != TSENG_REFRESH_ANY)
                 && (pChipInfo->Refresh != TSENG_REFRESH_UNKNOWN) )     /*JWK26*/
              {

                  printf( "  %s (@%d Hz).\n",                       /*JWK10*/
                    BuildModeString( pChipInfo->pChipHdr, s ), pChipInfo->Refresh); /*JWK10*/
              }
          }                                                     /*JWK10*/
          else                                                  /*JWK10*/
          {                                                     /*JWK10*/
              printf( "  %s.\n",                                /*JWK10*/
                BuildModeString( pChipInfo->pChipHdr, s ) );    /*JWK10*/
          }                                                     /*JWK10*/
      }
      pChipInfo++;
    }

    if (fGeneric && pusSupportedModes)
    {
      pusModes = pusSupportedModes;

      while (*pusModes != 0xffff)
      {
        pChipHdr = ChipInfoHeader;

        for( i = 0;
             i < usSizeChipInfoHeader;
             i++, pChipHdr++ )
          if (*pusModes == pChipHdr->usVESAModeNumber)
          {
            /* Just display the ones we have enough memory for*//*          */
            /* We could also limit them to 16/256/text modes  *//*          */
            /* if we just have std DAC */                       /*          */
            if( (pChipInfo->pChipHdr->ulSaveSize <=             /*          */
                   sSVGA.Memory )                               /*          */
                && ((pChipInfo->pChipHdr->bBitsPerPixel <= 8)   /*          */
                    || (sDACINFO.DACFamily != DEFAULT_DAC)) )   /*          */
              printf("  %s.\n", BuildModeString(pChipHdr, s));  /*JWK10*/
            break;
          }
        pusModes++;
      }
    }
  }
}

/*****************************************************************************/

SADAPTERINFO sVGAAdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  SVGADacGetType,
};

SADAPTERINFO sCirrusAdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  CirrusDacGetType,
};

SADAPTERINFO sIBMAdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  SVGADacGetType,
};

SADAPTERINFO sS3AdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataS3DacRS2Clear,
  aRegDataS3DacRS2Set,
  aRegDataS3DacRS3Clear,
  aRegDataS3DacRS3Set,
  S3DacGetType,
};

SADAPTERINFO sTridentAdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  SVGADacGetType,
};

SADAPTERINFO sTsengAdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  TsengDacGetType,
};

SADAPTERINFO sVideo7AdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  SVGADacGetType,
};

SADAPTERINFO sWDAdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  WDDacGetType,                                                 /*          */
};

SADAPTERINFO sWeitekAdapterInfo =
{
  SVGAEditTables,                                               /*          */
  SVGAAdjustedPort,                                             /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  aRegDataNone,                                                 /*          */
  WeitekDacGetType,
};

PSADAPTERINFO psAllAdapterInfo [SVGA_LASTADAPTER + 0x01] =
{
  &sVGAAdapterInfo,     /* 00 = UNKNOWN_ADAPTER    */
  &sVideo7AdapterInfo,  /* 01 = VIDEO7_ADAPTER     */
  &sTridentAdapterInfo, /* 02 = TRIDENT_ADAPTER    */
  &sTsengAdapterInfo,   /* 03 = TSENG_ADAPTER      */
  &sWDAdapterInfo,      /* 04 = WESTERNDIG_ADAPTER */
  &sATIAdapterInfo,     /* 05 = ATI_ADAPTER        */
  &sIBMAdapterInfo,     /* 06 = IBM_ADAPTER        */
  &sCirrusAdapterInfo,  /* 07 = CIRRUS_ADAPTER     */
  &sS3AdapterInfo,      /* 08 = S3_ADAPTER         */
  &sVGAAdapterInfo,     /* 09 = CHIPS_ADAPTER      */
  &sWeitekAdapterInfo,  /* 10 = WEITEK_ADAPTER     */
};

/*****************************************************************************
 *
 * FUNCTION NAME = main()
 *
 * DESCRIPTION   = Main entry point.
 *
 *      SVGA.EXE can be invoked with the following parameters:
 *
 *              <ON | OFF | STATUS | MONITOR> <DOS | INIT | GENERIC>
 *
 *      argc is the number of parameters e.g. svga on dos = 3
 *      argv is the positioning of the parameters e.g. svga=argv[0],on=argv[1]..
 *
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID main(INT argc,CHAR **argv)
{
  INT rc=0,iParm1=0,iParm2=0;
  INT iDosVersion;
  INT iWindowed = FALSE;                                        /*          */
  BOOL fGeneric = FALSE;
  PCHIPINFO ChipInfo;
  ULONG ulVESAMemorySize;               /* In bytes */          /*          */
  static union REGS regs;                                       /*          */
  static struct SREGS sregs;                                    /*          */
  BYTE far *fpByte;                                             /*          */
  USHORT i;                                                     /*@V3.0YEE02*/

  printf(BANNER, VERSION);


  EntryBIOSData88 = pBiosData[0x88];    /*jwk */
  EntryBIOSData89 = pBiosData[0x89];



  /*!! This call does not work correctly */                     /*          */
  /*!! for MS-DOS versions below 5.0!    */                     /*          */
  /*!! for IBM DOS version 4.0 a 42=0x2a is returned */         /*          */
  iDosVersion = get_dos_version();
  /*!! This test yields incorrect results for */                /*          */
  /*!! Diamond SpeedStar Pro VL cards w/Cirrus 5428  */         /*          */
  /*!! These cards return zero for read from port 0x03d6!  */   /*          */

  /* Delay test for windowed until we know adapter type */      /*          */
//OutpDelay( 0x03d6, 0x82 );            /* Enable IsWindow */   /*          */
//iWindowed   = !InpDelay( 0x03d6 );                            /*          */
///* Real DOS is NOT windowed! */                               /*          */
  /*!! This test yields incorrect results for IBM-DOS 4.0 */    /*          */
  /*!! with Diamond SpeedStar Pro VL cards w/Cirrus 5428  */    /*          */
  /*!! see comments above */                                    /*          */
//iWindowed &= (iDosVersion >= 20);                             /*          */
  strcpy(VIDEOCFGFName, VIDEOCFG_FNAME);                        /*          */
  VIDEOCFGFName[0] = GetBootDrive();                            /*          */
  strcpy(PMIFName, PMI_FNAME);
  PMIFName[0] = GetBootDrive();
  switch (argc)
  {
    case 4:                        /*JWK22*/
      switch (ParmType(argv[3]))   /* so to not interfere with other parms */
      {
        case PARM_BAD:
          ErrorExit(ERROR_NUM_PARM);
          break;
        case PARM_DEBUG:
          _asm{ int 3 }
          fDebug = TRUE;
          break;
      }
      /* Drop thru to next case: */

    case 3:                                     /* validate second parameter */
    case 8:                        /*@V3.0YEE02*/
      switch (iParm2 = ParmType(argv[2]))
      {
        case PARM_BAD:
          ErrorExit(ERROR_NUM_PARM);
          break;
        case PARM_INIT:
          SetDefaultMonitor = 1;
          break;
        case PARM_GENERIC:                      /* create file from script   */
          fGeneric = TRUE;
          break;
        case PARM_DOS:
          strcpy(PMIFName, "svgadata.dos");
          strcpy(VIDEOCFGFName, "video.cfg");                   /*          */
          DosParm = 1;                                          /*          */
          break;
        case PARM_DEBUG:                                        /*          */
          _asm{ int 3 }                                         /*          */
          fDebug = TRUE;                                        /*          */
          DosParm = 1;
          if( iDosVersion < 20 )                                /*          */
          {                                                     /*          */
            strcpy( PMIFName,                                   /*          */
                    "svgadata.dos" );                           /*          */
            strcpy(VIDEOCFGFName, "video.cfg");                 /*          */
          }                                                     /*          */
          /* Drop thru to PARM_INSTALL */                       /*          */
        case PARM_INSTALL:                                      /*          */
          SetDefaultMonitor = 1;                                /*          */
          fInstall = TRUE;                                      /*          */
          iWindowed = FALSE;                                    /*          */
          break;                                                /*          */
        case PARM_REFRESH:                                      /*@V3.0YEE02*/
          for (i=0; i<5; i++)                                   /*@V3.0YEE02*/
            Refresh[i] = (char)atoi(argv[i+3]);                 /*@V3.0YEE02*/
          GenerateRefresh = 1;                                  /*@V3.0YEE02*/
          break;                                                /*@V3.0YEE02*/
      }
      /* Drop thru to next case: */                             /*          */

    case 2:                             /* validate 1st param */
      if (iWindowed)                                            /*          */
        rc = ERROR_NUM_FULLSCREEN;      /* preset possible error */
      else                                                      /*          */
        rc = 0;                                                 /*          */

      switch(iParm1 = ParmType(argv[1]))
      {
        case PARM_CREATE:
          if( (iDosVersion < 20)                                /*          */
              && (iParm2 != PARM_DOS)                           /*          */
              && (iParm2 != PARM_DEBUG) )                       /*          */
            rc = ERROR_NUM_PARM;
//        else if (!iWindowed)                                  /*          */
//          rc = 0;                                             /*          */
          break;

        case PARM_STATUS:
//        if (!iWindowed)                                       /*          */
//          rc = 0;                                             /*          */
          break;

        case PARM_DELETE:
          if ((iDosVersion < 20) && (iParm2 != PARM_DOS))
            rc = ERROR_NUM_PARM;
          else
            rc = 0;
          break;

        default:
          rc = ERROR_NUM_PARM;
          break;
      }

      if (rc)
        ErrorExit(rc);
      break;

    default:
      ErrorExit(0);
      break;
  }

  /* sSVGA.Memory not defined yet! */                           /*          */
//fVesaBIOS = IsVesaBIOS(&ulVESAMemorySize, &pusSupportedModes);/*          */

  if (fGeneric)
  {
    sSVGA.ChipType = 0;
    sSVGA.AdapterType = DEFAULT_ADAPTER;
//  if (!fVesaBIOS)                                             /*          */
      sSVGA.Memory = 256L * 1024L;
    LoadScriptFile(PMIFName);
  }
  else
  {
    /*
    ** call SCREEN$ to identify the adapter. If it fails,
    ** resort to our own routines (real DOS).
    */
    if( fInstall                                                /*          */
        || !QueryAdapter( &sSVGA )                              /*          */
        || (!sSVGA.AdapterType && DosParm) )
      IdentifySVGA();

    /*
    ** The S3 911 chip is identified but not supported.                     
    ** Do not generate a PMI file for this chip.                            
    ** Neither a DOS FS nor DOS window session starts using the             
    ** S3 drivers, 132 cols don't work, and PM has problems.                
    ** Just use the SVGA driver.                                            
    */
    if ((sSVGA.AdapterType == S3_ADAPTER) &&                    /*          */
        (sSVGA.ChipType == S3_86C911_CHIP))                     /*          */
      ErrorExit(ERROR_NUM_UNSUPPORTED);                         /*          */

    psCurAdapterInfo =                                          /*          */
      psAllAdapterInfo                                          /*          */
        /* Allow uplevel SCREENDD & PMI files */                /*          */
        /* Unknown adapter type is OK! */                       /*          */
        [((sSVGA.AdapterType <= SVGA_LASTADAPTER)               /*          */
         ? sSVGA.AdapterType                                    /*          */
         : UNKNOWN_ADAPTER)];                                   /*          */
    psCurAdapterInfo->pfnSVGAEditTables();                      /*          */

//           thanks to MNH30 fix, this piece of code is dead. Move it below
//the IsVesaBIOS call.
//
//    if (strstr(sAdapter.szRevision, "STB"))                     /*          */
//      sOEM.Manufacturer = STB_MANUFACTURER;                     /*          */
//    else if (strstr(sAdapter.szRevision, "Number Nine"))        /*          */
//      sOEM.Manufacturer = NUMBER9_MANUFACTURER;                 /*          */
//    else if (strstr(sAdapter.szRevision, "Diamond"))            /*          */
//      sOEM.Manufacturer = DIAMOND_MANUFACTURER;                 /*          */

    /*
    ** Don't want this test to get in the way on adapters where
    ** 3d6 is a real port. Until we get a better is windowed test,
    ** stick with it.           
    */
    if( (iParm2 != PARM_INSTALL)                                /*          */
        && (iParm2 != PARM_DEBUG) )                             /*          */
      if( (sSVGA.AdapterType != WEITEK_ADAPTER)                 /*          */
          && (sSVGA.AdapterType != CHIPS_ADAPTER)               /*          */
          && (sSVGA.AdapterType != CIRRUS_ADAPTER) )            /*          */
      {                                                         /*          */
        OutpDelay( 0x03d6, 0x82 );      /* Enable IsWindow */   /*          */
        iWindowed = !InpDelay( 0x03d6 )                         /*          */
                       /* Real DOS is NOT windowed! */          /*          */
                    && (iDosVersion >= 20);                     /*          */
      }                                                         /*          */
  }
//LockPushState( sSVGA.AdapterType,                             /*          */
//               sSVGA.ChipType,                                /*          */
//               aulRelockInfo );                               /*          */
//if( (sSVGA.AdapterType == WESTERNDIG_ADAPTER)                 /*          */
//    && ((sSVGA.ChipType == WESTERNDIG_WD9024_CHIP)            /*          */
//        || (sSVGA.ChipType == WESTERNDIG_WD9026_CHIP)         /*          */
//        || (sSVGA.ChipType == WESTERNDIG_WD9027_CHIP))        /*          */
//    && (OutpDelay( 0x03d4, 0x33),                             /*          */
//        ((InpDelay( 0x03d5 ) & 0x60) == 0x60) /*Dual 16b STN*//*          */
//  /* Dual panel 16-bit STNs (Super Twisted Nematic) must be *//*          */
//  /* only 1/2M organization in order to function at all */    /*          */
//  sSVGA.Memory =  0x80000L;           /* 1/2M */              /*          */
//LockPopState( sSVGA.AdapterType,                              /*          */
//              sSVGA.ChipType,                                 /*          */
//              aulRelockInfo );                                /*          */
  fVesaBIOS = IsVesaBIOS(&ulVESAMemorySize, &pusSupportedModes);/*          */


  /* JWK03
  ** Disable VESA Compliance for Tseng. Most Tseng BIOS's return wrong
  ** memory size, and and can't go from failed extended modes into text mode
  ** without additional cleanup.  Also, vsvga.sys not VESA compliant for tseng,
  ** as well as some routines in this executable.
  ** Maybe after changes to vsvga.sys, and then maybe on a per BIOS
  ** level basis or chiptype level basis.
 */

//JWK16 Memory size still may be wrong, but all other dependancies have been
//JWK16 eliminated
//JWK16
//JWK16  if (sSVGA.AdapterType == TSENG_ADAPTER )
//JWK16  {
//JWK16      fVesaBIOS = FALSE;
//JWK16  }
//JWK16

  if (strstr(sAdapter.szRevision, "STB"))                     /*          */
    sOEM.Manufacturer = STB_MANUFACTURER;                     /*          */
  else if (strstr(sAdapter.szRevision, "Number Nine"))        /*          */
    sOEM.Manufacturer = NUMBER9_MANUFACTURER;                 /*          */
  else if (strstr(sAdapter.szRevision, "#9 Computer"))        /*@V3.0YEE04*/
    sOEM.Manufacturer = NUMBER9_MANUFACTURER;                 /*@V3.0YEE04*/
  else if (strstr(sAdapter.szRevision, "Diamond"))            /*          */
    sOEM.Manufacturer = DIAMOND_MANUFACTURER;                 /*          */
  else if (strstr(sAdapter.szRevision, "ORCHID"))             /*@V3.0YEE06*/
    sOEM.Manufacturer = ORCHID_MANUFACTURER;                  /*@V3.0YEE06*/

  if (IsDiamondW32())                                         /*          */
  {                                                           /*          */
      TSENGDiamondW32 = TRUE;                                 /*          */
      fVesaBIOS = FALSE;                                      /*          */
  }                                                           /*          */
  else                                                        /*          */
      TSENGDiamondW32 = FALSE;                                /*          */

  /*
  ** For the vesa-compliant cards, we can query the video
  ** memory size directly from the BIOS.
  ** Don't change memory size if S3 since VESA BIOS does
  ** not return accurate information.  Use value from SCREENDD.
  **             don't change memory size if WEITEK,
  ** since DIAMOND VIPER VESA BIOS returns information about the VGA only!
  ** Quite possibly other WEITEK P9000 BIOSes will as well.
  ** The IdentifySVGA/WhichWeitek memory test should suffice.
  ** Don't change memory size if TSENG.
  ** Don't change memory size if WD - looks like 768K means 1M
  ** and 0K means 256K.
  ** Does this call work for anybody besides CIRRUS?
  */
  if( sSVGA.AdapterType
      && fVesaBIOS
      && (sSVGA.AdapterType != S3_ADAPTER)                      /*          */
      && (sSVGA.AdapterType != WEITEK_ADAPTER)                  /*          */
      && (sSVGA.AdapterType != TSENG_ADAPTER)
      && (sSVGA.AdapterType != WESTERNDIG_ADAPTER) )            /*          */
    sSVGA.Memory = ulVESAMemorySize;                            /*          */

  /*            start
  ** Identify Lacuna and put statement in PMI.  The PM driver will recognize
  ** it's a Lacuna and issue the mode3 at PM death.  This is because Lacuna
  ** system BIOS does not set the extended S3 registers to VGA when setting
  ** mode 3.
  */

  if (sSVGA.AdapterType == S3_ADAPTER)
  {
      if (sSVGA.ChipType == S3_86C928_CHIP)
      {
        regs.x.ax = 0xC000;
        int86x(LBIOS, &regs, &regs, &sregs);   /* query Lacuna ID via int 15 */

        SEGMENTOF(fpByte) = sregs.es;
        OFFSETOF(fpByte) =  regs.x.bx;
        if ((fpByte[2] == 0xF8) &&
            (*(fpByte+3) == 0xB0))
          sOEM.Manufacturer = LACUNA_MANUFACTURER;
      }

      /* looking for Mach5 VP system with S3864 on planar                */
      if (sSVGA.ChipType == S3_86C864_CHIP)
      {
        regs.x.ax = 0xD207;
        int86x(LBIOS, &regs, &regs, &sregs);   /* query Mach 5 ID via int 15 */
        if ((regs.h.ah == 0x00)  &&
            !(regs.x.cflag & 0x01))            /* carry flag not set         */
        {
          SEGMENTOF(fpByte) = sregs.es;
          OFFSETOF(fpByte) =  regs.x.di;
          if ((fpByte[0xd] == 'N') &&
              ((fpByte[0xe] == '1') ||         /* Mach5 ISA */
               (fpByte[0xe] == '2') ||         /* Mach5 MC  */
               (fpByte[0xe] == '3')))          /* Mach5 MC  */
            sOEM.ManufacturerData = Mach5;
        }                                     /* end Mach5 test           */

        /**  identify Dell system by looking at address 0xfe076 @V3.0YEE11*/
        /**  for the string "Dell"                              @V3.0YEE11*/
        if (!memcmp((UCHAR far *)0xf000e076, "Dell",4))       /*@V3.0YEE11*/
          sOEM.ManufacturerData = DELL;                       /*@V3.0YEE11*/
      }
  }

  /*  see if it is a Thinkpad system                            @V3.0YEE09*/
  if ((sSVGA.AdapterType == WESTERNDIG_ADAPTER) &&
      (sSVGA.ChipType == WESTERNDIG_WD9024_CHIP))
    IsThinkpad();

  if( fGeneric
      || sSVGA.AdapterType )
    switch (iParm1)
    {
      case PARM_CREATE :                /* create file */
        if( iWindowed )                                         /*          */
          ErrorExit( ERROR_NUM_FULLSCREEN );                    /*          */
        /* if (sSVGA.AdapterType) already checked! */           /*          */
        if (rc = ProcessChipset(sSVGA, fGeneric))
          ErrorExit(rc);
        else
          WriteVideoCFGFile();                                  /*          */
        break;

      case  PARM_DELETE :               /* delete file */
        if (remove(PMIFName))
          ErrorExit(ERROR_NUM_DELETE);
        break;

      case  PARM_STATUS :               /* status */
        if( iWindowed )                                         /*          */
          ErrorExit( ERROR_NUM_FULLSCREEN );                    /*          */
        if (ChipInfo = SetupChipInfo(sSVGA.AdapterType, sSVGA.ChipType, fGeneric))
          PrintStatus(ChipInfo, fGeneric);
        else
          ErrorExit(ERROR_NUM_UNSUPPORTED);
        break;
    }
  else
    ErrorExit(ERROR_NUM_UNSUPPORTED);

  pBiosData[0x88] = EntryBIOSData88;   /*jwk*/
  pBiosData[0x89] = EntryBIOSData89;

  exit( (fInstall && (iParm1 == PARM_STATUS))                   /*          */
        ? ((sSVGA.AdapterType << 8) | sSVGA.ChipType)           /*          */
        : 0 );                                                  /*          */
}
