/*DDK*************************************************************************/
/*                                                                           */
/* 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 = VVWD.C
 *
 * DESCRIPTIVE NAME = Virtual Video WD Specific Processing
 *
 *
 * VERSION = V2.1
 *
 * DATE      04/30/93
 *
 * DESCRIPTION  This module contains all accelerator specific SVGA code and data.
 *
 *
 * FUNCTIONS
 *      vvWDC31WriteWRegByteL()         Write low byte of WD Ext word register
 *      vvWDC31WriteWRegByteH()         Write high byte of WD Ext word register
 *      vvWDC31WriteWRegWord()          Write WD Ext word register
 *      vvWDC31WriteIndxByteL()         Write low byte of WD Index register
 *      vvWDC31WriteIndxByteH()         Write high byte of WD Index register
 *      vvWDC31WriteIndxWord()          Write WD Index register
 *      vvWDC31ReadDataByteL()          Read low byte of WD Data register
 *      vvWDC31ReadDataByteH()          Read high byte of WD Data register
 *      vvWDC31ReadDataWord()           Read WD Data register
 *      vvWDC31WriteDataByteL()         Write low byte of WD Data register
 *      vvWDC31WriteDataByteH()         Write high byte of WD Data register
 *      vvWDC31WriteDataWord()          Write WD Data register
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#define  IO8BIT           /* CL386 Version 6.00.054 FLAG:              */
#include <mvdm.h>
#include <vvd.h>
#include <vvdp.h>

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif
#define  INCL_DOSERRORS
#include <bseerr.h>

#pragma  BEGIN_SWAP_DATA
/*
**     Externals
*/
extern PSACCELERATORINFO psCurAcceleratorInfo;                  /*          */
extern ULONG ulSVGAChipType;
extern BOOL fSVGASeqFixups;
extern OEMINFO sOEMData;
extern PLE pleCRTIndx;                  /* 0x03b4/0x03d4 */     /*          */
extern PLE pleCRTData;                  /* 0x03b5/0x03d5 */     /*          */
extern PLE pleSEQIndx;                  /* 0x03c4 */            /*          */
extern PLE pleSEQData;                  /* 0x03c5 */            /*          */
extern PLE pleGDCIndx;                  /* 0x03ce */            /*          */
extern PLE pleGDCData;                  /* 0x03cf */            /*          */
extern PLE pleMiscOutWrite;             /* 0x03c2 */            /*@V3.0YEE01*/
extern BYTE abCRTMask[];                                        /*@V3.0YEE01*/
extern BYTE abGDCMask[];                                        /*@V3.0YEE01*/
extern BYTE abSEQMask[];                                        /*@V3.0YEE01*/
extern STRAPREGPARTINFO sTrapWRegLow;                           /*          */
extern STRAPREGPARTINFO sTrapWRegHigh;                          /*          */
extern STRAPREGPARTINFO sTrapWRegWhole;                         /*          */
extern BYTE abAccelCRTReadMask[];                               /*          */
extern BYTE abAccelSEQReadMask[];                               /*          */
extern BYTE abAccelGDCReadMask[];                               /*          */
extern BYTE abAccelATCReadMask[];                               /*          */

CHAR pszWDAdapterName [] = "WESTERNDIGITAL" ;                   /*          */

PCHAR ppszWDChipNames [MAX_WESTERNDIG_CHIP] =                   /*          */
{  /* As produced by SVGA.EXE! */                               /*          */
  "PVGA1A",
  "PVGA1B",
  "PVGA1C",
  "PVGA1D",
  "WD90C26",                                                    /*          */
  "WD90C27",                                                    /*          */
  "WD90C31",                                                    /*          */
  "WD90C24",                                                    /*          */
  "WD90C33",                                                    /*          */
};                                                              /*          */

IOH iohWDC31wreg [2];                   /* Forward */
IOH iohWDC31indx [2];                   /* Forward */
IOH iohWDC31data [2];                   /* Forward */

BYTE bWDRefresh640;                                             /*@V3.0YEE01*/
BYTE bWDRefresh800;                                             /*@V3.0YEE02*/

#define WDC31TRAPREGSIZE 0x20                                   /*          */
#define WS(x) ((PVOID)(&VDMData.VdmSVGA.wRegShadow [x]))
#define RW_INDX (WRITE_INDX | READ_INDX | R_EQ_W)
#define RW_MANY (WRITE_MANY | READ_MANY | R_EQ_W)
#define RW_ONCE (WRITE_ONCE | READ_ONCE | R_EQ_W)
#define RW_NONE (WRITE_NONE | READ_NONE | R_NE_W)

STRAPREGINFO sWDC31TrapRegInfo [WDC31TRAPREGSIZE] =
{
  {/*x00*/0x23c0, WS(0x00), WS(0x00), RW_MANY, iohWDC31indx} ,
  {/*x01*/0x23c2, WS(0x01), WS(0x01), RW_INDX, iohWDC31data} , /* Array */
  {/*x02*/0x23c4, WS(0x02), WS(0x02), RW_ONCE, iohWDC31wreg} ,
  {/*x03*/0x23c6, WS(0x03), WS(0x03), RW_ONCE, iohWDC31wreg} ,
  {/*x04*/0x23c8, WS(0x04), WS(0x04), RW_MANY, iohWDC31wreg} ,
  {/*x05*/0x23ca, WS(0x05), WS(0x05), RW_MANY, iohWDC31wreg} ,
  {/*x06*/0x23cc, WS(0x06), WS(0x06), RW_MANY, iohWDC31wreg} ,
  {/*x07*/0x23ce, WS(0x07), WS(0x07), RW_MANY, iohWDC31wreg} ,
  {/*x08*/0x23d0, WS(0x08), WS(0x08), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x09*/0x23d2, WS(0x09), WS(0x09), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x0a*/0x23d4, WS(0x0a), WS(0x0a), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x0b*/0x23d6, WS(0x0b), WS(0x0b), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x0c*/0x23d8, WS(0x0c), WS(0x0c), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x0d*/0x23da, WS(0x0d), WS(0x0d), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x0e*/0x23dc, WS(0x0e), WS(0x0e), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x0f*/0x23de, WS(0x0f), WS(0x0f), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x10*/0x2de0, WS(0x10), WS(0x10), RW_MANY, iohWDC31wreg} ,  /*          */
  {/*x11*/0x2de2, WS(0x11), WS(0x11), RW_MANY, iohWDC31wreg} ,  /*          */
  {/*x12*/0x2de4, WS(0x12), WS(0x12), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x13*/0x2de6, WS(0x13), WS(0x13), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x14*/0x2de8, WS(0x14), WS(0x14), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x15*/0x2dea, WS(0x15), WS(0x15), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x16*/0x2dec, WS(0x16), WS(0x16), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x17*/0x2dee, WS(0x17), WS(0x17), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x18*/0x2df0, WS(0x18), WS(0x18), RW_MANY, iohWDC31wreg} ,  /*          */
  {/*x19*/0x2df2, WS(0x19), WS(0x19), RW_MANY, iohWDC31wreg} ,  /*          */
  {/*x1a*/0x2df4, WS(0x1a), WS(0x1a), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x1b*/0x2df6, WS(0x1b), WS(0x1b), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x1c*/0x2df8, WS(0x1c), WS(0x1c), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x1d*/0x2dfa, WS(0x1d), WS(0x1d), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x1e*/0x2dfc, WS(0x1e), WS(0x1e), RW_NONE, iohWDC31wreg} ,  /*          */
  {/*x1f*/0x2dfe, WS(0x1f), WS(0x1f), RW_NONE, iohWDC31wreg} ,  /*          */
};

#pragma  END_SWAP_DATA

#pragma  BEGIN_SWAP_CODE
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDEditTables()
 *
 * DESCRIPTION   = Called once to do SVGA-specific initialisation
 *
 * INPUT         =
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID PRIVENTRY vvWDEditTables( VOID )
{
  fSVGASeqFixups = FALSE;                                       /*          */
  /*
  ** Fix up the masks as to allow more registers to be read. All of the
  ** registers within the range are assumed as readable (default). Should
  ** that not be the case, force 0's in all bit positions of non-existing or
  ** non-readable registers. Later on, in the creation routine, setup the shadow
  ** states of the non-readable registers (such as advance function control), so
  ** that the registers get initialized correctly.
  */
  pleCRTData.pbBRegReadMask = &abAccelCRTReadMask [0];          /*          */
  pleSEQData.pbBRegReadMask = &abAccelSEQReadMask [0];          /*          */
  pleGDCData.pbBRegReadMask = &abAccelGDCReadMask [0];          /*          */

  /*
  ** Read CMOS to get the refresh rate on Thinkpad systems           @V3.0YEE02
  */
  DISABLE();
  OUTB(0x70, 0x6b);
  bWDRefresh640 = INB(0x71) & 0x07;   /* 60/72/75Hz */

  OUTB(0x70, 0x6c);                                                /*@V3.0YEE02*/
  bWDRefresh800 = (INB(0x71) >> 0x03) & 0x07;   /* 60/72Hz */
  ENABLE();
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDInterlaced
 *
 * DESCRIPTION   = Get Interlaced Status
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = True = interlacing on
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vvWDInterlaced(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return( (pvd->aregCRTData [0x2d] & 0x20) >> ZEROBITS( 0x20 ) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDVertTimingOverflow
 *
 * DESCRIPTION   = Get Vertical Timing Overflow Index
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Vertical Timing Overflow Byte
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE PRIVENTRY vvWDVertTimingOverflow(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return( pvd->aregCRTData
            [(((ulSVGAChipType == WESTERNDIG_WD9024_CHIP)
               || (ulSVGAChipType == WESTERNDIG_WD9026_CHIP)
               || (ulSVGAChipType == WESTERNDIG_WD9027_CHIP))
              ? 0x3d                    /* PR18A */
              : 0x3e)] );               /* PR18 */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDStartAddr
 *
 * DESCRIPTION   = Get Display frame start address
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = offset into VRAM for display frame
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

ULONG PRIVENTRY vvWDStartAddr(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return(  vvCGAStartAddr( hvdm )
           | ((pvd->aregGDCData [0x0d] & 0x18)
              >> ZEROBITS( 0x18) << 16)
           | ((vvWDVertTimingOverflow( hvdm ) & 0x40)
              >> ZEROBITS( 0x40) << 18) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDVertDspEnd
 *
 * DESCRIPTION   = Get Vertical Display Length
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Vertical Display Length
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT PRIVENTRY vvWDVertDspEnd(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  return( vvVGAVertDspEnd( hvdm )
          + ((vvWDVertTimingOverflow( hvdm ) & 0x02)
             >> ZEROBITS( 0x02 ) << 10) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDVertLineCmp
 *
 * DESCRIPTION   = Get Vertical Line Compare
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Vertical Line Compare (for split screen)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT PRIVENTRY vvWDVertLineCmp(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return( vvVGAVertLineCmp( hvdm )
          + ((vvWDVertTimingOverflow( hvdm ) & 0x10)
             >> ZEROBITS( 0x10 ) << 10) );
}

/*****************************************************************************
 *
 * FUNCTION NAME = ThinkpadMaxLCDRes()                            @V3.0YEE01
 *
 * DESCRIPTION   = Obtain maximum resolution supported by Thinkpad LCD
 *
 * INPUT         = NONE
 * OUTPUT        = LCD panel max resolution / 720
 *
 ****************************************************************************/

USHORT ThinkpadMaxLCDRes(VOID)
{
  USHORT MaxRes = 720;                /* set lowest denominator */

  /* PR1A has flat panel max resolution size.                     */
  /* This doesn't work on Thinkpad.  It appears PR1A is set after */
  /* the setmode.  PR1A also controls the screen centering.       */
  /* This is how the TFT panel manufacturer designed it.          */
  /* So for Thinkpad systems, get the value from (d00h.12h+1)*8   */
  /* to determine max resolution supported on panel.              */

  if (sOEMData.Manufacturer == THINKPAD_MANUFACTURER)
  {
     OUTB(0x0d00, 0x12);
     MaxRes = (INB(0x0d01) +1) * 8;

     if (MaxRes == 640)
       MaxRes = 720;               /* anticipate text mode */
  }
  return (MaxRes);

}

/***************************************************************************
 *
 * FUNCTION NAME = ThinkpadFixClock()                             @V3.0YEE02
 *
 * DESCRIPTION   = Fix up the clock values for Thinkpad with SVGA LCD
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY ThinkpadFixClock(HVDM hvdm)
{
   BYTE SaveSEQIndx, SaveCRTIndx;
   BYTE Displaytype, RefreshValue, MiscValue;
   register PVDMDATA pvd = pVDMData(hvdm);

   if (!(pvd->flVDMXVideo & VDMX_INTRESTOREFGND) &&
       (ThinkpadMaxLCDRes() == 800))      /* 800x600 panel */
   {
      /* On LCD panel that does 800x600, need to do some register */
      /* fix-ups to set clock correctly since clock values set    */
      /* by the BIOS for the initial set mode may not be the same */
      /* if user restores session on different display.           */
      /* Also, cleanup section in PMI may not reflect correct     */
      /* values for CRT if PMI was generated on LCD and viceversa.*/
      /* Code duplicated in svgautil\svgawd.c  also.  (P-U!!)     */

      SaveSEQIndx = pvd->regSEQIndx;      /*save shadowed index @V3.0YEE03*/
      SaveCRTIndx = pvd->regCRTIndx;      /*save shadowed index @V3.0YEE04*/

      Displaytype = pvd->aregCRTData[0x32] & 0x10;  /* CRT=0; LCD/BOTH=10*/

      /* For all modes but 1024, turn off HIGH VCLK of             @V3.0YEE04*/
      /* Miscellaneous Control 1 if on external display (3d4.2eh)  @V3.0YEE04*/
      if (pvd->vvMode.vvm_nCols != 1024)
      {
         vvOutput(hvdm, &pleCRTIndx, 0x2e);
         if (!Displaytype)              /* CRT */
           vvOutput(hvdm, &pleCRTData,
                    (BYTE)(pvd->aregCRTData[0x2e] & 0xbf));
      }

      if (pvd->mstateVideo == MEMORY_TEXT)
      {
         /* TEXT Mode:  3c2h |  3c4.31h |  3c4.31h |  3c4.31h    */
         /*                  |   60Hz   |    72Hz  |    75Hz     */
         /* -----------------|----------|----------|------------ */
         /* LCD/BOTH    63h  |    15h   |    15h   |    15h      */
         /* CRT         67h  |    0dh   |    0dh   |    1dh      */

         MiscValue = ((Displaytype) ? 0x63         /* LCD/BOTH */
                                    : 0x67);       /* CRT      */
         switch (bWDRefresh640)
         {
           case 2:                 /* 75Hz*/
             RefreshValue = ((Displaytype) ? 0x15      /* LCD/BOTH */
                                           : 0x1d);    /* CRT      */
             break;

           default:               /* 60Hz or 72Hz */
             RefreshValue = ((Displaytype) ? 0x15      /* LCD/BOTH */
                                           : 0x0d);    /* CRT      */
             break;
         }
         vvOutput(hvdm, &pleMiscOutWrite, MiscValue);  /* set Misc */
         vvOutput(hvdm, &pleSEQIndx, 0x31);
         vvOutput(hvdm, &pleSEQData, RefreshValue);    /* set clock*/

         /* For text modes, set 8/9 character dot clock          @V3.0YEE02*/
         /* appropriately for display type (3c4.01h)             @V3.0YEE02*/
         vvOutput(hvdm, &pleSEQIndx, 0x01);
         RefreshValue = ((Displaytype)
                         ? (pvd->aregSEQData[0x01] | 0x01)   /* LCD/BOTH */
                         : (pvd->aregSEQData[0x01] & 0xfe)); /* CRT      */
         vvOutput(hvdm, &pleSEQData, RefreshValue); /* 8/9 char clock*/
      }

      else if ((pvd->ulBIOSMode & ~BIOSVINFO_DONTCLEAR) <= 0x13)
      {
         /* 320x200:    |  3c4.31h |  3c4.31h |  3c4.31h   */
         /*             |   60Hz   |    72Hz  |    75Hz    */
         /* ------------|----------|----------|----------- */
         /* LCD/BOTH    |    15h   |    15h   |    15h     */
         /* CRT         |    0dh   |    0dh   |    1dh     */

         switch (bWDRefresh640)
         {
           case 2:                 /* 75Hz*/
             RefreshValue = ((Displaytype) ? 0x15      /* LCD/BOTH */
                                           : 0x1d);    /* CRT      */
             break;

           default:               /* 60Hz or 72Hz */
             RefreshValue = ((Displaytype) ? 0x15      /* LCD/BOTH */
                                           : 0x0d);    /* CRT      */
             break;
         }
         vvOutput(hvdm, &pleSEQIndx, 0x31);
         vvOutput(hvdm, &pleSEQData, RefreshValue);    /* set clock*/
      }

      else if (pvd->vvMode.vvm_nCols == 640)   /* 640 resolution */
      {
         if (pvd->vvMode.vvm_nBitCount <= 8)   /* 16/256 colors */
         {
            /* 640x480x16:  |  3c4.31h |  3c4.31h |  3c4.31h   */
            /* 640x480x256: |   60Hz   |    72Hz  |    75Hz    */
            /*  ------------|----------|----------|----------- */
            /*  LCD/BOTH    |    15h   |    15h   |    15h     */
            /*  CRT         |    0dh   |    1dh   |    1dh     */

            switch (bWDRefresh640)
            {
              case 0:                 /* 60Hz*/
                RefreshValue = ((Displaytype) ? 0x15      /* LCD/BOTH */
                                              : 0x0d);    /* CRT      */
                break;

              default:               /* 72Hz or 75Hz */
                RefreshValue = ((Displaytype) ? 0x15      /* LCD/BOTH */
                                              : 0x1d);    /* CRT      */
                break;
            }
            vvOutput(hvdm, &pleSEQIndx, 0x31);
            vvOutput(hvdm, &pleSEQData, RefreshValue);   /* set clock*/
         }

         else if (pvd->vvMode.vvm_nBitCount == 16)  /* 64K colrs */
         {
            /* 640x480x64K:3c2h |  3c4.31h |  3c4.31h |  3c4.31h    */
            /*                  |   60Hz   |    72Hz  |    75Hz     */
            /* -----------------|----------|----------|------------ */
            /* LCD/BOTH    efh  |    0dh   |    0dh   |    0dh      */
            /* CRT         e3h  |    0dh   |    1dh   |    1dh      */

            MiscValue = ((Displaytype) ? 0xef         /* LCD/BOTH */
                                       : 0xe3);       /* CRT      */
            switch (bWDRefresh640)
            {
              case 0:                 /* 60Hz*/
                RefreshValue = 0x0d;
                break;

              default:                /* 72Hz or 75Hz */
                RefreshValue = ((Displaytype) ? 0x0d      /* LCD/BOTH */
                                              : 0x1d);    /* CRT      */
                break;
            }
            vvOutput(hvdm, &pleMiscOutWrite, MiscValue);  /* set Misc */
            vvOutput(hvdm, &pleSEQIndx, 0x31);
            vvOutput(hvdm, &pleSEQData, RefreshValue);    /* set clock*/
         }                            /* end 640x480x16/256/64K test  */
      }                               /* end text/graphics test       */

      else if ((pvd->vvMode.vvm_nCols == 800) &&   /* 800 res  @V3.0YEE02 */
               (pvd->vvMode.vvm_nBitCount == 8))   /* 256 colors */
      {
         /* 800x600x256: 3c2h  3c4.31h | 3c2h   3c4.31h  */
         /*                  60 Hz     |     72Hz        */
         /*  --------------------------|---------------- */
         /*  LCD/BOTH    23h     15h   | 23h      15h    */
         /*  CRT         23h     15h   | 27h      15h    */

         if (bWDRefresh800 == 0x01)          /*72Hz*/
         {
             MiscValue = ((Displaytype) ? 0x23         /* LCD/BOTH */
                                        : 0x27);       /* CRT      */
             vvOutput(hvdm, &pleMiscOutWrite, MiscValue);  /* set Misc */
         }
//       vvOutput(hvdm, &pleSEQIndx, 0x31);
//       vvOutput(hvdm, &pleSEQData, RefreshValue);   /* set clock*/
      }

      vvOutput(hvdm, &pleSEQIndx, SaveSEQIndx);        /*restore index @V3.0YEE03*/
      vvOutput(hvdm, &pleCRTIndx, SaveCRTIndx);        /*restore index @V3.0YEE04*/
   }                                  /* end Thinkpad SVGA LCD test   */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvWDRestoreIoState()
 *
 * DESCRIPTION   = Do adapter-specific register restores that can't be
 *                 handled in the usual way.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvWDRestoreIoState(                              /*          */
  HVDM hvdm )
{
  BYTE Displaytype;                                             /*@V3.0YEE01*/
  BYTE RefreshValue, MiscValue;                                 /*@V3.0YEE01*/
  /*
  ** Check for Diamond SpeedStar (external clock)
  */
//if (!(pVDMData(hvdm)->flVDMXVideo & VDMX_INTRESTOREFGND) &&   /*          */
  if (!(pVDMData(hvdm)->flVDMXVideo & VDMX_INTRESTOREFGND))     /*          */
  {
    if (sOEMData.Manufacturer == DIAMOND_MANUFACTURER )         /*          */
    {                                                           /*          */
      SETDIAMONDCLK( hvdm,                                      /*          */
                     pVDMData(hvdm)->ulBIOSMode,                /*          */
                     pVDMData(hvdm)->vvMode.vvm_nBitCount );    /*          */
    } /* endif */                                               /*          */

    else if (sOEMData.Manufacturer == THINKPAD_MANUFACTURER)    /*@V3.0YEE01*/
      ThinkpadFixClock(hvdm);                                   /*@V3.0YEE02*/
  }
  vvAcceleratorRestoreIOState( hvdm );                          /*          */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvWDSetBank()
 *
 * DESCRIPTION   = Set Western Digital bank register
 *
 *                 Only use Bank Register PR0A because we set up Single Bank
 *                 mode first.  The register has 4k granularity, so adjust
 *                 to 64k.  Registers must be unlocked before we get here.
 *
 * INPUT         = hvdm
 *                 ulBank
 *                 fSetWriteBank
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvWDSetBank(
  HVDM hvdm,
  ULONG ulBank,
  BOOL fSetWriteBank )
{
  register BYTE bBank,bTmp;
  PVDMDATA pvd = pVDMData(hvdm);
  register BYTE bGDCIndex, bSEQIndex;                           /*          */

                                        /* First set up for Single Bank Mode*/
  fSetWriteBank;                        /* shut compiler up   */
  bSEQIndex = vvInput( hvdm,
                       &pleSEQIndx );   /* save SEQ index     *//*          */
  vvOutput( hvdm,
            &pleSEQIndx,                                        /*          */
            0x11 );                     /* Sys Interface reg  */
  bTmp = vvInput( hvdm,
                  &pleSEQData )         /* get current value  *//*          */
         & 0x7f;                        /* clear bit 7        */
  vvOutput( hvdm,
            &pleSEQData,                                        /*          */
            bTmp );                     /* restore register   */
  bBank = (BYTE)((ulBank & 0x10) << 2); /* Get bank hi bit    *//*          */
  vvOutput( hvdm,
            &pleSEQIndx,                                        /*          */
            0x14 );                     /* Get PR34           *//*          */
  bTmp = vvInput( hvdm,
                  &pleSEQData )         /* get current value  *//*          */
         & ~ 0x40                       /* clear bit 6        *//*          */
         | bBank;                                               /*          */
  vvOutput( hvdm,
            &pleSEQData,                                        /*          */
            bTmp );                     /* restore register   *//*          */
  vvOutput( hvdm,
            &pleSEQIndx,
            bSEQIndex );                /* restore SEQ index  *//*          */
  bGDCIndex = vvInput( hvdm,
                       &pleGDCIndx );   /* save GDC index     *//*          */
  vvOutput( hvdm,
            &pleGDCIndx,                                        /*          */
            0x0b );                     /* Fix Memory Size reg*/
  bTmp = vvInput( hvdm,
                  &pleGDCData )         /* disable PR0B       *//*          */
         & 0xf7;                        /* clear bit 3        */
  vvOutput( hvdm,
            &pleGDCData,                                        /*          */
            bTmp);                      /* restore register   */
                                        /* Now set the Bank   */
  bBank = (BYTE)ulBank << 4;            /* adjust for 64k     */
  vvOutput( hvdm,
            &pleGDCIndx,                                        /*          */
            0x09);                      /* index PR0A         */
  vvOutput( hvdm,
            &pleGDCData,                                        /*          */
            bBank);                     /* set the bank       */
  vvOutput( hvdm,
            &pleGDCIndx,
            bGDCIndex);                 /* restore GDC index  *//*          */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvWDGetBank()
 *
 * DESCRIPTION   = Get Western Digital bank register
 *
 *
 * INPUT         = hvdm
 *                 fGetWriteBank
 *
 * OUTPUT        = ulBank
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

ULONG PRIVENTRY vvWDGetBank(
  HVDM hvdm,
  BOOL fGetWriteBank )
{
  BYTE bBankLo, bBankHi;                                        /*          */
  register BYTE bGDCIndex;                                      /*          */
  register BYTE bSEQIndex;                                      /*          */
  BOOL bPrevUnlock;                                             /*          */

  fGetWriteBank;                                 /* shut the compiler up    */

  /* Add locks again, but this time, PUSH! */                   /*          */
  bPrevUnlock = vvSVGALockPushState( hvdm );                    /*          */
  /* vvSVGAUnLockRegisters(); */                                /*          */
  bGDCIndex = vvInput( hvdm,
                       &pleGDCIndx );   /* save GDC index */    /*          */
  vvOutput( hvdm,
            &pleGDCIndx,                                        /*          */
            0x09 );                     /* index PR0A   */
  bBankLo = vvInput( hvdm,
                     &pleGDCData );     /* get the bank */      /*          */
  vvOutput( hvdm,
            &pleGDCIndx,
            bGDCIndex );                /* restore GDC index */ /*          */
  bSEQIndex = vvInput( hvdm,
                       &pleSEQIndx );   /* save SEQ index */    /*          */
  vvOutput( hvdm,
            &pleSEQIndx,                                        /*          */
            0x14 );                     /* index PR34   */      /*          */
  bBankHi = vvInput( hvdm,
                     &pleSEQData );     /* get the bank bits */ /*          */
  vvOutput( hvdm,
            &pleSEQIndx,
            bSEQIndex );                /* restore SEQ index */ /*          */
  /* Add locks again, but this time, POP! */                    /*          */
  vvSVGALockPopState( hvdm, bPrevUnlock );                      /*          */
  return( (ULONG) (((bBankLo >> 4) & 0x0f)                      /*          */
                   | ((bBankHi & 0x40) >> 2)) );                /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDFixSetMode()
 *
 * DESCRIPTION   = Fix up registers based on the mode set
 *
 *                 This subroutine fixes up various register states
 *                 after an int 10 set mode request completes.
 *                 Usually this is to fix BIOS bugs.
 *
 *                 This routine must get called before vvUpdateAll.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvSVGAFixSetMode
 *
 ****************************************************************************/

VOID PRIVENTRY vvWDFixSetMode(
  HVDM hvdm,
  ULONG ulMode )
{
  BYTE bIndex;                                                  /*          */
  BYTE bTmp;                                      /*          *//*          */
  register PVDMDATA pvd = pVDMData(hvdm);                       /*          */

  /* Similar code should probably be in SVGA.EXE */             /*          */
  /* in PostProcessModeSet */                                   /*          */

  /* Why not do this one for all adapters? */                   /*          */
  if((ulMode <= 0x13 ) && !(pvd->flVDMXVideo & VDMX_INT2F))     /*          */
  {
    vvSVGACleanup( hvdm, TRUE );                                /*          */

    if (sOEMData.Manufacturer == THINKPAD_MANUFACTURER)         /*@V3.0YEE02*/
      ThinkpadFixClock(hvdm);                                   /*@V3.0YEE02*/
  }

  if( ulSVGAChipType >= WESTERNDIG_WD9026_CHIP )                /*          */
  {                                                             /*          */
    /* In case we are background,                             *//*          */
    /* Fixup improperly shadowed indexed word ports           *//*          */
    /* In particular, ones which cause the black cursor bar   *//*          */
    /* Turn cursor on but move off screen to the right        *//*          */
    /* Turn hardware cursor on (off screen) */                  /*          */
    /* Except on mono panels where it does not work right */    /*          */
    pvd->VdmSVGA.wRegShadow [WD_WREGS_BASE + 0x20] =            /*          */
      ((((ulSVGAChipType == WESTERNDIG_WD9024_CHIP)             /*          */
         || (ulSVGAChipType == WESTERNDIG_WD9026_CHIP)          /*          */
         || (ulSVGAChipType == WESTERNDIG_WD9027_CHIP))         /*          */
        && !(pvd->aregCRTData [0x3e] & 0x20)) /* mono */        /*          */
       ? 0x0a00                                                 /*          */
       : 0x0200);                                               /*          */
    pvd->VdmSVGA.wRegShadow [WD_WREGS_BASE + 0x21] = 0x1000;    /*          */
    pvd->VdmSVGA.wRegShadow [WD_WREGS_BASE + 0x22] = 0x2000;    /*          */
    if( ulSVGAChipType < WESTERNDIG_WD9033_CHIP )               /*          */
    {                                                           /*          */
      pvd->VdmSVGA.wRegShadow [WD_WREGS_BASE + 0x26] = 0x67c0;  /*          */
      pvd->VdmSVGA.wRegShadow [WD_WREGS_BASE + 0x27] = 0x7000;  /*          */
    }                                                           /*          */
    {                                                           /*          */
      pvd->VdmSVGA.wRegShadow [WD_WREGS_BASE + 0x2d] = 0xd7c0;  /*          */
      pvd->VdmSVGA.wRegShadow [WD_WREGS_BASE + 0x2e] = 0xe000;  /*          */
    }                                                           /*          */
  }                                                             /*          */
  if( ulSVGAChipType <= WESTERNDIG_WD9031_CHIP )                /*          */
  {                                                             /*          */
    /*
    ** On WD adapters, in 132 column mode,
    ** font gets damaged while being restored
    ** due to a hardware problem.
    ** On WD's suggestion,
    ** the VRAM is being put into the 8 bit mode,
    ** in order to fix it.
    **/
    bIndex = vvInput( hvdm,
                      &pleCRTIndx );    /* save CRT index */    /*          */
    vvOutput( hvdm,
              &pleCRTIndx,
              REG_CRTHORZDSPEND );                              /*          */
    /* Get logical line length */                               /*          */
    bTmp = vvInput( hvdm,
                    &pleCRTData ) + 0x01;                       /*          */
    vvOutput( hvdm,
              &pleCRTIndx,
              bIndex );                 /* restore CRT index */ /*          */
    if( bTmp > 80 )                                             /*          */
    {
      bIndex = vvInput( hvdm,
                        &pleGDCIndx );  /* save SEQ index */    /*          */
      vvOutput( hvdm,
                &pleGDCIndx,
                0x0b );
      /* put VRAM into 8 bit mode */
      bTmp = vvInput( hvdm,
                      &pleGDCData )
             & ~ 0x04;                                          /*          */
      vvOutput( hvdm,                                           /*          */
                &pleGDCData,                                    /*          */
                bTmp );                                         /*          */
      if( ulSVGAChipType == WESTERNDIG_WD9011_CHIP )            /*          */
      {                                                         /*          */
        /* On Westinghouse 90c11, Write buffer should */        /*          */
        /* Write buffer should be disabled 3c5,11(2). */        /*          */
        /* Causes font corruption in 132 modes */               /*          */
        vvOutput( hvdm,                                         /*          */
                  &pleGDCIndx,                                  /*          */
                  0x11 );                                       /*          */
        /* put VRAM into 8 bit mode */                          /*          */
        bTmp = vvInput( hvdm,                                   /*          */
                        &pleGDCData )                           /*          */
               & ~ 0x04;                                        /*          */
        vvOutput( hvdm,                                         /*          */
                  &pleGDCData,                                  /*          */
                  bTmp );                                       /*          */
      }                                                         /*          */
      vvOutput( hvdm,
                &pleGDCIndx,
                bIndex );               /* restore SEQ index*/  /*          */
    }
  }                                                             /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvWDFixSetBgnd()
 *
 * DESCRIPTION   = Fix WD Registers
 *
 * INPUT         = HVDM
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvSVGAFixSetBgnd
 *
 **************************************************************************/

VOID PRIVENTRY vvWDFixSetBgnd(
  HVDM hvdm )
{
  hvdm;
}

/***************************************************************************
 *
 * FUNCTION NAME = vvWDWriteGDCData()
 *
 * DESCRIPTION   = Do gymnastics associated with emulating the
 *                 Western Digital GDC regs in the background.
 *
 * INPUT         = bNewValue = new GDC reg value
 *
 * OUTPUT        = Appropriate GDC data value in shadow updated
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvWriteGDCDataFgnd
 *      vvWriteGDCDataBgnd
 *
 **************************************************************************/

VOID PRIVENTRY vvWDWriteGDCData(
  BYTE bNewValue )
{
  if( (VDMData.regGDCIndx == 0x09)
      && !(VDMData.flVDMVideo & VDM_FGND)                       /*          */
      && (VDMData.mstateVideo == MEMORY_GRFX256)
      && !(VDMData.flVDMXVideo & VDMX_INT2F))                   /*          */
  {
    VDMData.ulDirtyBankEvent = VDMData.aregGDCData [0x09] >> 4; /*@V3.0MNH03*/
    /*
    ** Shadow before mapping, in case mapping causes a freeze.
    */                                                          /*          */
    VDMData.aregGDCData [0x09] = bNewValue;                     /*@V3.0MNH03*/
    vvMapBank( bNewValue >> 4);                                 /*          */
  }
  VDMData.aregGDCData [VDMData.regGDCIndx] = bNewValue;         /*@V3.0MNH03*/
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteWRegByteL()
 *
 * DESCRIPTION   = Write low byte of accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the lower half of an accelerator word
 *                 register.
 *
 * INPUT         = bLow == output data
 *                 port == port address to write
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteWRegByteL(
  BYTE bData,
  ULONG port,
  PCRF pcrf)
{
  vvAcceleratorWrite( &psCurAcceleratorInfo->
                        psAcceleratorTrapRegInfo
                          [psCurAcceleratorInfo->
                            puifnAcceleratorPortIndex( port )],
                      &sTrapWRegLow,
                      (PVOID) SSToDS( &bData ),
                      FALSE );          /* Not a command */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteWRegByteH()
 *
 * DESCRIPTION   = Write high byte of accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the upper half of an accelerator word
 *                 register.
 *
 * INPUT         = bHigh == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteWRegByteH(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  vvAcceleratorWrite( &psCurAcceleratorInfo->
                        psAcceleratorTrapRegInfo
                          [psCurAcceleratorInfo->
                            puifnAcceleratorPortIndex( port )],
                      &sTrapWRegHigh,
                      (PVOID) SSToDS( &bData ),
                      FALSE );          /* Not a command */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteWRegWord()
 *
 * DESCRIPTION   = Write accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to an accelerator word register.
 *
 * INPUT         = wData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteWRegWord(
  WORD wData,
  ULONG port,
  PCRF pcrf )
{
  vvAcceleratorWrite( &psCurAcceleratorInfo->
                        psAcceleratorTrapRegInfo
                          [psCurAcceleratorInfo->
                            puifnAcceleratorPortIndex( port )],
                      &sTrapWRegWhole,
                      (PVOID) SSToDS(  &wData ),
                      FALSE );          /* Not a command */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteIndxAdjust()
 *
 * DESCRIPTION   = Adjust write accelerator index register
 *
 * INPUT         = wData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31WriteIndxAdjust( VOID )
{
  VDMData.VdmSVGA.wRegShadow [WD_WREGS_INDEX] &=
    ~WD_INDX_BLKINVALID;                /* Clear invalid register block */
  if( BYTEOF( VDMData.VdmSVGA.wRegShadow [WD_WREGS_INDEX], 0 )
      > ((ulSVGAChipType >= WESTERNDIG_WD9033_CHIP)
         ? 0x03
         : 0x02) )                     /* If block index out of range: */
    VDMData.VdmSVGA.wRegShadow [WD_WREGS_INDEX] |=
      WD_INDX_BLKINVALID;               /* Indicate invalid register block */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteIndxByteL()
 *
 * DESCRIPTION   = Write low byte of accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the lower half of the accelerator
 *                 index register.
 *
 * INPUT         = bLow == output data
 *                 port == port address to write
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteIndxByteL(
  BYTE bData,
  ULONG port,
  PCRF pcrf)
{
  vvAcceleratorWrite( &psCurAcceleratorInfo->
                        psAcceleratorTrapRegInfo
                          [WD_WREGS_INDEX],
                      &sTrapWRegLow,
                      (PVOID) SSToDS( &bData ),
                      FALSE );          /* Not a command */
  vvWDC31WriteIndxAdjust();
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteIndxByteH()
 *
 * DESCRIPTION   = Write high byte of accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the upper half of the accelerator
 *                 index register.
 *
 * INPUT         = bHigh == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteIndxByteH(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  vvAcceleratorWrite( &psCurAcceleratorInfo->
                        psAcceleratorTrapRegInfo
                          [WD_WREGS_INDEX],
                      &sTrapWRegHigh,
                      (PVOID) SSToDS( &bData ),
                      FALSE );          /* Not a command */
  vvWDC31WriteIndxAdjust();
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteIndxWord()
 *
 * DESCRIPTION   = Write accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a word to the accelerator index register.
 *
 * INPUT         = wData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteIndxWord(
  WORD wData,
  ULONG port,
  PCRF pcrf )
{
  vvAcceleratorWrite( &psCurAcceleratorInfo->
                        psAcceleratorTrapRegInfo
                          [WD_WREGS_INDEX],
                      &sTrapWRegWhole,
                      (PVOID) SSToDS( &wData ),
                      FALSE );          /* Not a command */
  vvWDC31WriteIndxAdjust();
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31ReadDataIndx()
 *
 * DESCRIPTION   = Get index for read of an accelerator data register
 *
 * INPUT         =
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

UINT    PRIVENTRY vvWDC31ReadDataIndx( VOID )
{
  WORD wNextIndex;                                              /*@V3.0MNH03*/
  register UINT uiUsedIndex;

  wNextIndex = VDMData.VdmSVGA.wRegShadow [WD_WREGS_INDEX];
/*
**      Bit Pattern Was:
**              15:14 Reserved
**              13:13 Invalid Register Block (read only)
**              12:12 Auto Increment Disable
**              11:08 Register Index
**              07:00 Register Block Pointer
*/
  uiUsedIndex =
    BYTEOF (wNextIndex, 1) & 0x0f;      /* Get register index */
  if( uiUsedIndex == WD_INDX_INDX )     /* If reading index register: */
  {
    BYTEOF( wNextIndex, 1 ) |=                                  /*@V3.0MNH03*/
      WD_INDX_INDX << WD_INDX_SHIFT;                            /*@V3.0MNH03*/
    VDMData.VdmSVGA.wRegShadow [WD_WREGS_BASE + WD_INDX_INDX] =
      wNextIndex;                       /* Make dummy reg     *//*@V3.0MNH03*/
  }
  else if( wNextIndex & WD_INDX_BLKINVALID ) /* If invalid reg block: */
  {
    BYTEOF( wNextIndex, 1 ) =                                   /*@V3.0MNH03*/
      (BYTE) (uiUsedIndex << WD_INDX_SHIFT);                    /*@V3.0MNH03*/
    BYTEOF( wNextIndex, 0 ) = 0;                                /*@V3.0MNH03*/
    VDMData.VdmSVGA.wRegShadow [WD_WREGS_BASE + WD_INDX_INDX] =
      wNextIndex;                       /* Make dummy reg     *//*@V3.0MNH03*/
    uiUsedIndex = WD_INDX_INDX;         /* Point to it as well */
  }
  else
    uiUsedIndex |=                                              /*@V3.0MNH03*/
      BYTEOF( wNextIndex, 0 ) << WD_BLK_SHIFT; /* Add block # *//*@V3.0MNH03*/
  uiUsedIndex += WD_WREGS_BASE;                                 /*@V3.0MNH03*/
  if( !(wNextIndex & WD_INDX_NOAUTO) ) /* If auto increment: */
  {
    /*
    ** Microsoft Compiler error:
    ** Incorrectly optimizes this equivalent expression
    ** wNextIndex += 0x0100;
    ** into oblivion when followed by the AND (&) expression
    ** which follows it.
    ** So we use BYTEOF( wNextIndex, 1)++; instead.
    */
    BYTEOF( wNextIndex, 1)++;   /* Increment register index */  /*@V3.0MNH03*/
    wNextIndex &=                                               /*@V3.0MNH03*/
      ~ WD_INDX_NOAUTO;         /* But prevent overrun & keep auto */
    VDMData.VdmSVGA.wRegShadow
      [WD_WREGS_INDEX] =        /* Update register index */
        wNextIndex;                                             /*@V3.0MNH03*/
  }
  return( uiUsedIndex );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31ReadDataByteL()
 *
 * DESCRIPTION   = Read low byte of an accelerator data register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads a byte from the lower half of the accelerator
 *                 data register.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

BYTE    HOOKENTRY vvWDC31ReadDataByteL(
  ULONG port,
  PCRF pcrf )
{
  STRAPREGINFO sTrapRegInfo;
  BYTE bData;

  sTrapRegInfo.portTrap = port;
  sTrapRegInfo.pvTrapReadShadow =
    (PVOID) &(VDMData.VdmSVGA.wRegShadow [vvWDC31ReadDataIndx()]);
  sTrapRegInfo.piohTrap = iohWDC31data;
  vvAcceleratorRead( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                     &sTrapWRegLow,
                     (PVOID) SSToDS( &bData ) );
  return( bData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31ReadDataByteH()
 *
 * DESCRIPTION   = Read high byte of accelerator data register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads a byte from the upper half of the accelerator
 *                 data register.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

BYTE    HOOKENTRY vvWDC31ReadDataByteH(
  ULONG port,
  PCRF pcrf)
{
  STRAPREGINFO sTrapRegInfo;
  BYTE bData;

  sTrapRegInfo.portTrap = port;
  sTrapRegInfo.pvTrapReadShadow =
    (PVOID) &(VDMData.VdmSVGA.wRegShadow [vvWDC31ReadDataIndx()]);
  sTrapRegInfo.piohTrap = iohWDC31data;
  vvAcceleratorRead( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                     &sTrapWRegHigh,
                     (PVOID) SSToDS( &bData ) );
  return( bData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31ReadDataWord()
 *
 * DESCRIPTION   = Read accelerator data register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads from the accelerator data register.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

WORD    HOOKENTRY vvWDC31ReadDataWord(
  ULONG port,
  PCRF pcrf )
{
  STRAPREGINFO sTrapRegInfo;
  WORD wData;

  sTrapRegInfo.portTrap = port;
  sTrapRegInfo.pvTrapReadShadow =
    (PVOID) &(VDMData.VdmSVGA.wRegShadow [vvWDC31ReadDataIndx()]);
  sTrapRegInfo.piohTrap = iohWDC31data;
  vvAcceleratorRead( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                     &sTrapWRegWhole,
                     (PVOID) SSToDS( &wData ) );
  return( wData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteDataIndx()
 *
 * DESCRIPTION   = Get index for write of an accelerator data register
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

UINT    PRIVENTRY vvWDC31WriteDataIndx(
  WORD wData )
{
  WORD wNextIndex;                                              /*@V3.0MNH03*/
  register UINT uiUsedIndex;

  wNextIndex = VDMData.VdmSVGA.wRegShadow [WD_WREGS_INDEX];
/*
**      Bit Pattern Was:
**              15:14 Reserved
**              13:13 Invalid Register Block (read only)
**              12:12 Auto Increment Disable
**              11:08 Register Index
**              07:00 Register Block Pointer
*/
  uiUsedIndex = BYTEOF( wNextIndex, 1 ) >> WD_INDX_SHIFT;       /*@V3.0MNH03*/
  if( uiUsedIndex == WD_INDX_INDX )     /* If setting index register: */
  {
    VDMData.VdmSVGA.wRegShadow [WD_WREGS_INDEX] =
      (WORD)                                                    /*@V3.0MNH03*/
      ((wNextIndex & WD_INDX_NOAUTO)    /* Keep auto increment*/
       | (wData & ~ WD_INDX_MASK));     /* Use new index&blk  *//*@V3.0MNH03*/
    vvWDC31WriteIndxAdjust();
  }
  else if( wNextIndex & WD_INDX_BLKINVALID ) /* If invalid reg block: */
    uiUsedIndex = WD_INDX_INDX;         /* Point dummy reg */
  else
    uiUsedIndex |=                                              /*@V3.0MNH03*/
      BYTEOF( wNextIndex, 0 ) << WD_BLK_SHIFT; /* Add block # *//*@V3.0MNH03*/
  uiUsedIndex += WD_WREGS_BASE;                                 /*@V3.0MNH03*/
  return( uiUsedIndex );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31IsCmd()
 *
 * DESCRIPTION   = Check to see if write is an accelerator command.
 *
 * INPUT         =
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

BOOL    PRIVENTRY vvWDC31IsCmd(
  UINT uiUsedIndex,
  WORD wData )
{
/*
**          Check for:
**          < WD90C33
**          Block 01 Index 0 Bit 800 ON = BITBLT Start/In Progress.
**          Block 01 Index 4 Bit fff ON = BITBLT Destination Low
**          Block 01 Index 2 Bit fff ON = BITBLT Source Low.
**          Block 01 Index 1 Bit 080 ON = BITBLT Quick Start.
**          Block 01 Index 1 Bit 040 ON = BITBLT Auto Update Destination.
**          >= WD90C33
**          Block 01 Index 0 Bit e00 ON = ENGINE non-NOP.
*/
  return( (ulSVGAChipType < WESTERNDIG_WD9033_CHIP)
          ? ((uiUsedIndex == (WD_WREGS_BASE + 0x10))
             && (wData & 0x0e00))       /* ENGINE non-NOP. */
          : ((uiUsedIndex == (WD_WREGS_BASE + 0x10))
             && (wData & 0x0800))       /* BITBLT Start/In Progress */
            || ((VDMData.VdmSVGA.wRegShadow [(WD_WREGS_BASE + 0x10)]
                 & 0x80)                /* BITBLT Quick Start: */
                && ((uiUsedIndex == (WD_WREGS_BASE + 0x14))
                                        /* BITBLT Dest Low */
                    || ((uiUsedIndex == (WD_WREGS_BASE + 0x12))
                                        /* BITBLT Source Low */
                        && (VDMData.VdmSVGA.wRegShadow [(WD_WREGS_BASE + 0x11)]
                                        /* BITBLT Auto Update Dest: */
                            & 0x40)))) );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteDataByteL()
 *
 * DESCRIPTION   = Write low byte of accelerator data register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the lower half of the accelerator
 *                 data register.
 *
 * INPUT         = bLow == output data
 *                 port == port address to write
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteDataByteL(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  register UINT uiUsedIndex;
  STRAPREGINFO sTrapRegInfo;
  WORD wData;

  /* Get index from high byte write: */
  BYTEOF( VDMData.VdmSVGA.wRegShadow [WD_WREGS_DATA], 0 ) = bData;
  wData = VDMData.VdmSVGA.wRegShadow [WD_WREGS_DATA];
  uiUsedIndex = vvWDC31WriteDataIndx( wData );

  sTrapRegInfo.portTrap = port;
  sTrapRegInfo.pvTrapWriteShadow =
    (PVOID) &(VDMData.VdmSVGA.wRegShadow [WD_WREGS_BASE + WD_INDX_INDX]);
  sTrapRegInfo.piohTrap = iohWDC31data;
  vvAcceleratorWrite( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                      &sTrapWRegLow,
                      (PVOID) SSToDS( &bData ),
                      vvWDC31IsCmd( uiUsedIndex, wData ) );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteDataByteH()
 *
 * DESCRIPTION   = Write high byte of accelerator multi-function register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the upper half of the accelerator
 *                 multi-function register (ie, one of those listed under
 *                 A8514_MULTIFUNCTION).
 *
 * INPUT         = bHigh == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteDataByteH(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  register UINT uiUsedIndex;
  STRAPREGINFO sTrapRegInfo;
  WORD wData;

  BYTEOF( wData, 0 ) = 0;
  BYTEOF( wData, 1 ) = bData;
  uiUsedIndex = vvWDC31WriteDataIndx( wData );
  /* Save index for low byte write: */
  VDMData.VdmSVGA.wRegShadow [WD_WREGS_DATA] = wData;

  sTrapRegInfo.portTrap = port;
  sTrapRegInfo.pvTrapWriteShadow =
    (PVOID) &(VDMData.VdmSVGA.wRegShadow [uiUsedIndex]);
  sTrapRegInfo.piohTrap = iohWDC31data;
  vvAcceleratorWrite( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                      &sTrapWRegHigh,
                      (PVOID) SSToDS( &bData ),
                      vvWDC31IsCmd( uiUsedIndex, wData ) );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31WriteDataWord()
 *
 * DESCRIPTION   = Write accelerator multi-function register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the accelerator multi-function register (ie, one
 *                 of those listed under A8514_MULTIFUNCTION).
 *
 * INPUT         = wData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvWDC31WriteDataWord(
  WORD wData,
  ULONG port,
  PCRF pcrf )
{
  register UINT uiUsedIndex;
  STRAPREGINFO sTrapRegInfo;

  uiUsedIndex = vvWDC31WriteDataIndx (wData);
  sTrapRegInfo.portTrap = port;
  sTrapRegInfo.pvTrapWriteShadow =
    (PVOID) &(VDMData.VdmSVGA.wRegShadow [uiUsedIndex]);
  sTrapRegInfo.piohTrap = iohWDC31data;
  vvAcceleratorWrite( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                      &sTrapWRegWhole,
                      (PVOID) SSToDS( &wData ),
                      vvWDC31IsCmd( uiUsedIndex, wData ) );
}

#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA

IOH iohWDC31wreg [2] =
{
  {
    vvA8514ReadWRegByteL, vvWDC31WriteWRegByteL,
    vvA8514ReadWRegWord,  vvWDC31WriteWRegWord,
    NULL,
  },
  {
    vvA8514ReadWRegByteH, vvWDC31WriteWRegByteH,
    NULL,                 NULL,
    NULL,
  },
};

IOH iohWDC31indx [2] =
{
  {
    vvA8514ReadWRegByteL, vvWDC31WriteIndxByteL,
    vvA8514ReadWRegWord,  vvWDC31WriteIndxWord,
    NULL,
  },
  {
    vvA8514ReadWRegByteH, vvWDC31WriteIndxByteH,
    NULL,                 NULL,
    NULL,
  }
};

IOH iohWDC31data [2] =
{
  {
    vvWDC31ReadDataByteL, vvWDC31WriteDataByteL,
    vvWDC31ReadDataWord,  vvWDC31WriteDataWord,
    NULL,
  },
  {
    vvWDC31ReadDataByteH, vvWDC31WriteDataByteH,
    NULL,                 NULL,
    NULL,
  },
};

#pragma  END_SWAP_DATA

#pragma  BEGIN_SWAP_CODE
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31PortIndex()
 *
 * DESCRIPTION   = Get index for write of an accelerator data register
 *
 * INPUT         = port
 *
 * OUTPUT        = table index for port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

UINT    PRIVENTRY vvWDC31PortIndex( PORT port )
{
  return( (port & 0x003e) >> 1 );                               /*          */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31OutputIndex()
 *
 * DESCRIPTION   = Output Index port value
 *
 *
 * INPUT         = pvd -> VDM data
 *                 port = port address
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31OutputIndex(                           /*          */
  wIndex )
{
  _asm
  {
    mov    dx, WD_INDEXPORT
    mov    ax, word ptr wIndex
    out    dx, ax
  }
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31InputData()
 *
 * DESCRIPTION   = Output Data port value
 *
 *
 * INPUT         = pvd -> VDM data
 *                 port = port address
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

WORD    PRIVENTRY vvWDC31InputData( VOID )                      /*          */
{
  WORD wData;

  _asm
  {
    mov    dx, WD_DATAPORT
    in     ax, dx
    mov    wData, ax
  }
  return( wData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31OutputData()
 *
 * DESCRIPTION   = Output Data port value
 *
 *
 * INPUT         = pvd -> VDM data
 *                 port = port address
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31OutputData(                            /*          */
  wData )
{
  _asm
  {
    mov    dx, WD_DATAPORT
    mov    ax, word ptr wData
    out    dx, ax
  }
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31UpdatePort()
 *
 * DESCRIPTION   = Transfer virtual I/O port state from hardware
 *
 *
 * INPUT         = pvd -> VDM data
 *                 port = port address
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31UpdatePort(
  HVDM hvdm,                                                    /*          */
  PORT port )
{
  /* Read word & copy into shadow storage for unindexed port  *//*          */
  vvInputWord( hvdm,                                            /*          */
               &psCurAcceleratorInfo->                          /*          */
                 psAcceleratorTrapRegInfo                       /*          */
                   [psCurAcceleratorInfo->                      /*          */
                      puifnAcceleratorPortIndex( port )] );     /*          */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31RestorePort()
 *
 * DESCRIPTION   = Transfer virtual I/O port state to hardware
 *
 *
 * INPUT         = pvd -> VDM data
 *                 port = port address
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31RestorePort(
  HVDM hvdm,                                                    /*          */
  PORT port )
{
  register PVDMDATA pvd = pVDMData(hvdm);                       /*          */
  WORD wData;

  wData = pvd->VdmSVGA.wRegShadow
            [psCurAcceleratorInfo->
              puifnAcceleratorPortIndex( port )];
  _asm
  {
    mov    dx, word ptr port
    mov    ax, wData
    out    dx, ax
  }
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31Chip()
 *
 * DESCRIPTION   = Has some type of accelerator chip
 *                 (means Chip exists, does not mean Chip active)
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      VVCreate (to decide whether to create semaphores)
 *      vvAcceleratorIsOn
 *      vvAcceleratorSetBgndOnlyHooks
 *      vvAcceleratorInstallIOHooks
 *      vvAcceleratorSetIOHooks
 *      vvAcceleratorUpdateIOState
 *      vvAcceleratorRestoreIOState
 *
 ***********************************************************************/
BOOL    PRIVENTRY vvWDC31Chip( VOID )
{
  return( ulSVGAChipType >= WESTERNDIG_WD9031_CHIP );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31IsOn()
 *
 * DESCRIPTION   = Is in accelerator mode
 *
 *                 This routine CAN assume
 *                 that there IS an accelerator chip
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorIsOn
 *
 ***********************************************************************/
BOOL    PRIVENTRY vvWDC31IsOn(
  HVDM hvdm )
{
  return( TRUE );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31Busy()
 *
 * DESCRIPTION   = Test for accelerator busy
 *
 * INPUT         = NONE
 *
 * OUTPUT        = TRUE if busy, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

BOOL    PRIVENTRY vvWDC31Busy(                                  /*          */
  HVDM hvdm )                                                   /*          */
{
  register PVDMDATA pvd = pVDMData(hvdm);                       /*          */
  WORD wData;
  register BOOL bTmp;
  PSTRAPREGINFO psTrapRegInfo;                                  /*          */

  if( ulSVGAChipType >= WESTERNDIG_WD9033_CHIP )
  {
    psTrapRegInfo =                                             /*          */
      &psCurAcceleratorInfo->                                   /*          */
        psAcceleratorTrapRegInfo                                /*          */
          [psCurAcceleratorInfo->       /* Cmd/Intrpt Ctl Reg *//*          */
             puifnAcceleratorPortIndex( WD_ENGINEPORT )];       /*          */
    wData = vvInputWord( hvdm,          /* Get Cmd Status */    /*          */
                         psTrapRegInfo );                       /*          */
    bTmp = ( wData & 0x0080 );
  }
  else
  {
    vvWDC31UpdatePort( hvdm,                                    /*          */
                       WD_INDEXPORT );                          /*          */
    vvWDC31OutputIndex( 0x0001 );       /* Set Blk 1 Idx 0 */   /*          */
    wData =                                                     /*          */
      pvd->VdmSVGA.wRegShadow [(WD_WREGS_BASE + 0x10)] =
        vvWDC31InputData();             /* BITBLT Ctrl Part 1 *//*          */
    vvWDC31RestorePort( hvdm,                                   /*          */
                        WD_INDEXPORT );                         /*          */
    bTmp = ( wData & 0x0800 );          /* Test BITBLT in progess */
  }
  return( bTmp );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31Reset()
 *
 * DESCRIPTION   = Force the accelerator to be UNbusy, if possible.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = TRUE if busy, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorWaitOnEngine
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31Reset(
  HVDM hvdm  )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  WORD wData;
  PSTRAPREGINFO psTrapRegInfo;                                  /*          */

  /*
  ** Being here means that the engine is still not free.
  ** The application may have trapped in its engine servicing code
  ** or it trashed the engine beyond belief.
  ** The reset we are attempting is not guaranteed to work,
  ** but this is the best we can do.
  */
  if( ulSVGAChipType >= WESTERNDIG_WD9033_CHIP )
  {
    psTrapRegInfo =                                             /*          */
      &psCurAcceleratorInfo->                                   /*          */
        psAcceleratorTrapRegInfo                                /*          */
          [psCurAcceleratorInfo->       /* Cmd/Intrpt Ctl Reg *//*          */
             puifnAcceleratorPortIndex( WD_ENGINEPORT )];       /*          */
    wData =
      pvd->VdmSVGA.wRegShadow [WD_WREGS_ENGINE]
      | 0x0080;                         /* Abort DE and Dump Cmd Buffer */
    vvOutputWord( INVALID_HVDM,                                 /*          */
                  psTrapRegInfo,                                /*          */
                  wData );              /* Reset data */        /*          */
  }
  else
  {
    vvWDC31UpdatePort( hvdm,                                    /*          */
                       WD_INDEXPORT );                          /*          */
    vvWDC31OutputIndex( 0x0001 );       /* Set Blk 1 Idx 0 */   /*          */
    vvWDC31OutputData(                  /* BITBLT Ctrl Part 1 *//*          */
      pvd->VdmSVGA.wRegShadow [(WD_WREGS_BASE + 0x10)]
        | 0x0800 );                     /* Abort BITBLT */
    vvWDC31RestorePort( hvdm,                                   /*          */
                        WD_INDEXPORT );                         /*          */
  }
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31UpdateScreenState()
 *
 * DESCRIPTION   = Modify screen state for special cases
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorUpdateScreenState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31UpdateScreenState(
  HVDM hvdm )
{
  /* Nothing to do! */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31UpdateIOState()
 *
 * DESCRIPTION   = Transfer hardware I/O state to virtual
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31UpdateIoState(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  PORT port;
  register UINT uiIndex;
  UINT uiBlock;

  /* This C24 reg is unreadable under certain circumstances */  /*          */
  pvd->aregCRTData [0x30] = 0x40;                               /*          */
  /* Get current index reg */
  vvWDC31UpdatePort( hvdm,                                      /*          */
                     WD_INDEXPORT );
  for (uiBlock = 0x00;
       uiBlock <= ((ulSVGAChipType >= WESTERNDIG_WD9033_CHIP)
                   ? 0x03
                   : 0x02);
       uiBlock++)
  {
    vvWDC31OutputIndex( uiBlock );      /* Set Block & Idx 0 */ /*          */
    for (uiIndex = 0;
         uiIndex <= 0x0f;
         uiIndex++)
      pvd->VdmSVGA.wRegShadow
        [WD_WREGS_BASE + (uiBlock << WD_BLK_SHIFT) + uiIndex] =
          vvWDC31InputData();                                   /*          */
  } /* endfor */
  vvWDC31RestorePort( hvdm,             /* Restore index */     /*          */
                      WD_INDEXPORT );                           /*          */
  /* WD_BITBLTPORT is write once/read once! do not restore! */
  for (port = WD_K1PORT;
       port <= ((ulSVGAChipType >= WESTERNDIG_WD9033_CHIP)
                ? WD_ENGINEPORT
                : WD_ETPORT);
       port += 0x0002)
    vvWDC31UpdatePort( hvdm,                                    /*          */
                       port );
  vvWDC31UpdatePort( hvdm,                                      /*          */
                     0x2de0 );
  vvWDC31UpdatePort( hvdm,                                      /*          */
                     0x2de2 );
  vvWDC31UpdatePort( hvdm,                                      /*@V3.0MNH03*/
                     0x2df0 );                                  /*@V3.0MNH03*/
  vvWDC31UpdatePort( hvdm,                                      /*@V3.0MNH03*/
                     0x2df2 );                                  /*@V3.0MNH03*/
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31RestoreIoState()
 *
 * DESCRIPTION   = Transfer virtual I/O state to hardware
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31RestoreIoState(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  WORD wData;
  PORT port;
  register UINT uiIndex;
  UINT uiBlock;

  /* This C24 reg is unreadable under certain circumstances */  /*          */
  pvd->aregCRTData [0x30] = 0x40;                               /*          */
  /* WD_BITBLTPORT is write once/read once! do not restore! */
  for (port = WD_K1PORT;
       port <= ((ulSVGAChipType >= WESTERNDIG_WD9033_CHIP)
                ? WD_ENGINEPORT
                : WD_ETPORT);
       port += 0x0002)
    vvWDC31RestorePort( hvdm,                                   /*          */
                        port );
  vvWDC31RestorePort( hvdm,                                     /*          */
                      0x2de0 );
  vvWDC31RestorePort( hvdm,                                     /*          */
                      0x2de2 );
  vvWDC31RestorePort( hvdm,                                     /*@V3.0MNH03*/
                      0x2df0 );                                 /*@V3.0MNH03*/
  vvWDC31RestorePort( hvdm,                                     /*@V3.0MNH03*/
                      0x2df2 );                                 /*@V3.0MNH03*/
  /* Command activation should already be off, but just in case.. */
  vvWDC31OutputIndex( 0x0001 );         /* Set Blk 1 Idx 0 */   /*          */
  if( ulSVGAChipType >= WESTERNDIG_WD9033_CHIP )
    vvWDC31OutputData(                                          /*          */
      pvd->VdmSVGA.wRegShadow [(WD_WREGS_BASE + 0x10)] &=
        ~ 0x0e00 );                     /* NOOP command */
  else
  {                                                             /*          */
    vvWDC31OutputData(                                          /*          */
      pvd->VdmSVGA.wRegShadow [(WD_WREGS_BASE + 0x10)] &=
        ~ 0x0800 );                     /* No Activation */
    vvWDC31OutputData(                                          /*          */
      /* Do not change shadow though */                         /*          */
      pvd->VdmSVGA.wRegShadow [(WD_WREGS_BASE + 0x11)] &        /*          */
        ~ 0x0080 );                     /* No Quick Start */    /*          */
  }                                                             /*          */
  for (uiBlock = 0x00;
       uiBlock <= ((ulSVGAChipType >= WESTERNDIG_WD9033_CHIP)
                   ? 0x03
                   : 0x02);
       uiBlock++)
  {
    vvWDC31OutputIndex( uiBlock );      /* Set Block & Idx 0 */ /*          */
    for (uiIndex = 0;
         uiIndex <= 0x0f;
         uiIndex++)
    {
      wData = pvd->VdmSVGA.wRegShadow
                [WD_WREGS_BASE + (uiBlock << WD_BLK_SHIFT) + uiIndex];
      if( (uiIndex == 0x01)             /* BILBLT Ctrl Part 2 */
          && (uiBlock == 0x01)          /* BITBLT/DRAWING ENGINE */
          && (ulSVGAChipType < WESTERNDIG_WD9033_CHIP) ) /* No Quick Start! */
        wData &= ~0x0080;               /* Else restoring dest starts BITBLT! */
      vvWDC31OutputData( wData );       /* Set Indexed Reg *    /*          */
    } /* endfor */
  } /* endfor */
  if( ulSVGAChipType < WESTERNDIG_WD9033_CHIP )
  {
    /* BITBLT Control Part 2 Real Quick Start: */
    vvWDC31OutputIndex( 0x0101 );       /* Set Blk 1 Idx 1 */   /*          */
    vvWDC31OutputData( pvd->VdmSVGA.wRegShadow                  /*          */
                         [(WD_WREGS_BASE + 0x11)] );            /*          */
                                        /* Set Indexed Reg *    /*          */
  }
  /* Since writes to Cursor Pattern Address or Cursor Origin, *//*          */
  /* do not take effect until the next write to Cursor        *//*          */
  /* Control, we need to write Cursor Control Last!           *//*          */
  vvWDC31OutputIndex( 0x0002 );         /* Set Blk 2 Idx 0 */   /*          */
  vvWDC31OutputData( pvd->VdmSVGA.wRegShadow                    /*          */
                       [(WD_WREGS_BASE + 0x20)] );              /*          */
  /* Get current index reg */
  vvWDC31RestorePort( hvdm,                                     /*          */
                      WD_INDEXPORT );
  /* WD_BITBLT port is write once/read once! do not restore! */
}

/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31AcceleratorCreate()                     @V3.0YEE01
 *
 * DESCRIPTION   = Set selective masks for restore
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorCreate
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31AcceleratorCreate(HVDM hvdm )
{
   /* these mask values were obtained from a PMI file mode set */
   /* REMEMBER:  if PMI changes, change this too !!            */
   /* These masks are to maintain the panel independent values */
   /* regardless of whether we are running on the LCD/CRT/BOTH.*/
   if ((ulSVGAChipType == WESTERNDIG_WD9024_CHIP) ||
       (ulSVGAChipType == WESTERNDIG_WD9026_CHIP) ||
       (ulSVGAChipType == WESTERNDIG_WD9027_CHIP))
   {
      abSEQMask[0x10] &= ~ 0x20;
      abSEQMask[0x12] &= ~ 0x04;
      abSEQMask[0x13] &= ~ 0x03;
      abSEQMask[0x21] &= ~ 0x07;
      abSEQMask[0x27] &= ~ 0x10;
      abSEQMask[0x29] &= ~ 0x0c;

      abCRTMask[0x2a] &= ~ 0x05;
      abCRTMask[0x2e] &= ~ 0x40;                  /*@V3.0YEE02*/
      abCRTMask[0x31] &= ~ 0x87;
      abCRTMask[0x32] &= ~ 0x7c;
      abCRTMask[0x33] &= ~ 0x61;
      abCRTMask[0x3a] &= ~ 0x02;
      abCRTMask[0x3c] &= ~ 0x3f;
      abCRTMask[0x3e] &= ~ 0xa7;

      abGDCMask[0x0b] &= ~ 0x00;
      abGDCMask[0x0c] &= ~ 0x01;
      abGDCMask[0x0e] &= ~ 0x60;
   }
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvWDC31Init()
 *
 * DESCRIPTION   = Initialize addressing of accelerator registers.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorCreate
 *
 ***********************************************************************/

VOID    PRIVENTRY vvWDC31Init(
  HVDM hvdm )
{
  /* Nothing to do.  Unless you want to initialize shadow to 0xffff's */
}

#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA

SACCELERATORINFO sWDC31Info =
{
  sWDC31TrapRegInfo,
  WDC31TRAPREGSIZE,
  &vvWDC31PortIndex,
  &vvWDC31Chip,
  &vvWDC31IsOn,
  &vvWDC31AcceleratorCreate,                        /*@V3.0YEE01            */
  NULL,                                                         /*          */
  &vvWDC31Busy,
  &vvWDC31Reset,
  &vvA8514InstallIoHooks,
  &vvA8514SetIoHooks,
  &vvA8514SetBgndOnlyHooks,
  &vvWDC31UpdateScreenState,
  &vvWDC31UpdateIoState,
  &vvWDC31RestoreIoState,
  &vvWDC31Init,
};

SSVGAINFO sWDAdapterInfo =                                      /*          */
{
  { /* SVGAINFO */                                              /*          */
    { /* SEGAINFO */
      { /* SCGAINFO */
        &vvEGAAdjustedPort,
        &vvWDStartAddr,
        &vvEGAOddEvenMode,
        &vvEGAHighResMode,
        &vvEGAHorzDspEnd,
        &vvEGAHorzLogEnd,                                       /*          */
        &vvWDVertDspEnd,
        &vvVGABitsPerPixel,
        &vvVGAPrepareSetMode,                                   /*          */
      },
      &vvEGAPackedMode,
      &vvWDVertLineCmp,
    },
    &vvVGADacSave,                                              /*          */
    &vvVGADacRestore,                                           /*          */
  },                                                            /*          */
  &vvWDEditTables,
  &vvWDInterlaced,
  &vvVGAUpdateIoState,
  &vvWDRestoreIoState,                                          /*          */
  &vvWDSetBank,
  &vvWDGetBank,
  &vvWDFixSetMode,
  &vvVGAFixSetBgnd,
  &vvWDWriteGDCData,                                            /*          */
  &vvVGAReadSEQDataBgnd,
  &vvVGAWriteSEQDataBgnd,
  &vvVGADacRS2Clear,                                            /*          */
  &vvVGADacRS2Set,                                              /*          */
  &vvVGADacRS3,                                                 /*          */
  &sWDC31Info,
  pszWDAdapterName,
  MAX_WESTERNDIG_CHIP,
  ppszWDChipNames,
  NULL,                                                         /*          */
  SVGA_INT10INITUPDATEENABLED,                                  /*          */
};

#pragma  END_SWAP_DATA

