/*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 = VVS3.C
 *
 * DESCRIPTIVE NAME = Virtual Video S3 Specific Processing
 *
 *
 * VERSION = V2.1
 *
 * DATE      04/30/93
 *
 * DESCRIPTION  This module contains all accelerator specific SVGA code and data.
 *
 *
 * FUNCTIONS
 *
 * 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 ULONG ulSVGAVRAMSize;
extern ULONG ulSVGAChipType;                                    /*          */
extern BOOL fSVGASeqFixups;
extern PLE pleCRTIndx;                                          /*          */
extern PLE pleCRTData;                                          /*          */
extern OEMINFO sOEMData;                                        /*          */
extern PSADAPTERINFO psCurAdapterInfo;                          /*          */
extern PSACCELERATORINFO psCurAcceleratorInfo;                  /*          */
extern PSDACINFO psCurDacInfo;                                  /*          */
extern IOH iohA8514wreg [2];                                    /*          */
extern IOH iohA8514mfreg [2];                                   /*          */
extern STRAPREGPARTINFO sTrapWRegLow;                           /*          */
extern STRAPREGPARTINFO sTrapWRegHigh;                          /*          */
extern STRAPREGPARTINFO sTrapWRegWhole;                         /*          */
extern SDACINFO sDacS3SDACInfo;                                 /*          */
extern BYTE abAccelCRTReadMask[];                               /*            */
extern BYTE abCRTMask[];                                        /*            */

CHAR pszS3AdapterName [] = "S3" ;                               /*          */

PCHAR ppszS3ChipNames [MAX_S3_CHIP] =                           /*          */
{  /* As produced by SVGA.EXE! */                               /*          */
  "S386C80X",                                                   /*          */
  "S386C928",                                                   /*          */
  "S386C911",                                                   /*          */
  "S386C864",                                                   /*          */
  "S386C964",                                                   /*          */
};                                                              /*          */

RLE rleS3MemCR3A =                                              /*          */
{ /* See vvS3PackedMode below */
  &pleCRTData,                          /* 0x03d5h (R/W) */
  PORTF_NOTVALIDSVGAPORT,            /*           */
  0x3a, 0x00,
  0x00,                                 /* No conditions */
  0x00,
  {0x00, 0x00, 0x00, 0x00},
  NULL,
  NULL,
};

RLE rleS3MemCR40 =                                              /*          */
{ /* required for vvtransferbuffer:  bit0=0 for text mode */
  &pleCRTData,                          /* 0x03d5h (R/W) */
  PORTF_NOTVALIDSVGAPORT|PORTF_REQUIRED,/*           */
  0x40, 0x00,
  0x00,                                 /* No conditions */
  0x09,
  {0x00, 0x00, 0x00, 0x08},
  NULL,
  NULL,

};

/*
** Write many registers are ones which writing many times with the
** same value generally has the same result as writing them only once.
**
** Write once registers are ones which usually expect a stream of
** values where each value is used only once, perhaps deposited or XORed
** somewhere in VRAM, such as pixel bytes and stroke drawing regs.
**
** Read once registers are similar to write once registers.
** They usually are a stream of values extracted from VRAM.
**
** Read many registers are simliar to write many registers.
** These are the ones which reading many times usually gets the same value
** as the first (unless some asynchronous status changes).
*/

#define S3ACCELERATORTRAPREGSIZE 0x20
#define WS(x) ((PVOID)(&VDMData.VdmSVGA.wRegShadow [x]))

STRAPREGINFO sS3TrapRegInfo [S3ACCELERATORTRAPREGSIZE] =
{
  {/*x00*/0x82e8, WS(0x00), WS(0x00), WRITE_MANY | READ_MANY | NONE  , iohA8514wreg } ,
  {/*x01*/0x86e8, WS(0x01), WS(0x01), WRITE_MANY | READ_MANY | NONE  , iohA8514wreg } ,
  {/*x02*/0x8ae8, WS(0x02), WS(0x02), WRITE_MANY | NONE      | R_NE_W  , iohA8514wreg } ,
  {/*x03*/0x8ee8, WS(0x03), WS(0x03), WRITE_MANY | NONE      | R_NE_W  , iohA8514wreg } ,
  {/*x04*/0x92e8, WS(0x04), WS(0x04), WRITE_MANY | READ_MANY | NONE  , iohA8514wreg } ,
  {/*x05*/0x96e8, WS(0x05), WS(0x05), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x06*/0x9ae8, WS(0x06), WS(0x26), WRITE_MANY | READ_MANY | R_NE_W, iohA8514wreg } ,
  {/*x07*/0x9ee8, WS(0x07), WS(0x27), WRITE_ONCE | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x08*/0xa2e8, WS(0x08), WS(0x08), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x09*/0xa6e8, WS(0x09), WS(0x09), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x0a*/0xaae8, WS(0x0a), WS(0x0a), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x0b*/0xaee8, WS(0x0b), WS(0x0b), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x0c*/0xb2e8, WS(0x0c), WS(0x0c), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x0d*/0xb6e8, WS(0x0d), WS(0x2d), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x0e*/0xbae8, WS(0x0e), WS(0x2e), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x0f*/0xbee8, WS(0x0f), WS(0x2f), WRITE_INDX | READ_INDX | R_NE_W, iohA8514mfreg } ,
  {/*x10*/0x42e8, WS(0x10), WS(0x30), WRITE_MANY | READ_MANY | R_NE_W, iohA8514wreg } ,
  /* 0x46e8 already handled with pleVSE */                                             /*          */
  {/*x11*/0x46e8, WS(0x11), WS(0x11), NONE       | NONE      | NONE  , iohA8514wreg} , /*          */
  {/*x12*/0x4ae8, WS(0x12), WS(0x12), WRITE_MANY | NONE      | R_NE_W  |PORT_STAYS_HOOKED,iohA8514wreg } , //          
  {/*x13*/0x4ee8, WS(0x13), WS(0x33), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x14*/0x52e8, WS(0x14), WS(0x34), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x15*/0x56e8, WS(0x15), WS(0x35), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x16*/0x5ae8, WS(0x16), WS(0x36), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x17*/0x5ee8, WS(0x17), WS(0x37), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x18*/0xe2e8, WS(0x18), WS(0x38), WRITE_ONCE | READ_ONCE | R_NE_W, iohA8514wreg } ,
  {/*x19*/0xe6e8, WS(0x19), WS(0x39), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x1a*/0xeae8, WS(0x1a), WS(0x3a), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x1b*/0xeee8, WS(0x1b), WS(0x3b), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x1c*/0xf2e8, WS(0x1c), WS(0x3c), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x1d*/0xf6e8, WS(0x1d), WS(0x3d), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x1e*/0xfae8, WS(0x1e), WS(0x3e), NONE       | NONE      | R_NE_W, iohA8514wreg } ,
  {/*x1f*/0xe2ea, WS(0x1f), WS(0x3f), WRITE_ONCE | READ_ONCE | R_NE_W, iohA8514wreg } , /*Special case*/
};

BYTE bS3ReadMFRegMap [] =
{
  MFREG_MINORAXISCNT,
  MFREG_TOPSCISSORS,
  MFREG_LEFTSCISSORS,
  MFREG_BOTTOMSCISSORS,
  MFREG_RIGHTSCISSORS,
  MFREG_PIXELCTRL,
  MFREG_MISCCTRL
};

#pragma  END_SWAP_DATA

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

VOID PRIVENTRY vvS3EditTables( VOID )
{
  BYTE i;
  fSVGASeqFixups = FALSE;                                       /*          */
  /*
  ** Edit rle to remove the PORTF_NOTVALIDSVGAPORT.
  */
  rleS3MemCR3A.rle_flags &= ~PORTF_NOTVALIDSVGAPORT;            /*           */
  rleS3MemCR40.rle_flags &= ~PORTF_NOTVALIDSVGAPORT;            /*           */
  if( (ulSVGAChipType == S3_86C864_CHIP)                        /*          */
      || (ulSVGAChipType == S3_86C964_CHIP))                    /*          */
    psCurDacInfo = &sDacS3SDACInfo;                             /*          */
  /*           
  ** Fix up the masks as to allow all readable registers to be read.
  ** By default,  readmask pointer is set to writemasks. Accelerator masks
  ** set to all readable are available for fixups.
  ** Force 0's in all bit positions of non-existing or
  ** non-readable registers. Remove read-only regs from the write mask.
  ** If in any doubts about the write-only regs being initialized by the cleanup
  ** as part of the vvInt10SetModePrepare, use vvxxCreate
  ** as an occasion to initialize the shadow state of the write-only regs.
  */
  for (i=TOTAL_IBM_CRTREGS;i<0x30;i++)
  {
//@V3.0YEE01    abAccelCRTReadMask[i >> 3] &= ~(1 << (i % 8));
//@V3.0YEE01    abCRTMask[i >> 3] &= ~(1 << (i % 8));       //ensure that write mask doesn't contain them either.
    abAccelCRTReadMask [i] = 0x00;
    abCRTMask [i] = 0x00;               //ensure that write mask doesn't contain them either.
  }
  pleCRTData.pbBRegReadMask = &abAccelCRTReadMask[0];         //          
  pleCRTData.pbBRegMask [0x30] = 0x00;  //0x30 is a read-only register
//@V3.0YEE01  pleCRTData.pbBRegMask[0x30 >> 3] &= ~(1 << (0x30 % 8)); //0x30 is a read-only register
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = IsS3Locked
 *
 * DESCRIPTION   = Get S3 lock state
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = True = shadow state locked
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 ****************************************************************************/
BOOL IsS3Locked(HVDM hvdm)                              /*            */
{
  register PVDMDATA pvd = pVDMData(hvdm);
  return(!(pvd->aregCRTData[0x38] & 0x48));
}
/***************************************************************************
 *
 * FUNCTION NAME = vvS3PackedMode
 *
 * DESCRIPTION   = Get SVGA packed pixel mode.
 *
 *                 This req'd because the GDC Mode reg doesn't reflect
 *                 256-colour modes.
 *
 *                 ATI has bits in extended 'ATI registers'.
 *                 Video7 have bits in extended sequencer 0xfc.
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = True = 256 colour mode
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * REMARK: More on the fault hook processing...
 *         Page mapping depends on the state evaluated from the
 *         shadow registers,
 *         which has to represent the true state of the hardware.
 *         If the register is not added to the aprleMemory structure,
 *         its shadow value represents the true state
 *         only after the mode set has returned,
 *         when vvUpdateAll will refresh them all.
 *         If the page mappings are believed to be       at that time,
 *         they will be invalidated and fault hooks enabled again.
 *         However, if evaluating 256-color (i.e. packed) mode
 *         is essential before the mode set returns,
 *         ensure that the register which is being evaluated is added
 *         to the aprleMemory struc.
 * NOTE: Lock state doesn't change the meaning of the packed test!                
 ****************************************************************************/

BOOL PRIVENTRY vvS3PackedMode(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  return( vvEGAPackedMode( hvdm )
          || (pvd->aregCRTData [0x3a] & 0x10));                 /*            */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3Interlaced
 *
 * DESCRIPTION   = Get Interlaced Status
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = True = interlacing on
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  return( (pvd->aregCRTData [0x42] & 0x20) >> ZEROBITS( 0x20 ) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3StartAddr
 *
 * DESCRIPTION   = Get Display frame start address
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = offset into VRAM for display frame
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * WARNING:     Locks have to be emulated. Do not include extended bits if state locked!
 *
 ****************************************************************************/

ULONG PRIVENTRY vvS3StartAddr(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  ULONG ulStartAddr = IsS3Locked(hvdm) ? 0 :            //          
                     ((pvd->aregCRTData [0x31] & 0x30)
                        >> ZEROBITS( 0x30) << 16)
                     | ((pvd->aregCRTData [0x51] & 0x30)
                        >> ZEROBITS( 0x30) << 18);
  /*
  ** Emulate the lock behav
  */
  return(  vvCGAStartAddr( hvdm )
           | ulStartAddr );                     //          
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3HorzDspEnd
 *
 * DESCRIPTION   = Get Horizontal Display Width
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Horizontal Display Width
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * WARNING:     Locks have to be emulated. Do not include extended bits if state locked!
 *
 ****************************************************************************/

USHORT PRIVENTRY vvS3HorzDspEnd(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);                       /*          */
  USHORT usDspEnd = IsS3Locked( hvdm ) ? 0 :
                                       (((pvd->aregCRTData [0x5d] & 0x02)
                                        >> ZEROBITS( 0x02 ) << 8))
                                        << ((pvd->aregCRTData[0x43] & 0x80) >> ZEROBITS( 0x80 ));
  return( vvEGAHorzDspEnd( hvdm ) + usDspEnd);                  /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3HorzLogEnd
 *
 * DESCRIPTION   = Get Horizontal Logical Width
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Horizontal Logical Width
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * WARNING:     Locks have to be emulated. Do not include extended bits if state locked!
 *
 ****************************************************************************/

USHORT PRIVENTRY vvS3HorzLogEnd(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register BYTE bNewWidth89 = ((pvd->aregCRTData[0x51] & 0x30)
                >> ZEROBITS( 0x30 ));

  USHORT usLogEnd;
  bNewWidth89 = (bNewWidth89 ? bNewWidth89 : (pvd->aregCRTData[0x43] & 0x04) >> ZEROBITS(0x04)) << 8;
  usLogEnd= IsS3Locked( hvdm ) ? 0 : bNewWidth89;
  usLogEnd = (pvd->aregCRTData [REG_CRTOFFSET] + usLogEnd)
                        << (1
                        + ((pvd->aregCRTData[REG_CRTUNDLINELOC])
                           ? 2
                           : !(pvd->aregCRTData [REG_CRTMODECTRL] & 0x40)));
  return (usLogEnd);
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3VertDspEnd
 *
 * DESCRIPTION   = Get Vertical Display Length
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Vertical Display Length
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * WARNING:     Locks have to be emulated. Do not include extended bits if state locked!
 *
 ****************************************************************************/

USHORT PRIVENTRY vvS3VertDspEnd(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  USHORT usVertEnd = IsS3Locked( hvdm ) ? 0 :                  //          
                     ((pvd->aregCRTData [0x5e] & 0x02)
                       >> ZEROBITS( 0x02 ) << 10);
  return( vvVGAVertDspEnd( hvdm )+ usVertEnd);
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3VertLineCmp
 *
 * DESCRIPTION   = Get Vertical Line Compare
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Vertical Line Compare (for split screen)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * WARNING:     Locks have to be emulated. Do not include extended bits if state locked!
 *
 ****************************************************************************/

USHORT PRIVENTRY vvS3VertLineCmp(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  USHORT usVertCmp = IsS3Locked( hvdm ) ? 0 :                  //          
                     ((pvd->aregCRTData [0x5e] & 0x40)
                        >> ZEROBITS( 0x40 ) << 10);
  return( vvVGAVertLineCmp( hvdm ) + usVertCmp);
}
/***************************************************************************
 *
 * FUNCTION NAME = vvS3BitsPerPixel
 *
 * DESCRIPTION   = Get Bits Per Pixel
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Bits Per Pixel
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * WARNING:     Locks have to be emulated. Do not include extended bits if state locked!
 *
 ****************************************************************************/

USHORT PRIVENTRY vvS3BitsPerPixel(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register BYTE bPixelBytes;
  bPixelBytes = IsS3Locked( hvdm ) ? 0 : ((pvd->aregCRTData[0x50] & 0x30)
                 >> ZEROBITS( 0x30 ));                          /*          */
  return( ((!bPixelBytes)
           ? vvVGABitsPerPixel( hvdm )
           : ((bPixelBytes + 0x01) << 3)) );                    /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3DacRS2Clear()
 *
 * DESCRIPTION   = Reset DAC RS2
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvS3DacRS2Clear(                                 /*          */
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  vvOutput( INVALID_HVDM,
            &pleCRTIndx,
            0x55 );                     /* S3's key to DAC  */
  pvd->aregCRTData [0x55] &= ~ 0x01;
  vvOutput( INVALID_HVDM,
            &pleCRTData,
            pvd->aregCRTData [0x55] );
  psCurDacInfo->pfnDacIPFClear( hvdm );                         /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3DacRS2Set()
 *
 * DESCRIPTION   = Reset DAC RS2
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvS3DacRS2Set(                                   /*          */
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  psCurDacInfo->pfnDacIPFSet( hvdm );                           /*          */
  vvOutput( INVALID_HVDM,
            &pleCRTIndx,
            0x55 );                     /* S3's key to DAC  */
  pvd->aregCRTData [0x55] |= 0x01;
  vvOutput( INVALID_HVDM,
            &pleCRTData,
            pvd->aregCRTData [0x55] );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3DacRS3()
 *
 * DESCRIPTION   = Set DAC RS3 State
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvS3DacRS3(                                      /*          */
  HVDM hvdm,
  BOOL bRS3 )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  vvOutput( INVALID_HVDM,
            &pleCRTIndx,
            0x55 );                     /* S3's key to DAC  */
  pvd->aregCRTData [0x55] &= ~ 0x02;
  pvd->aregCRTData [0x55] |=
    bRS3 << ZEROBITS( 0x02 );
  vvOutput( INVALID_HVDM,
            &pleCRTData,
            pvd->aregCRTData [0x55] );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3DacSave()
 *
 * DESCRIPTION   = Save DAC state
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvS3DacSave(                                     /*          */
  HVDM hvdm )
{
  BYTE bDACKey;
  register PVDMDATA pvd = pVDMData(hvdm);

  /* Add save and restore RS[3:2] */
  bDACKey = pvd->aregCRTData [0x55];
  pvd->aregCRTData [0x55] &= ~ 0x03;    /* RS[3:2] = 0:0 */
  vvOutput( INVALID_HVDM,
            &pleCRTIndx,
            0x55 );                     /* S3's key to DAC  */
  vvOutput( INVALID_HVDM,
            &pleCRTData,
            pvd->aregCRTData [0x55] );
  psCurDacInfo->pfnDacSave( hvdm );                             /*          */
  pvd->aregCRTData [0x55] = bDACKey;
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3DacRestore()
 *
 * DESCRIPTION   = Restore DAC state
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvS3DacRestore(                                  /*          */
  HVDM hvdm )
{
  BYTE bDACKey;
  register PVDMDATA pvd = pVDMData(hvdm);

  /* Add save and restore RS[3:2] if necessary */
  bDACKey = pvd->aregCRTData [0x55];
  pvd->aregCRTData [0x55] &= ~ 0x03;    /* RS[3:2] = 0:0 */
  vvOutput( INVALID_HVDM,
            &pleCRTIndx,
            0x55 );                     /* S3's key to DAC  */
  vvOutput( INVALID_HVDM,
            &pleCRTData,
            pvd->aregCRTData [0x55] );
  psCurDacInfo->pfnDacRestore( hvdm );                          /*          */
  pvd->aregCRTData [0x55] = bDACKey;
}

/***************************************************************************
 *
 * FUNCTION NAME = vvS3SetBank()
 *
 * DESCRIPTION   = Set S3 bank register(s)
 *
 * INPUT         = hvdm
 *                 ulBank
 *                 fSetWriteBank
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * NOTE: To address 2/4 MB of RAM, set bit 2/3 of 3d4,51 to 1.
 ****************************************************************************/
/*            */
VOID    PRIVENTRY vvS3SetBank(
  HVDM hvdm,
  ULONG ulBank,
  BOOL fSetWriteBank )
{
  register BYTE   bBanklo, bBankhi, bTmp, bIndx, bSave;
  PVDMDATA        pvd = pVDMData(hvdm);

  fSetWriteBank;                        // shut the compiler up

  /*
  ** Non-linear organization.
  */
  if (!(pvd->flVDMXVideo & VDMX_ENHANCEDMODE))                  /*          */
    ulBank <<= 2;                       // bank granularity is still 64K

  bIndx = vvInput( hvdm,
                   &pleCRTIndx );       // get current contents /*          */

  vvOutput( hvdm,                       /*            start */
            &pleCRTIndx,
            0x31 );                     // Mem config reg
  bSave = vvInput( hvdm,
                   &pleCRTData );
  vvOutput( hvdm,
            &pleCRTData,
            (BYTE) (bSave | 0x01) );    // enable 64K page addressing

  if ((ulSVGAChipType == S3_86C864_CHIP) ||
      (ulSVGAChipType == S3_86C964_CHIP))
  {
     vvOutput( hvdm,
               &pleCRTIndx,
               0x6a );                  // Offset register
     vvOutput( hvdm,
               &pleCRTData,
               (BYTE)ulBank);           // Set Bank (up to 4MB addressing)
  } /*           end */

  vvOutput( hvdm,
            &pleCRTIndx,
            0x35 );                     // Offset register      /*          */
  bTmp = vvInput( hvdm,
                  &pleCRTData )
         & 0xf0;                        //get current hi-nib/*          */
  bBanklo = ((BYTE)ulBank) & 0x0f;      // mask into place (bits 3-0)
  bBanklo |= bTmp;                      // combine other previous bits
  vvOutput( hvdm,
            &pleCRTData,
            bBanklo );                  // Set Bank             /*          */
  vvOutput( hvdm,
            &pleCRTIndx,
            0x51 );                     // Offset register      /*          */
  bTmp = vvInput( hvdm,
                  &pleCRTData );        // get current contents /*          */
  bTmp &= 0xf3;                         // clear bits 2,3
  bBankhi = (((BYTE)ulBank) & 0x30) >> 2; // get extended bits in CR51 /*          */
  bBankhi |= bTmp;                      // combine other previous bits
  vvOutput( hvdm,
            &pleCRTData,                                        /*          */
            bBankhi );                  // Set Bank (2/4 MB addressing)
  vvOutput( hvdm,
            &pleCRTIndx,
            bIndx );                    // Restore Index        /*          */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvS3GetBank()
 *
 * DESCRIPTION   = Get S3 bank register(s)
 *
 * INPUT         = hvdm
 *                 fGetWriteBank
 *
 * OUTPUT        = ulBank
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 *
 ****************************************************************************/
ULONG   PRIVENTRY vvS3GetBank(
  HVDM hvdm,
  BOOL fGetWriteBank )                                          /*          */
{
  BYTE bBank = 0;   /*           */
  BYTE bTmp;
  PVDMDATA pvd = pVDMData(hvdm);
  if (IsS3Locked) return 0;                                     /*          */

  bTmp = vvInput( hvdm,
                  &pleCRTIndx );      // get current contents   /*          */

  if ((ulSVGAChipType == S3_86C864_CHIP) ||   /*            start */
      (ulSVGAChipType == S3_86C964_CHIP))
  {
     vvOutput( hvdm,
               &pleCRTIndx,
               0x6a );                     // Offset register
     bBank = vvInput( hvdm,
                      &pleCRTData );
  }  /*           end */

  if (!bBank)      /*          */
  {                /*          */
    vvOutput( hvdm,
              &pleCRTIndx,
              0x35 );                 // Offset register        /*          */
    bBank = vvInput( hvdm,
                     &pleCRTData )                              /*          */
            & 0x0f;                   // get current contents   /*          */
    vvOutput( hvdm,
              &pleCRTIndx,
              0x51 );                 // Mode extn register     /*          */
    bBank |= (vvInput( hvdm,
                       &pleCRTData )                            /*          */
              & 0x0C) << 2;           // bits 2,3 are bits 4, 5 /*          */
    vvOutput( hvdm,
              &pleCRTIndx,
              bTmp );                 // Restore Index          /*          */
  }  /*          */
  /*
  ** Non-linear organization.
  */
  if (!(pvd->flVDMXVideo & VDMX_ENHANCEDMODE))                  /*          */
    bBank >>= 2;

  return( bBank );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvS3PrepareSetMode()
 *
 * DESCRIPTION   = Fix Registers & return mode number
 *
 * INPUT         = HVDM
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvInt10SetMode
 *
 **************************************************************************/

USHORT PRIVENTRY vvS3PrepareSetMode(
  HVDM hvdm,
  PCRF pcrf )
{
  USHORT Addr_6845;                              /*                         */
  BYTE Data;                                     /*                         */
  UCHAR  SaveIndex;                              /*                         */

  hvdm;

  return( vvVGAPrepareSetMode( hvdm, pcrf ) );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvS3PortIndex()
 *
 * DESCRIPTION   = Get index for write of an accelerator data register
 *
 * INPUT         = port
 *
 * OUTPUT        = table index for port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

UINT    PRIVENTRY vvS3PortIndex( PORT port )
{
  return( (port == A8514_PIXELTRANSFER_EXT) /*Special case*/
          ? 0x1f
          : ((port & 0x7c00) >> 10) );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvS3ReadMFRegShadow()
 *
 * DESCRIPTION   = Get accelerator multi-function register shadow location
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads from the accelerator multi-function register
 *                 (ie, one of those listed under A8514_MULTIFUNCTION).
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

PWORD   PRIVENTRY vvS3ReadMFRegShadow( VOID )
{
  UINT uiIndex;

  uiIndex = VDMData.VdmSVGA.awreg8514MFData [MFREG_READSEL] & 0x07;
  if( !(VDMData.VdmSVGA.awreg8514MFData [MFREG_READSEL]
        & MFREG_INDXODD) )
  {
    VDMData.VdmSVGA.awreg8514MFData [MFREG_READSEL]++;
    VDMData.VdmSVGA.awreg8514MFData [MFREG_READSEL] &=
      ~MFREG_INDXODD;
  }
  return( ((uiIndex < 0x07)
           ? &VDMData.VdmSVGA.awreg8514MFData
               [bS3ReadMFRegMap [uiIndex]]
           : (PWORD) (psCurAcceleratorInfo->psAcceleratorTrapRegInfo
                        [psCurAcceleratorInfo->
                          puifnAcceleratorPortIndex( A8514_STATUS )]
                            .pvTrapReadShadow)) );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvS3Chip()
 *
 * 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 vvS3Chip( VOID )
{
  return( TRUE );
}

/***********************************************************************
 *
 * FUNCTION NAME = vvS3UpdateScrnState()
 *
 * DESCRIPTION   = Return line len in bytes for accelerated modes, depending on
 *                 the memory map organization.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorUpdateScreenState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvS3UpdateScrnState(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  ULONG ulLineLen;

}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvS3EnableEngineAddr()
 *
 * DESCRIPTION   = Enable addressing of accelerator registers.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorEnableEngineAddr
 *
 ***********************************************************************/

VOID    PRIVENTRY vvS3EnableEngineAddr( VOID )
{
  BYTE bData, bIndx;

  bIndx = vvInput( INVALID_HVDM,                                /*          */
                   &pleCRTIndx );      /* get current index */  /*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTIndx,                                        /*          */
            0x40 );
  bData = vvInput( INVALID_HVDM,                                /*          */
                   &pleCRTData )                                /*          */
          | 0x01;
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTData,                                        /*          */
            bData );
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTIndx,                                        /*          */
            bIndx);                   /* restore the index */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvS3UpdateIoState()
 *
 * DESCRIPTION   = Transfer hardware I/O state to virtual
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorUpdateIoState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvS3UpdateIoState(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData( hvdm );
  WORD wData;
  PORT port;
  UINT uiIndex;
  WORD wOldIndex;
  PSTRAPREGINFO psTrapRegInfo;                                  /*          */
  BYTE bIndx;                    /*          */
  BYTE bDACKey;                  /*          */

  vvA8514UpdateIoState( hvdm );
  for (uiIndex = 0;
       uiIndex < psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
       uiIndex++)
  {
    psTrapRegInfo =                                             /*          */
      &psCurAcceleratorInfo->psAcceleratorTrapRegInfo [uiIndex];
    if( (psTrapRegInfo->fTrapType & READ_MANY) == READ_MANY )   /*          */
    {
      port = psTrapRegInfo->portTrap;                           /*          */
      if( (psTrapRegInfo->fTrapType & READ_INDX) == READ_INDX ) /*          */
      {
        /*
        ** Then read all the multi-function registers.
        */
        wOldIndex =
          pvd->VdmSVGA.awreg8514MFData [MFREG_READSEL];
        vvOutputWord( INVALID_HVDM,                             /*          */
                      psTrapRegInfo,                            /*          */
                      (WORD) MFINDX_READSEL );                  /*          */
        do
        {
          wData = vvInputWord( INVALID_HVDM,                    /*          */
                               psTrapRegInfo );                 /*          */
          pvd->VdmSVGA.awreg8514MFData
            [wData >> MFINDX_INDXSHIFT] = wData;
        } while( (wData & MFINDX_INDXMASK) < MFINDX_MISCCTRL );
        pvd->VdmSVGA.awreg8514MFData [MFREG_READSEL] =
          wOldIndex;
        vvOutputWord( INVALID_HVDM,                             /*          */
                      psTrapRegInfo,                            /*          */
                      wOldIndex );                              /*          */
      } /* end if */
    } /* end if */
  } /* end for */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvS3RestoreIoState()
 *
 * DESCRIPTION   = Transfer virtual I/O state to hardware
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorRestoreIoState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvS3RestoreIoState(
  HVDM hvdm )
{
  USHORT Addr6845 = PORT_MONOCRTINDX + ((INB(PORT_GDCPOS1)&01) << 5); /*          */
  BYTE bData;
  /*
  **           
  ** Unlock the accelerator set. Crt 40 may be unlocked, or locked at
  ** this point, depending on the state the BIOS has left it in. If the
  ** BIOS left it locked, that should be equivalent to engine being disabled
  ** and VGA enabled. However, we want to ensure that engine is disabled, so
  ** that no glitches happen when we do have to unlock. So, the engine disabled
  ** state is restored as well as the state of the engine lock register.
  */
  OUTB(Addr6845,0x40);
  bData = (BYTE) INB(Addr6845+1);
  OUTB(Addr6845+1,bData | 0x1);
  if (!(pVDMData(hvdm)->flVDMXVideo & VDMX_INTRESTOREFGND))
  {
     /*
     **            
     ** Diamond s3 eeprom does not have an entry for any VGA modes. The BIOS just
     ** disables the external clock chip. Do not call the SetDiamondClk in VGA modes on S3.
     */
     if ((sOEMData.Manufacturer == DIAMOND_MANUFACTURER) &&
        ((pVDMData(hvdm)->ulBIOSMode & ~BIOSVINFO_DONTCLEAR) > BIOSVMODE_CO320X200X256))
        SETDIAMONDCLK(hvdm, pVDMData(hvdm)->vvMode.vvm_nCols,
                    pVDMData(hvdm)->vvMode.vvm_nBitCount);       /*          */
  }
  /*
  **             If the accelerator is enabled, restore all of the registers.
  ** Else, restore just the advance function control register.
  */
  if (vvA8514IsOn(hvdm))
     vvA8514RestoreIoState(hvdm);
  else
  {
     PSTRAPREGINFO psTrapRegInfo;
     psTrapRegInfo = &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
                   [psCurAcceleratorInfo->
                    puifnAcceleratorPortIndex( A8514_ADVCTRL )];
     vvOutputWord( INVALID_HVDM,
                    psTrapRegInfo,
                    *pVDM( hvdm,
                           PWORD,
                           psTrapRegInfo->pvTrapWriteShadow ));
  }
  if (!(pVDMData(hvdm)->flVDMXVideo & VDMX_INTRESTOREFGND) &&           /*            */
       (sOEMData.Manufacturer == NUMBER9_MANUFACTURER))            /*          */
    SETNUMBER9CLK(hvdm, pVDMData(hvdm)->vvMode.vvm_nCols);      /*          */
  OUTB(Addr6845+1,bData);    //restore the engine lock state.
}

#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA

SA8514INFO sS3Info =
{
  {
    sS3TrapRegInfo,
    S3ACCELERATORTRAPREGSIZE,
    &vvS3PortIndex,
    &vvS3Chip,
    &vvA8514IsOn,
    &vvA8514Create,                                             /*          */
    NULL,                                                       /*          */
    &vvA8514Busy,
    &vvA8514Reset,
    &vvA8514InstallIoHooks,
    &vvA8514SetIoHooks,
    &vvA8514SetBgndOnlyHooks,
    &vvS3UpdateScrnState,
    &vvS3UpdateIoState,
    &vvS3RestoreIoState,
    &vvA8514Init,
  },
  &vvS3ReadMFRegShadow,
};

SSVGAINFO sS3AdapterInfo =                                      /*          */
{
  { /* SVGAINFO */                                              /*          */
    { /* SEGAINFO */
      { /* SCGAINFO */
        &vvEGAAdjustedPort,
        &vvS3StartAddr,
        &vvEGAOddEvenMode,
        &vvEGAHighResMode,
        &vvS3HorzDspEnd,
        &vvS3HorzLogEnd,
        &vvS3VertDspEnd,
        &vvS3BitsPerPixel,
        &vvS3PrepareSetMode,                                    /*          */
      },
      &vvS3PackedMode,
      &vvS3VertLineCmp,
    },
    &vvS3DacSave,                                               /*          */
    &vvS3DacRestore,                                            /*          */
  },
  &vvS3EditTables,
  &vvS3Interlaced,
  &vvVGAUpdateIoState,
  &vvVGARestoreIoState,
  &vvS3SetBank,
  &vvS3GetBank,
  &vvVGAFixSetMode,
  &vvVGAFixSetBgnd,
  &vvVGAWriteGDCDataFgnd,
  &vvVGAReadSEQDataBgnd,
  &vvVGAWriteSEQDataBgnd,
  &vvS3DacRS2Clear,                                             /*          */
  &vvS3DacRS2Set,                                               /*          */
  &vvS3DacRS3,                                                  /*          */
  &sS3Info.sAcceleratorInfo,
  pszS3AdapterName,
  MAX_S3_CHIP,
  ppszS3ChipNames,
  &vvA8514UpdateModeData,                                       /*          */
  SVGA_INT10INITUPDATEENABLED,                                  /*          */
};

#pragma  END_SWAP_DATA

