/*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 = VVA8514.C
 *
 * DESCRIPTIVE NAME = Virtual Video 8514A Specific Processing
 *
 *
 * VERSION = V2.1
 *
 * DATE      04/30/93
 *
 * DESCRIPTION  This module contains all accelerator specific SVGA code and data.
 *
 *
 * FUNCTIONS
 *      vvA8514ReadWRegByteL()          Read low byte of 8514/A word register
 *      vvA8514ReadWRegByteH()          Read high byte of 8514/A word register
 *      vvA8514ReadWRegWord()           Read 8514/A word register
 *      vvA8514WriteWRegByteL()         Write low byte of 8514/A word register
 *      vvA8514WriteWRegByteH()         Write high byte of 8514/A word register
 *      vvA8514WriteWRegWord()          Write 8514/A word register
 *      vvA8514ReadMFRegByteL()         Read low byte of 8514/A multi-function register
 *      vvA8514ReadMFRegByteH()         Read high byte of 8514/A multi-function register
 *      vvA8514ReadMFRegWord()          Read 8514/A multi-function register
 *      vvA8514WriteMFRegByteL()        Write low byte of 8514/A multi-function register
 *      vvA8514WriteMFRegByteH()        Write high byte of 8514/A multi-function register
 *      vvA8514WriteMFRegWord()         Write 8514/A multi-function 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>

/*
**     Externals
*/
/*
** Global data
*/
extern PLE pleCRTIndx;                                          /*          */
extern PLE pleCRTData;                                          /*          */
extern PSACCELERATORINFO psCurAcceleratorInfo;                  /*          */
extern STRAPREGPARTINFO sTrapWRegLow;                           /*          */
extern STRAPREGPARTINFO sTrapWRegHigh;                          /*          */
extern STRAPREGPARTINFO sTrapWRegWhole;                         /*          */

#pragma  BEGIN_SWAP_DATA

 /*
 ** The following is a complete list of word registers, all of which use
 ** the following I/O handlers:
 **
 **     vvA8514ReadWRegByteL      vvA8514ReadWRegByteH      vvA8514ReadWRegWord
 **     vvA8514WriteWRegByteL     vvA8514WriteWRegByteH     vvA8514WriteWRegWord
 **
 ** Only one word register is excluded (A8514_MULTIFUNCTION), which actually
 ** indexes into an array of internal registers, so shadowing of the port is
 ** handled by a special set of routines, and which are specially installed by
 ** vvAcceleratorSetIOHooks:
 **
 **     vvA8514ReadMFRegByteL     vvA8514ReadMFRegByteH     vvA8514ReadMFRegWord
 **     vvA8514WriteMFRegByteL    vvA8514WriteMFRegByteH    vvA8514WriteMFRegWord
 */

IOH iohA8514wreg [2] =
{
  {
    vvA8514ReadWRegByteL, vvA8514WriteWRegByteL,
    vvA8514ReadWRegWord,  vvA8514WriteWRegWord,
    NULL,
  },
  {
    vvA8514ReadWRegByteH, vvA8514WriteWRegByteH,
    NULL,                 NULL,
    NULL,
  },
};

IOH iohA8514mfreg [2] =
{
  {
    vvA8514ReadMFRegByteL, vvA8514WriteMFRegByteL,
    vvA8514ReadMFRegWord,  vvA8514WriteMFRegWord,
    NULL,
  },
  {
    vvA8514ReadMFRegByteH, vvA8514WriteMFRegByteH,
    NULL,                 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 A8514TRAPREGSIZE 0x40
#define WS(x) ((PVOID)(&VDMData.VdmSVGA.wRegShadow [x]))

STRAPREGINFO sA8514TrapRegInfo [A8514TRAPREGSIZE] =
{
  {/*x00*/0x02e8, WS(0x00), WS(0x40), WRITE_MANY | READ_MANY | R_NE_W, iohA8514wreg} ,
  {/*x01*/0x06e8, WS(0x01), WS(0x41), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x02*/0x0ae8, WS(0x02), WS(0x42), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x03*/0x0ee8, WS(0x03), WS(0x43), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x04*/0x12e8, WS(0x04), WS(0x44), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x05*/0x16e8, WS(0x05), WS(0x45), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x06*/0x1ae8, WS(0x06), WS(0x46), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x07*/0x1ee8, WS(0x07), WS(0x47), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x08*/0x22e8, WS(0x08), WS(0x48), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x09*/0x26e8, WS(0x09), WS(0x49), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x0a*/0x2ae8, WS(0x0a), WS(0x4a), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x0b*/0x2ee8, WS(0x0b), WS(0x4b), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x0c*/0x32e8, WS(0x0c), WS(0x4c), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x0d*/0x36e8, WS(0x0d), WS(0x4d), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x0e*/0x3ae8, WS(0x0e), WS(0x4e), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x0f*/0x3ee8, WS(0x0f), WS(0x4f), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x10*/0x42e8, WS(0x10), WS(0x50), 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(0x52), WRITE_MANY | NONE      | R_NE_W | PORT_STAYS_HOOKED, iohA8514wreg} , /*            */
  {/*x13*/0x4ee8, WS(0x13), WS(0x53), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x14*/0x52e8, WS(0x14), WS(0x54), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x15*/0x56e8, WS(0x15), WS(0x55), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x16*/0x5ae8, WS(0x16), WS(0x56), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x17*/0x5ee8, WS(0x17), WS(0x57), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x18*/0x62e8, WS(0x18), WS(0x58), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x19*/0x66e8, WS(0x19), WS(0x59), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x1a*/0x6ae8, WS(0x1a), WS(0x5a), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x1b*/0x6ee8, WS(0x1b), WS(0x5b), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x1c*/0x72e8, WS(0x1c), WS(0x5c), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x1d*/0x76e8, WS(0x1d), WS(0x5d), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x1e*/0x7ae8, WS(0x1e), WS(0x5e), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x1f*/0x7ee8, WS(0x1f), WS(0x5f), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x20*/0x82e8, WS(0x20), WS(0x60), WRITE_MANY | READ_MANY | NONE  , iohA8514wreg} ,
  {/*x21*/0x86e8, WS(0x21), WS(0x61), WRITE_MANY | READ_MANY | NONE  , iohA8514wreg} ,
  {/*x22*/0x8ae8, WS(0x22), WS(0x62), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x23*/0x8ee8, WS(0x23), WS(0x63), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x24*/0x92e8, WS(0x24), WS(0x64), WRITE_MANY | READ_MANY | NONE  , iohA8514wreg} ,
  {/*x25*/0x96e8, WS(0x25), WS(0x65), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x26*/0x9ae8, WS(0x26), WS(0x66), WRITE_MANY | READ_MANY | R_NE_W, iohA8514wreg} ,
  {/*x27*/0x9ee8, WS(0x27), WS(0x67), WRITE_ONCE | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x28*/0xa2e8, WS(0x28), WS(0x68), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x29*/0xa6e8, WS(0x29), WS(0x69), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x2a*/0xaae8, WS(0x2a), WS(0x6a), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x2b*/0xaee8, WS(0x2b), WS(0x6b), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x2c*/0xb2e8, WS(0x2c), WS(0x6c), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x2d*/0xb6e8, WS(0x2d), WS(0x6d), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x2e*/0xbae8, WS(0x2e), WS(0x6e), WRITE_MANY | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x2f*/0xbee8, WS(0x2f), WS(0x6f), WRITE_INDX | NONE      | R_NE_W, iohA8514mfreg} , /* Array */
  {/*x30*/0xc2e8, WS(0x30), WS(0x70), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x31*/0xc6e8, WS(0x31), WS(0x71), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x32*/0xcae8, WS(0x32), WS(0x72), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x33*/0xcee8, WS(0x33), WS(0x73), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x34*/0xd2e8, WS(0x34), WS(0x74), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x35*/0xd6e8, WS(0x35), WS(0x75), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x36*/0xdae8, WS(0x36), WS(0x76), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x37*/0xdee8, WS(0x37), WS(0x77), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x38*/0xe2e8, WS(0x38), WS(0x78), WRITE_ONCE | READ_ONCE | R_NE_W, iohA8514wreg} ,
  {/*x39*/0xe6e8, WS(0x39), WS(0x79), NONE       | READ_MANY | R_NE_W, iohA8514wreg} , /* Only when not drawing!*/
  {/*x3a*/0xeae8, WS(0x3a), WS(0x7a), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x3b*/0xeee8, WS(0x3b), WS(0x7b), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x3c*/0xf2e8, WS(0x3c), WS(0x7c), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x3d*/0xf6e8, WS(0x3d), WS(0x7d), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x3e*/0xfae8, WS(0x3e), WS(0x7e), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
  {/*x3f*/0xfae8, WS(0x3f), WS(0x7f), NONE       | NONE      | R_NE_W, iohA8514wreg} ,
};

#pragma  END_SWAP_DATA

#pragma  BEGIN_SWAP_CODE
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadWRegByteL()
 *
 * DESCRIPTION   = Read low byte of accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads a byte from the lower half of an accelerator word
 *                 register (ie, one of those listed in aportS3WReg).
 *                 Note that most of these registers are W/O, so we
 *                 don't expect apps to try this very often.  We may
 *                 also decide to make the W/O ports readable.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

BYTE    HOOKENTRY vvA8514ReadWRegByteL(
  ULONG port,
  PCRF pcrf )
{
  BYTE bData;

  vvAcceleratorRead( &psCurAcceleratorInfo->
                       psAcceleratorTrapRegInfo
                         [psCurAcceleratorInfo->
                           puifnAcceleratorPortIndex( port )],
                     &sTrapWRegLow,
                     (PVOID) SSToDS( &bData) );
  return( bData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadWRegByteH()
 *
 * DESCRIPTION   = Read high byte of accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads a byte from the upper half of an accelerator word
 *                 register (ie, one of those listed in aportS3WReg).
 *
 *                 Note that most of these registers are W/O, so we
 *                 don't expect apps to try this very often.  We may
 *                 also decide to make the W/O ports readable.
 *
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

BYTE    HOOKENTRY vvA8514ReadWRegByteH(
  ULONG port,
  PCRF pcrf )
{
  BYTE bData;

  vvAcceleratorRead( &psCurAcceleratorInfo->
                       psAcceleratorTrapRegInfo
                         [psCurAcceleratorInfo->
                           puifnAcceleratorPortIndex( port )],
                     &sTrapWRegHigh,
                     (PVOID) SSToDS( &bData ) );
  return( bData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadWRegWord()
 *
 * DESCRIPTION   = Read accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads from an accelerator word register (ie, one of those
 *                 listed in aportS3WReg).
 *
 *                 Note that most of these registers are W/O, so we don't
 *                 expect apps to try this very often.  We may also decide
 *                 to make the W/O ports readable.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

WORD    HOOKENTRY vvA8514ReadWRegWord(
  ULONG port,
  PCRF pcrf )
{
  WORD wData;

  vvAcceleratorRead( &psCurAcceleratorInfo->
                       psAcceleratorTrapRegInfo
                         [psCurAcceleratorInfo->
                           puifnAcceleratorPortIndex( port )],
                     &sTrapWRegWhole,
                     (PVOID) SSToDS( &wData ) );
  return( wData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WriteWRegByteL()
 *
 * 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 (ie, one of those listed in aportS3WReg).
 *
 * INPUT         = bLow == output data
 *                 port == port address to write
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvA8514WriteWRegByteL(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  register BOOL bIsCmd;

  /*
  ** Allow all kinds of background access except commands!
  */
  bIsCmd = ((port & ~0x0001) == A8514_SHORTSTROKE)
              /* Drawing chgs VRAM, moving CURRENTXY! */
           /* || ((port & ~0x0001) == A8514_COMMAND) */
              /* Drawing chgs VRAM, moving CURRENTXY! */
              /* Low is OK if High is blocked */
           || ((port & ~0x0001) == 0x96ee)                      /*          */
              /* Bresenham Count Register for ATI Mach8/32 */   /*          */
           || (((port & ~0x0001) == A8514_SUBSYSCTRL)
               && (bData & 0x0f));      /* These bits change other regs! */
  vvAcceleratorWrite( &psCurAcceleratorInfo->
                        psAcceleratorTrapRegInfo
                          [psCurAcceleratorInfo->
                            puifnAcceleratorPortIndex( port )],
                      &sTrapWRegLow,
                      (PVOID) SSToDS( &bData ),
                      bIsCmd );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WriteWRegByteH()
 *
 * 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 (ie, one of those listed in aportS3WReg).
 *
 * INPUT         = bHigh == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvA8514WriteWRegByteH(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  register BOOL bIsCmd;
  register PSTRAPREGINFO psTrapRegInfo;

  psTrapRegInfo =
    &psCurAcceleratorInfo->
      psAcceleratorTrapRegInfo
        [psCurAcceleratorInfo->
          puifnAcceleratorPortIndex( port )];
  /*
  ** Allow all kinds of background access except commands!
  */
  bIsCmd = ((port & ~0x0001) == A8514_SHORTSTROKE)
              /* Drawing chgs VRAM, moving CURRENTXY! */
           || (((port & ~0x0001) == A8514_COMMAND)
              /* Drawing chgs VRAM, moving CURRENTXY! */
               && (bData & 0xe0))       /* NOP OK, others NOT */
           || ((port & ~0x0001) == 0x96ee)                      /*          */
              /* Bresenham Count Register for ATI Mach8/32 */   /*          */
           || (((port & ~0x0001) == A8514_SUBSYSCTRL)
               && (bData != BYTEOF(*(PWORD)psTrapRegInfo->
                                     pvTrapWriteShadow, 1)));
                                        /* Anything different NOT OK */
  vvAcceleratorWrite( psTrapRegInfo,
                      &sTrapWRegHigh,
                      (PVOID) SSToDS( &bData ),
                      bIsCmd );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WriteWRegWord()
 *
 * DESCRIPTION   = Write accelerator word register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to an accelerator word register (ie, one of those
 *                 listed in aportS3WReg).
 *
 * INPUT         = wData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvA8514WriteWRegWord(
  WORD wData,
  ULONG port,
  PCRF pcrf )
{
  register BOOL bIsCmd;
  register PSTRAPREGINFO psTrapRegInfo;

  psTrapRegInfo =
    &psCurAcceleratorInfo->
      psAcceleratorTrapRegInfo
        [psCurAcceleratorInfo->
          puifnAcceleratorPortIndex( port )];
  /*
  ** Allow all kinds of background access except commands!
  */
  bIsCmd = ((port & ~0x0001) == A8514_SHORTSTROKE)
              /* Drawing chgs VRAM, moving CURRENTXY! */
           || (((port & ~0x0001) == A8514_COMMAND)
               && (wData & 0xe000))     /* NOP OK, others NOT */
              /* Drawing chgs VRAM, moving CURRENTXY! */
           || ((port & ~0x0001) == 0x96ee)                      /*          */
              /* Bresenham Count Register for ATI Mach8/32 */   /*          */
           || (((port & ~0x0001) == A8514_SUBSYSCTRL)
               && (((wData
                     ^ *(PWORD)psTrapRegInfo->
                         pvTrapWriteShadow)
                    & ~0x00ff)          /* Anything different NOT OK */
                   || (wData & 0x000f)));
                                        /* These bits change other regs! */
  vvAcceleratorWrite( psTrapRegInfo,
                      &sTrapWRegWhole,
                      (PVOID) SSToDS( &wData ),
                      bIsCmd );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadMFRegShadow()
 *
 * 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 vvA8514ReadMFRegShadow( VOID )
{
  return( &VDMData.VdmSVGA.awreg8514MFData [0x0f] );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadMFRegByteL()
 *
 * DESCRIPTION   = Read low byte of accelerator multi-function register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads a byte from the lower half of the accelerator
 *                 multi-function register (ie, one of those listed under
 *                 A8514_MULTIFUNCTION).
 *
 *                 Note that all of the multi-function registers are W/O,
 *                 so we don't expect apps to try this very often.  We may
 *                 also decide to make the W/O ports readable.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

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

  VDMData.VdmSVGA.awreg8514MFData [MFREG_READSEL] ^=
    MFREG_INDXODD;
  *(PSTRAPREGINFO) SSToDS( &sTrapRegInfo ) =                    /*          */
    psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  sTrapRegInfo.pvTrapReadShadow =
    (PVOID) ((PSA8514INFO) psCurAcceleratorInfo)->              /*          */
              ppwfnA8514ReadMFRegShadow();                      /*          */
  vvAcceleratorRead( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                     &sTrapWRegLow,
                     (PVOID) SSToDS( &bData ) );
  return( bData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadMFRegByteH()
 *
 * DESCRIPTION   = Read high byte of accelerator multi-function register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads a byte from the upper half of 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  =
 *
 ***********************************************************************/

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

  VDMData.VdmSVGA.awreg8514MFData [MFREG_READSEL] ^=
    MFREG_INDXODD;
  *(PSTRAPREGINFO) SSToDS( &sTrapRegInfo ) =                    /*          */
    psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  sTrapRegInfo.pvTrapReadShadow =
    (PVOID) ((PSA8514INFO) psCurAcceleratorInfo)->              /*          */
              ppwfnA8514ReadMFRegShadow();                      /*          */
  vvAcceleratorRead( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                     &sTrapWRegHigh,
                     (PVOID) SSToDS( &bData ) );
  return( bData );
}

/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadMFRegWord()
 *
 * DESCRIPTION   = Read accelerator multi-function register
 *
 *                 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  =
 *
 ***********************************************************************/

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

  *(PSTRAPREGINFO) SSToDS( &sTrapRegInfo ) =                    /*          */
    psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  sTrapRegInfo.pvTrapReadShadow =
    (PVOID) ((PSA8514INFO) psCurAcceleratorInfo)->              /*          */
              ppwfnA8514ReadMFRegShadow();                      /*          */
  vvAcceleratorRead( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                     &sTrapWRegWhole,
                     (PVOID) SSToDS( &wData ) );
  return( wData );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WriteMFRegByteL()
 *
 * DESCRIPTION   = Write low byte of accelerator multi-function register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the lower half of the accelerator
 *                 multi-function register (ie, one of those listed
 *                 under A8514_MULTIFUNCTION).
 *
 * INPUT         = bLow == output data
 *                 port == port address to write
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    HOOKENTRY vvA8514WriteMFRegByteL(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  PSTRAPREGINFO psTrapRegInfo;

  psTrapRegInfo =
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  vvAcceleratorWrite( psTrapRegInfo,
                      &sTrapWRegLow,
                      (PVOID) SSToDS( &bData ),
                      FALSE );          /* Not a command */
  /* This assumes the low byte can/must be written before the high byte. */
  /* Since the high byte contains the index, this is unusual! */
  /* We cannot store the data into a shadow register now */
  /* Because we do not yet know its index! */
  /*
  ** VDMData.VdmSVGA.awreg8514MFData
  **   [VDMData.VdmSVGA.wreg8514MFIndx >> MFINDX_INDXSHIFT] =
  **     VDMData.VdmSVGA.wreg8514MFIndx;
  */
}

/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WriteMFRegByteH()
 *
 * 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 vvA8514WriteMFRegByteH(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
  PSTRAPREGINFO psTrapRegInfo;

  psTrapRegInfo =
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  vvAcceleratorWrite( psTrapRegInfo,
                      &sTrapWRegHigh,
                      (PVOID) SSToDS( &bData ),
                      FALSE );          /* Not a command */
  /* This assumes the low byte can/must be written before the high byte. */
  /* Since the high byte contains the index, this is unusual! */
  /* Now that we know the index, we must shadow the whole register */
  VDMData.VdmSVGA.awreg8514MFData
    [*(PWORD)(psTrapRegInfo->pvTrapWriteShadow)
      >> MFINDX_INDXSHIFT] =
        *(PWORD)(psTrapRegInfo->pvTrapWriteShadow);             /*          */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WriteMFRegWord()
 *
 * 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 vvA8514WriteMFRegWord(
  WORD wData,
  ULONG port,
  PCRF pcrf )
{
  STRAPREGINFO sTrapRegInfo;
  register UINT uiIndex;

  *(PSTRAPREGINFO) SSToDS( &sTrapRegInfo ) =                    /*          */
    psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  *(PWORD)(sTrapRegInfo.pvTrapWriteShadow) = wData;
  uiIndex = wData >> MFINDX_INDXSHIFT;                          /*          */
  sTrapRegInfo.pvTrapWriteShadow =                              /*          */
    (PVOID) &(VDMData.VdmSVGA.awreg8514MFData [uiIndex]);
  vvAcceleratorWrite( (PSTRAPREGINFO) SSToDS( &sTrapRegInfo ),
                      &sTrapWRegWhole,
                      (PVOID) SSToDS( &wData ),
                      FALSE );          /* Not a command */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514PortIndex()
 *
 * DESCRIPTION   = Get index for write of an accelerator data register
 *
 * INPUT         = port
 *
 * OUTPUT        = table index for port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

UINT    PRIVENTRY vvA8514PortIndex( PORT port )
{
  return( (port & 0xfc00) >> 10 );
}
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514Create()
 *
 * DESCRIPTION   = Do the accelerator specific creation:
 *                 set shadow values for write-only ports to some predefined
 *                 benign values.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      VVCreate
 *
 ***********************************************************************/
BOOL PRIVENTRY vvA8514Create( HVDM hvdm)                        /*            */
{
  /*
  ** For write-only ports, initialize the shadow state to some benign
  ** values, such as 0. If cleanup function exists, it may load more
  ** meaningfull values into the shadow.
  */
  UINT uiIndex;
  PSTRAPREGINFO psCurTrapRegInfo;

  for (uiIndex = 0;
       uiIndex < psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
       uiIndex++)
  {
    psCurTrapRegInfo =
      &psCurAcceleratorInfo->
        psAcceleratorTrapRegInfo [uiIndex];
    if( !(psCurTrapRegInfo->fTrapType & READ_MANY) &&
         (psCurTrapRegInfo->fTrapType & WRITE_MANY) == WRITE_MANY )
    {
       if (psCurTrapRegInfo->portTrap == 0x4ae8)
         vvOutputWord( hvdm,                 
                       psCurTrapRegInfo,         
                       0x2);
       else              
         vvOutputWord( hvdm,                 
                       psCurTrapRegInfo,         
                       0x0);
    }
  }
  return TRUE;
}
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514Chip()
 *
 * 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 vvA8514Chip( VOID )
{
  return( FALSE );                                              /*          */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514IsOn()
 *
 * 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 vvA8514IsOn(
  HVDM hvdm )
{
  return( *pVDM( hvdm,
                 PWORD,
                 psCurAcceleratorInfo->psAcceleratorTrapRegInfo
                   [psCurAcceleratorInfo->
                     puifnAcceleratorPortIndex( A8514_ADVCTRL )]
                       .pvTrapWriteShadow )
          & ADVCTRL_VGADISABLE );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514Busy()
 *
 * DESCRIPTION   = Test for accelerator busy
 *
 * INPUT         = uiWRegStatus = index of A8514_STATUS shadow word
 *
 * OUTPUT        = TRUE if busy, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorRead
 *      vvAcceleratorWaitOnEngine
 *
 ***********************************************************************/

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

  psTrapRegInfo =                                               /*          */
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->           /* Command/Flag Reg */
        puifnAcceleratorPortIndex( A8514_STATUS )];
  /* Copy into shadow too, so pass hvdm */                      /*          */
  wData = vvInputWord( hvdm,            /* Get command status *//*          */
                       psTrapRegInfo );                         /*          */
  return( (BOOL) (wData & STATUS_COMMAND_ACTIVE) );
}
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514Reset()
 *
 * 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 vvA8514Reset(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  WORD wDataReset;                                              /*          */
  WORD wDataNormal;                                             /*          */
  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.
  */
  psTrapRegInfo =                                               /*          */
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->
        puifnAcceleratorPortIndex( A8514_SUBSYSCTRL )];
  wDataNormal =                                                 /*          */
    *pVDM( hvdm,
           PWORD,
           psTrapRegInfo->pvTrapWriteShadow );                  /*          */
  wDataReset = (wDataNormal & ~0x4000) | 0x8000;                /*          */
  vvOutputWord( INVALID_HVDM,                                   /*          */
                psTrapRegInfo,                                  /*          */
                wDataReset );                                   /*          */
  vvOutputWord( INVALID_HVDM,                                   /*          */
                psTrapRegInfo,                                  /*          */
                wDataNormal );                                  /*          */
}
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514InstallIoHooks()
 *
 * DESCRIPTION   = Install I/O hooks and set the initial state to trapped.
 *
 *                 This routine installs all the appropriate I/O
 *                 handlers for the current VDM.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514InstallIoHooks( VOID )
{
  register UINT uiIndex;
  PSTRAPREGINFO psCurTrapRegInfo;

  /*
  ** Default to I/O trap on installation
  */
  for (uiIndex = 0;
       uiIndex < psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
       uiIndex++)
  {
    psCurTrapRegInfo =
      &psCurAcceleratorInfo->psAcceleratorTrapRegInfo [uiIndex];
    if( psCurTrapRegInfo->fTrapType
        & (WRITE_REG | READ_REG ) )
      vvAcceleratorInstallWordHooks( psCurTrapRegInfo->portTrap );
  }
}

/***********************************************************************
 *
 * FUNCTION NAME = vvA8514SetBgndOnlyHooks()
 *
 * DESCRIPTION   = Install/remove I/O hooks
 *
 *                 This routine installs all the appropriate I/O
 *                 handlers for the current VDM which trap in background only.
 *                 Usually this is only for performance reasons,
 *                 or because these are write once registers!
 *
 * INPUT         = fl = TRUE for on, FALSE for off
 *                 uiWRegsWriteOnce = Count of write once registers
 *                 aportWReg = Array of write once register ports
 *                 piohlo = Pointer to low address trap routines
 *                 piohhi = Pointer to high address trap routines
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorSetBgndOnlyHooks
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514SetBgndOnlyHooks(
  FLAGS fl )
{
  UINT uiIndex;
  PSTRAPREGINFO psCurTrapRegInfo;

  for (uiIndex = 0;
       uiIndex < psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
       uiIndex++)
  {
    psCurTrapRegInfo =
      &psCurAcceleratorInfo->psAcceleratorTrapRegInfo [uiIndex];
    /*
    ** Don't trap write once (transfer) registers in foreground:
    ** for performance reasons,
    ** and because these are write once registers!
    */
    if( ((psCurTrapRegInfo->fTrapType & WRITE_ALL)
         == WRITE_ONCE)
        || ((psCurTrapRegInfo->fTrapType & READ_ALL)
            == READ_ONCE) )
      vvAcceleratorSetWordHookState( psCurTrapRegInfo->portTrap,
                                     fl );
  }
}

/***********************************************************************
 *
 * FUNCTION NAME = vvA8514SetIoHooks()
 *
 * DESCRIPTION   = Set/reset I/O hooks
 *
 *                 This routine installs all the appropriate I/O
 *                 handlers for the current VDM which trap
 *                 in both foreground and background.
 *
 * INPUT         = fl = TRUE for on, FALSE for off
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514SetIoHooks(
  FLAGS fl )
{
  UINT uiIndex;
  PSTRAPREGINFO psCurTrapRegInfo;

  for (uiIndex = 0;
       uiIndex < psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
       uiIndex++)
  {
    psCurTrapRegInfo =
      &psCurAcceleratorInfo->psAcceleratorTrapRegInfo [uiIndex];
    if( psCurTrapRegInfo->fTrapType
        & (WRITE_REG | READ_REG ) )
      vvAcceleratorSetWordHookState( psCurTrapRegInfo->portTrap,
                                     fl );
  }
}
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514UpdateScrnState()
 *
 * 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
 *      vvAcceleratorUpdateScrnState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514UpdateScrnState(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  pvd->VdmSVGA.ulLogicalBytes =
    (BYTEOF( *pVDM( hvdm,
                    PWORD,
                    psCurAcceleratorInfo->psAcceleratorTrapRegInfo
                      [psCurAcceleratorInfo->
                        puifnAcceleratorPortIndex( A8514_HORZDSP )]
                          .pvTrapWriteShadow ),
             0 ) + 0x0001) * 0x08;
}

/***********************************************************************
 *
 * FUNCTION NAME = vvA8514UpdateModeData()
 *
 * DESCRIPTION   = Update current mode state variables which
 *                 having the accelerator on affects.
 *                 Do not change anything which is already calculated
 *                 correctly by vvUpdateModeData and vvUpdateScreenState.
 *                 Usually there is little or nothing to update.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 * CALLED BY
 *      vvS3UpdateModeData
 *      vvAcceleratorUpdateModeData
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514UpdateModeData(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData( hvdm );

  pvd->vvMode.vvm_ulAdapter = ADAPTER_8514A;
  /* vvUpdateModeData and vvUpdateScreenState work just fine */ /*          */
  /* Having accelerator on does not effect calculations */      /*          */
//pvd->vvMode.vvm_ulFormat = FORMAT_BITMAP;                     /*          */
//pvd->vvMode.vvm_nPlanes = 1;                                  /*          */
//pvd->vvMode.vvm_ulCellWidth = 1;                              /*          */
//pvd->vvMode.vvm_ulCellHeight = 1;                             /*          */
//pvd->vvMode.vvm_nRows =                                       /*          */
//  *pVDM( hvdm,                                                /*          */
//         PWORD,                                               /*          */
//         psCurAcceleratorInfo->psAcceleratorTrapRegInfo       /*          */
//           [psCurAcceleratorInfo->                            /*          */
//             puifnAcceleratorPortIndex( A8514_VERTDSP )]      /*          */
//               .pvTrapWriteShadow ) + 0x0001;                 /*          */
}
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514UpdateIoState()
 *
 * DESCRIPTION   = Transfer hardware I/O state to virtual
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvS3UpdateIoState
 *      vvAcceleratorUpdateIoState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514UpdateIoState(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData( hvdm );
  UINT uiIndex;
  PSTRAPREGINFO psCurTrapRegInfo;

  for (uiIndex = 0;
       uiIndex < psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
       uiIndex++)
  {
    psCurTrapRegInfo =
      &psCurAcceleratorInfo->
        psAcceleratorTrapRegInfo [uiIndex];
    if( (psCurTrapRegInfo->fTrapType & READ_MANY)
        == READ_MANY )
    {
      if( (psCurTrapRegInfo->fTrapType & READ_INDX)
          != READ_INDX )
        /* Read word into shadow for hvdm */                    /*          */
        vvInputWord( hvdm,                                      /*          */
                     psCurTrapRegInfo );                        /*          */
      else
      {
        /*
        ** Then read all the multi-function registers.
        */

        /* Cannot do that on a real A8514! Registers are read only! */
      } /* end if */
    } /* end if */
  } /* end for */
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WaitOutputWord()
 *
 * DESCRIPTION   = Transfer virtual I/O state word to hardware
 *                 But wait for FIFO to be empty enough first
 *
 *
 * INPUT         = hvdm -> VDM
 *                 psTrapRegInfo = port description for data
 *                 wOutput = word to output
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvS3RestoreIoState
 *      vvAcceleratorRestoreIoState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514WaitOutputWord(                        /*          */
  HVDM hvdm,
  PSTRAPREGINFO psTrapRegInfo,
  WORD wOutput )
{
  PSTRAPREGINFO psWaitTrapRegInfo;
  WORD wData;

  psWaitTrapRegInfo =
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->
        puifnAcceleratorPortIndex( A8514_STATUS )];
  while( vvInputWord( INVALID_HVDM,
                      psWaitTrapRegInfo )
         & STATUS_QUEUE7_INUSE )
  { /* Wait */ }
  vvOutputWord( INVALID_HVDM,
                psTrapRegInfo,
                wOutput );
}
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514RestoreIoState()
 *
 * DESCRIPTION   = Transfer virtual I/O state to hardware
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvS3RestoreIoState
 *      vvAcceleratorRestoreIoState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514RestoreIoState(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData( hvdm );
  WORD wData;
  PORT port;
  UINT uiIndex;
  PSTRAPREGINFO psTrapRegInfo;                                  /*          */

  for (uiIndex = 0;
       uiIndex < psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
       uiIndex++)
  {
    psTrapRegInfo =
      &psCurAcceleratorInfo->                                   /*          */
        psAcceleratorTrapRegInfo [uiIndex];
    if( (psTrapRegInfo->fTrapType & WRITE_ALL)                  /*          */
        == WRITE_MANY )
    {
      wData =
        *pVDM( hvdm,
               PWORD,
               psTrapRegInfo->pvTrapWriteShadow );              /*          */
      port = psTrapRegInfo->portTrap;                           /*          */
      if( port == A8514_COMMAND )
         wData &= ~0xe000;              /* NO-OP the command */
      vvA8514WaitOutputWord( INVALID_HVDM,                      /*          */
                             psTrapRegInfo,                     /*          */
                             wData );                           /*          */
    }
  }

  /*
  ** Then restore all the multi-function registers.
  */

  pvd->VdmSVGA.awreg8514MFData [MFREG_READSEL] &=
    ~MFREG_INDXODD;
  psTrapRegInfo =                                               /*          */
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo             /*          */
      [psCurAcceleratorInfo->                                   /*          */
        puifnAcceleratorPortIndex( A8514_MULTIFUNCTION )];      /*          */
  for (uiIndex = 0;
       uiIndex < MFINDX_INDXTOTAL;
       uiIndex++)
  {
    wData = pvd->VdmSVGA.awreg8514MFData [uiIndex];
    vvA8514WaitOutputWord( INVALID_HVDM,                        /*          */
                           psTrapRegInfo,                       /*          */
                           wData );                             /*          */
  }
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514Init()
 *
 * DESCRIPTION   = Initialize addressing of accelerator registers.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorCreate
 *
 ***********************************************************************/

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

/***********************************************************************
 *
 * FUNCTION NAME = vvA8514WriteOnly()
 *
 * DESCRIPTION   = Mark accelerator register as write only.
 *
 * INPUT         = port = port address.
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvATIAcceleratorInit
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514WriteOnly(
  PORT port )
{
  PSTRAPREGINFO psCurTrapRegInfo;

  psCurTrapRegInfo =
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  psCurTrapRegInfo->fTrapType &= ~READ_ALL;
  psCurTrapRegInfo->fTrapType |= R_NE_W;
  (PWORD)psCurTrapRegInfo->pvTrapReadShadow +=
    psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvA8514ReadOnly()
 *
 * DESCRIPTION   = Mark accelerator register as read only.
 *
 * INPUT         = port = port address.
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvATIAcceleratorInit
 *
 ***********************************************************************/

VOID    PRIVENTRY vvA8514ReadOnly(
  PORT port )
{
  PSTRAPREGINFO psCurTrapRegInfo;

  psCurTrapRegInfo =
    &psCurAcceleratorInfo->psAcceleratorTrapRegInfo
      [psCurAcceleratorInfo->puifnAcceleratorPortIndex( port )];
  psCurTrapRegInfo->fTrapType &= ~WRITE_ALL;
  psCurTrapRegInfo->fTrapType |= R_NE_W;
  (PWORD)psCurTrapRegInfo->pvTrapReadShadow +=
    psCurAcceleratorInfo->uiAcceleratorTrapWRegSize;
}

#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA

SA8514INFO sA8514Info =
{
  {
    sA8514TrapRegInfo,
    A8514TRAPREGSIZE,
    &vvA8514PortIndex,
    &vvA8514Chip,
    &vvA8514IsOn,
    &vvA8514Create,                     /*            */
    NULL,    
    &vvA8514Busy,
    &vvA8514Reset,
    &vvA8514InstallIoHooks,
    &vvA8514SetIoHooks,
    &vvA8514SetBgndOnlyHooks,
    &vvA8514UpdateScrnState,
    &vvA8514UpdateIoState,
    &vvA8514RestoreIoState,
    &vvA8514Init,
  },
  &vvA8514ReadMFRegShadow,
};

#pragma  END_SWAP_DATA

