/*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 = VVTSENG.C
 *
 * DESCRIPTIVE NAME = Virtual Video Tseng 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 PBYTE pPhysVRAM;                 //@senja
extern ULONG ulSVGAChipType;
extern OEMINFO sOEMData;
extern BOOL fSVGASeqFixups;
extern PSACCELERATORINFO psCurAcceleratorInfo;                  /*          */
extern STRAPREGPARTINFO sTrapWRegLow;                           /*          */
extern STRAPREGPARTINFO sTrapWRegHigh;                          /*          */
extern STRAPREGPARTINFO sTrapWRegWhole;                         /*          */
extern BYTE abCRTCBMask[];
extern BYTE abATCMask[];                                        /*            */

/* JWK01 start */
extern PLE pleCRTData;
extern PLE pleCRTIndx;
extern PLE pleGDCData;
extern PLE pleGDCIndx;
extern PLE pleATC0;                                             /*          */
extern PLE pleATCx;
extern PLE pleATC1;                                             /*          */
extern PLE pleSEQData;
extern PLE pleSEQIndx;
extern PLE pleVGADACMask;
extern PLE pleVGADACRead;
extern PLE pleVGADACWrite;
extern PLE pleVGADACData;
extern PVDM  pvdmStartupMMIOActive;                                            /*            */
extern ULONG npgStartupMMIOActive;                                             /*            */

     /*            */
VOID PRIVENTRY TsengICSave(register PVDMDATA pvd, register TSENGMMIO *pW32);
VOID PRIVENTRY TsengPCSave(register PVDMDATA pvd, register TSENGMMIO *pW32);
VOID PRIVENTRY TsengICRestore(register PVDMDATA pvd, register TSENGMMIO *pW32);
VOID PRIVENTRY TsengPCRestore(register PVDMDATA pvd, register TSENGMMIO *pW32);
BOOL PRIVENTRY UpdateMMIO(HVDM hvdm);           /*            */

/* JWK01 end */


CHAR pszTsengAdapterName [] = "TSENG" ;                         /*          */

PCHAR ppszTsengChipNames [MAX_TSENG_CHIP] =                     /*          */
{  /* As defined in svgadefs.h and used by SVGA.EXE et al */    /* JWK01 */
  TSENG_ET3000_NAME,                                            /* JWK01 */
  TSENG_ET4000_NAME,                                            /* JWK01 */
  TSENG_ET4000W32_NAME,                                         /* JWK01 */
  TSENG_ET4000W32I_NAME,                                        /* JWK01 */
  TSENG_ET4000W32IB_NAME,                                       /* JWK01 */
  TSENG_ET4000W32IC_NAME,                                       /* JWK01 */
  TSENG_ET4000W32PA_NAME,                                       /* JWK01 */
  TSENG_ET4000W32PB_NAME,                                       /* JWK01 */
  TSENG_ET4000W32PC_NAME,                                       /* JWK01 */
  TSENG_ET4000W32ID_NAME,                                       /* JWK05 */
  TSENG_ET4000W32PD_NAME,                                       /* JWK05 */
  TSENG_ET4000W32PX_NAME,                                       /* JWK23 */
};

USHORT  uTsengIOD = 0xffff;                                     /* JWK01 */
PFN     pfnTsengACLSave;                                        /* JWK01 */
PFN     pfnTsengACLRestore;                                     /* JWK01 */

#define hmxMMIO pVDMData(hvdm)->VdmSVGA.VdmTSENG.hmxMMIO      /*            */
PVOID   pMMIO = NULL;
VDHMAPTARGET vdhmtMMU;
VDHMAPSOURCE vdhmsMMU;
VDHMAPTARGET vdhmtMMIO;
VDHMAPSOURCE vdhmsMMIO;
VDHMAPTARGET vdhmtEMMIO;
VDHMAPSOURCE vdhmsEMMIO;


BYTE    aregCRTCBInit [TOTAL_TSENG_CRTCBREGS];                  /* JWK01 */

#ifdef SVGA
 /*
 **
 **  These bit masks determine which indexed registers in each group
 **  are saved/restored. They are initialised to standard VGA registers
 **  and modified during the PMI file parsing to reflect the particular
 **  adapter's extended registers. Note, each array must end with a zero
 **  which will fill the un-initialised elements.
 */

//@V3.0YEE01 BYTE    abCRTCBMask[32] = {0x00, 0x00, 0x00, 0x00,  /* ports 0xe0-0xff */
//@V3.0YEE01               0x00, 0x00, 0x00, 0x00,
//@V3.0YEE01               0x00, 0x00, 0x00, 0x00,
//@V3.0YEE01               0x00, 0x00, 0x00, 0x00,
//@V3.0YEE01               0x00, 0x00, 0x00, 0x00,
//@V3.0YEE01               0x00, 0x00, 0x00, 0x00,
//@V3.0YEE01               0x00, 0x00, 0x00, 0x00,
//@V3.0YEE01               0x00, 0x00, 0xff, 0xff};

BYTE abCRTCBMask [MAX_CRTCBREGS] =
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0 */
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff  /* 0xf8 */
};


#endif /* SVGA */


IOH iohTsengSegSelect [2] =            /* 03cd */
{
  {
    NULL,
    &VVWriteTsengSegSelectFgnd,
  },
  {
    &VVReadTsengSegSelectBgnd,
    &VVWriteTsengSegSelectBgnd,
  },
};

IOH iohTsengSegSelect2 [2] =           /* 03cb */        /* JWK01 */
{                                                        /* JWK01 */
  {                                                      /* JWK01 */
    NULL,                                                /* JWK01 */
    &VVWriteTsengSegSelect2Fgnd,                         /* JWK01 */
  },                                                     /* JWK01 */
  {                                                      /* JWK01 */
    &VVReadTsengSegSelect2Bgnd,                          /* JWK01 */
    &VVWriteTsengSegSelect2Bgnd,                         /* JWK01 */
  },                                                     /* JWK01 */
};                                                       /* JWK01 */

IOH iohTsengCRTCBData [2] =            /* 217B */       /* JWK01 */
{                                                       /* JWK01 */
  {                                                     /* JWK01 */
    NULL,                                               /* JWK01 */
    &VVWriteTsengCRTCBDataFgnd,                         /* JWK01 */
  },                                                    /* JWK01 */
  {                                                     /* JWK01 */
    &VVReadTsengCRTCBDataBgnd,                          /* JWK01 */
    &VVWriteTsengCRTCBDataBgnd,                         /* JWK01 */
  },                                                    /* JWK01 */
};                                                      /* JWK01 */

IOH iohTsengCRTCBIndex [2] =            /* 217A */      /* JWK01 */
{                                                       /* JWK01 */
  {                                                     /* JWK01 */
    NULL,                                               /* JWK01 */
    &VVWriteTsengCRTCBIndexFgnd,                        /* JWK01 */
  },                                                    /* JWK01 */
  {                                                     /* JWK01 */
    &VVReadTsengCRTCBIndexBgnd,                         /* JWK01 */
    &VVWriteTsengCRTCBIndexBgnd,                        /* JWK01 */
  },                                                    /* JWK01 */
};                                                      /* JWK01 */

IOH iohOrchidClkSelect [2] =            /* 03dd */
{
  {
    &VVReadOrchidClockSelectFgnd,                               /*          */
    &VVWriteOrchidClockSelectFgnd,                              /*          */
  },
  {
    &VVReadOrchidClockSelectBgnd,                               /*          */
    &VVWriteOrchidClockSelectBgnd,                              /*          */
  },
};

PLE pleTsengSegSelect2 =                                        /*          */
{                                                               /*          */
  {                                                             /*          */
    PORT_TSENG_SEGSELECT2,              /* 03cb */              /*          */
    &VDMData.VdmSVGA.VdmTSENG.regTsengSegSelect2,               /* JWK01 */
    &VDMData.VdmSVGA.VdmTSENG.regTsengSegSelect2,               /* JWK01 */
    PORTF_NOTVALIDSVGAPORT                                      /*            */
      | WRITE_MANY | READ_MANY | R_EQ_W,                        /*          */
    iohTsengSegSelect2,                                         /*          */
  },                                                            /*          */
  0,                                                            /*          */
  NULL,                                                         /*          */
};                                                              /*          */

PLE pleTsengSegSelect =                                         /*          */
{
  {                                                             /*          */
    PORT_TSENG_SEGSELECT,               /* 03cd */
    &VDMData.VdmSVGA.VdmTSENG.regTsengSegSelect,                /* JWK01 */
    &VDMData.VdmSVGA.VdmTSENG.regTsengSegSelect,                /* JWK01 */
    PORTF_NOTVALIDSVGAPORT                                      /*            */
      | WRITE_MANY | READ_MANY | R_EQ_W,                        /*          */
    iohTsengSegSelect,                                          /*          */
  },                                                            /*          */
  0,
  NULL,
};

PLE pleOrchidClkSelect =                                        /*          */
{                                                               /*          */
  {                                                             /*          */
    PORT_ORCHID_CLKSELECT,              /* 03dd */              /*          */
    &VDMData.VdmSVGA.regOrchidClockSelect,                      /*          */
    &VDMData.VdmSVGA.regOrchidClockSelect,                      /*          */
    PORTF_NOTVALIDSVGAPORT                                      /*            */
      | WRITE_MANY | READ_MANY | R_NE_W,                        /*          */
    iohOrchidClkSelect,                                         /*          */
  },                                                            /*          */
  0,                                                            /*          */
  NULL,                                                         /*          */
};                                                              /*          */

PLE pleTsengCRTCBIndex =                                        /* JWK01 */
{                                                               /* JWK01 */
  {                                                             /* JWK01 */
    PORT_TSENG_CRTCB_INDEX,                                     /* JWK01 */
    &VDMData.VdmSVGA.VdmTSENG.regCRTCBIndex,                    /* JWK01 */
    &VDMData.VdmSVGA.VdmTSENG.regCRTCBIndex,                    /* JWK01 */
    PORTF_NOTVALIDSVGAPORT                                      /*            */
      | WRITE_MANY | READ_MANY | R_EQ_W,                        /* JWK01 */
    iohTsengCRTCBIndex,                                         /* JWK01 */
  },                                                            /* JWK01 */
  0,                                                            /* JWK01 */
  NULL,                                                         /* JWK01 */
};                                                              /* JWK01 */

PLE pleTsengCRTCBData =                                         /* JWK01 */
{                                                               /* JWK01 */
  {                                                             /* JWK01 */
    PORT_TSENG_CRTCB_DATA,                                      /* JWK01 */
    &VDMData.VdmSVGA.VdmTSENG.aregCRTCBData[0],                 /* JWK01 */
    &VDMData.VdmSVGA.VdmTSENG.aregCRTCBData[0],                 /* JWK01 */
    PORTF_NOTVALIDSVGAPORT                                      /*            */
       | WRITE_INDX | READ_INDX | R_EQ_W,                       /* JWK01 */
    iohTsengCRTCBData,                                          /* JWK01 */
  },                                                            /* JWK01 */
  TOTAL_TSENG_CRTCBREGS,                                        /* JWK01 */
  &pleTsengCRTCBIndex,                                          /* JWK01 */
#ifdef SVGA                                                     /* JWK01 */
  &abCRTCBMask[0],                                              /* JWK01 */
  &abCRTCBMask[0],                                              /*            */
#endif /* SVGA */                                               /* JWK01 */
};                                                              /* JWK01 */




 /*
 ** The following is a complete list of word registers, all of which use
 ** the following I/O handlers:
 **
 **     vvTsengReadWRegByteL      vvTsengReadWRegByteH      vvTsengReadWRegWord
 **     vvTsengWriteWRegByteL     vvTsengWriteWRegByteH     vvTsengWriteWRegWord
 */

IOH iohTsengW32wreg [2];

/*
** 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 TSENGW32TRAPREGSIZE 0x01
#define WS(x) ((PVOID)(&VDMData.VdmSVGA.wRegShadow [x]))

STRAPREGINFO sTsengW32TrapRegInfo [TSENGW32TRAPREGSIZE] =
{
  {/*x00*/0x0000, WS(0x00), WS(0x00), WRITE_NONE | READ_NONE | NONE, iohTsengW32wreg  }
};

#pragma  END_SWAP_DATA

#pragma  BEGIN_SWAP_CODE
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengAcceleratorDestroy()
 *
 * DESCRIPTION   = Terminate VDM
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 * CALLED BY
 ***********************************************************************/
VOID    PRIVENTRY vvTsengAcceleratorDestroy(
  HVDM hvdm )
{
    DestroyMutexSem(hmxMMIO);           /*            */
}

/***********************************************************************
 *
 * FUNCTION NAME = vvTsengAcceleratorCreate()
 *
 * DESCRIPTION   = Initialize Accelerator code
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      VVCreate (to decide whether to create semaphores)
 *      Calls accelerator creation routines to do specific stuff, such as
 *      initialize the shadow state of write-only regs and create private sems.
 ***********************************************************************/
BOOL    PRIVENTRY vvTsengAcceleratorCreate(
  HVDM hvdm )
{
     return( CreateMutexSem(&hmxMMIO));         /*            */
}
/***************************************************************************
 *
 * FUNCTION NAME = vvTsengEditTables()
 *
 * DESCRIPTION   = Called once to do SVGA-specific initialization
 *
 * INPUT         =
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID PRIVENTRY vvTsengEditTables( VOID )
{
USHORT IODFound = 0xffff;         /* init not found */
USHORT TSENGBaseIOData, TSENGBaseIOIndex;



  fSVGASeqFixups = FALSE;                                       /*          */

  abATCMask [0x16] = 0xff;                                      /*@V3.0YEE01*/
  abATCMask [0x17] = 0xff;                                      /*@V3.0YEE01*/
  pleTsengSegSelect.sTrapBRegInfo.fTrapType    &= ~ PORTF_NOTVALIDSVGAPORT; /*            */
  pleOrchidClkSelect.sTrapBRegInfo.fTrapType   &= ~ PORTF_NOTVALIDSVGAPORT; /*            */

  if (ulSVGAChipType >= TSENG_ET4000W32_CHIP )
  {

     /*
     ** Set the fall back MMIO region.                            
     */
     pvdmStartupMMIOActive = (PVDM) 0xBf000;
     npgStartupMMIOActive = 1;
     /* set accelerator save/restore function pointers */

      switch (ulSVGAChipType)
      {
          case TSENG_ET4000W32_CHIP:
          case TSENG_ET4000W32I_CHIP:
          case TSENG_ET4000W32IB_CHIP:
          case TSENG_ET4000W32IC_CHIP:
          case TSENG_ET4000W32ID_CHIP:                        /*JWK05*/

                pfnTsengACLSave = (PFN) &TsengICSave;
                pfnTsengACLRestore = (PFN) &TsengICRestore;

          break;

          default:                                            /*JWK05*/
          case TSENG_ET4000W32PA_CHIP:
          case TSENG_ET4000W32PB_CHIP:
          case TSENG_ET4000W32PC_CHIP:
          case TSENG_ET4000W32PD_CHIP:                        /*JWK05*/
          case TSENG_ET4000W32PX_CHIP:                        /*JWK23*/

                pfnTsengACLSave = (PFN) &TsengPCSave;
                pfnTsengACLRestore = (PFN) &TsengPCRestore;

          break;

      }


    /*
    ** Enable appropriate trap list entries by removing NOTRAP flag!
    */

    pleTsengSegSelect2.sTrapBRegInfo.fTrapType &= ~ PORTF_NOTVALIDSVGAPORT; /*            */
    pleTsengCRTCBIndex.sTrapBRegInfo.fTrapType &= ~ PORTF_NOTVALIDSVGAPORT; /*            */
    pleTsengCRTCBData.sTrapBRegInfo.fTrapType  &= ~ PORTF_NOTVALIDSVGAPORT; /*            */

    /*!!Why not use zero instead of 0xffff ?? */                /*          */
    /*!!because 0 <= IODFound <= 7 */                           /*          */
    if (uTsengIOD == 0xffff)      /* if IOD not determined yet */
    {
  _asm {

        push    dx;
        push    cx;
        push    bx;
        push    ax;

        mov     dx, PORT_TSENG_CRTCB_INDEX ; get the CRTCB register base default
        and     dx, 0xff0f                 ; mask off IOD modifier

GTBIOLoop:
        in      al, dx                  ; read index value
        mov     cl, al                  ; save index value for later
        mov     al, TSENG_CRTCB_INDEX_COLOR_DEPTH
        out     dx, al                  ; point to color depth
        inc     dx                      ; point to data
        in      al, dx                  ; get original value
        mov     ah, al                  ; save original value
        xor     al, 8fh                 ; create a new value write/readback
        and     al, 0cfh                ; mask off reserved bits
        mov     bl, al                  ; save new value
        out     dx, al                  ; write new value
        in      al, dx                  ; read back data
;;;     and     al, 0cfh                ; mask off reserved bits
        cmp     al, bl                  ; see if same data 'saved'
        je      FoundTsengInstance

        dec     dx                      ; back to index
        add     dx, 10h                 ; try next IO Address
        cmp     dx,TSENG_BASE_INDEX+070h ; try from base plus seven addresses
        jbe     GTBIOLoop               ;  yup - try again
        jmp     short GTBIOSearchDone   ; no Instance found

FoundTsengInstance:
        mov     al, ah                  ; get original data value
        out     dx, al                  ; write back original data value
        mov     TSENGBaseIOData, dx     ; report back BaseIO data port value
        dec     dx                      ; point back to index
        mov     TSENGBaseIOIndex, dx    ; report back BaseIO index port value
        mov     al, cl                  ; get original index value
        out     dx, al                  ; restore index value
        shr     dx, 4                   ; get rid of low nibble
        and     dx, 07h                 ; make number 0-7
        mov     IODFound, dx            ; save number

 GTBIOSearchDone:
        pop    ax;
        pop    bx;
        pop    cx;
        pop    dx;
    }


      /*!!Why not use zero instead of 0xffff ?? */              /*          */
      if (IODFound != 0xffff)
      {
        uTsengIOD = IODFound;

        pleTsengCRTCBData.sTrapBRegInfo.portTrap  = TSENGBaseIOData;
        pleTsengCRTCBIndex.sTrapBRegInfo.portTrap = TSENGBaseIOIndex;

        IODFound = ((~IODFound) & 0x07) << 12;   /* modify modifier for following group */

        pleCRTData.sTrapBRegInfo.portTrap    |= IODFound;       /*          */
        pleCRTIndx.sTrapBRegInfo.portTrap    |= IODFound;       /*          */

        pleGDCData.sTrapBRegInfo.portTrap    |= IODFound;       /*          */
        pleGDCIndx.sTrapBRegInfo.portTrap    |= IODFound;       /*          */

        pleATC0.sTrapBRegInfo.portTrap       |= IODFound;       /*          */
        pleATCx.sTrapBRegInfo.portTrap       |= IODFound;       /*          */
        /*!!What about ATC1?? */                                /*          */
        pleATC1.sTrapBRegInfo.portTrap       |= IODFound;       /*          */

        pleSEQData.sTrapBRegInfo.portTrap    |= IODFound;       /*          */
        pleSEQIndx.sTrapBRegInfo.portTrap    |= IODFound;       /*          */

        pleVGADACMask.sTrapBRegInfo.portTrap  |= IODFound;      /*          */
        pleVGADACRead.sTrapBRegInfo.portTrap  |= IODFound;      /*          */
        pleVGADACWrite.sTrapBRegInfo.portTrap |= IODFound;      /*          */
        pleVGADACData.sTrapBRegInfo.portTrap  |= IODFound;      /*          */
      }
      else
      {
          ;
      }
    }
  }
}


/***************************************************************************
 *
 * FUNCTION NAME = vvTsengAdjustedPort()
 *
 * DESCRIPTION   = Adjust given port # for current state
 *
 *                 Strips off flags attached to port #, if any, and adjusts
 *                 the value of the port, if necessary.
 *
 * INPUT         = psTrapRegInfo contains port #
 *
 * OUTPUT        = port (possibly unchanged)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

PORT PRIVENTRY vvTsengAdjustedPort(
  PSTRAPREGINFO psTrapRegInfo )
{

  return( ((psTrapRegInfo->fTrapType & PORTF_COLRMONO)
                                        /* Make mono first */
           ? (((psTrapRegInfo->portTrap & ~ 0x0040) | 0x0020)   /*          */
              + ((INB( PORT_GDCPOS1 )   /* Add in color */      /*          */
                  & MISCOUT_COLRPORTS)                          /*          */
                 << 5))                                         /*          */
  /*          ^ Definitely PLUS and not OR!    */               /*          */
           : psTrapRegInfo->portTrap) );                        /*          */
}
                                                                /*          */

/***********************************************************************
 *
 * FUNCTION NAME = vvTsengIsOn()
 *
 * 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 vvTsengW32IsOn(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  pvd->VdmSVGA.VdmTSENG.flW32AcceleratorOn = FALSE;
  if ((pvd->flVDMVideo & VDM_IOINIT) &&                          /*            */
      (pvd->aregCRTData[0x36] & 0x38) &&
      pvd->VdmSVGA.VdmTSENG.flW32ACLMapped)
    pvd->VdmSVGA.VdmTSENG.flW32AcceleratorOn = TRUE;
  return pvd->VdmSVGA.VdmTSENG.flW32AcceleratorOn;
}


/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32Chip()
 *
 * 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 vvTsengW32Chip( VOID )
{

   if (ulSVGAChipType >= TSENG_ET4000W32_CHIP)
   {
         return (TRUE);
   }
   else
   {
         return (FALSE);
   }
}

/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32UpdateModeData()
 *
 * 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
 *      vvAcceleratorUpdateModeData
 *
 ***********************************************************************/

VOID    PRIVENTRY vvTsengW32UpdateModeData(  HVDM hvdm )
{
  if(vvTsengW32Chip() && vvTsengW32IsOn(hvdm))               /*            */
     pVDMData(hvdm)->flVDMXVideo |= VDMX_ENHANCEDMODE;
}

VOID PRIVENTRY TsengICRestore(register PVDMDATA pvd, register TSENGMMIO *pW32) /* @senja */
{


    // MMU Regs

        pW32->MMUBasePointer0 = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer0;
        pW32->MMUBasePointer1 = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer1;
        pW32->MMUBasePointer2 = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer2;
        pW32->MMUControl      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUControl;


    // Non-Queued Regs

        pW32->ACLSuspendTerminate    = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSuspendTerminate;
//skip  pW32->ACLOperationState      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLOperationState;
        pW32->ACLSyncEnable          = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSyncEnable;
        pW32->ACLWriteInterfaceValid = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLWriteInterfaceValid;
        pW32->ACLInterruptMask       = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptMask;
//skip  pW32->ACLInterruptStatus     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptStatus;
        pW32->ACLAcceleratorStatus   = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLAcceleratorStatus;
        pW32->ACLXPosition           = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXPosition;
        pW32->ACLYPosition           = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYPosition;


    // Queued Regs

        // write all from SAVE1


        pW32->ACLPatternAddress     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternAddress;
        pW32->ACLSourceAddress      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceAddress;
        pW32->ACLPatternYOffset     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternYOffset;
        pW32->ACLSourceYOffset      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceYOffset;
        pW32->ACLDestinationYOffset = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationYOffset;
        pW32->ACLPixelDepth         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPixelDepth;
        pW32->ACLXYDirection        = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXYDirection;
        pW32->ACLPatternWrap        = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternWrap;
        pW32->ACLSourceWrap         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceWrap;
        pW32->ACLXCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXCount;
        pW32->ACLYCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYCount;
        pW32->ACLRoutingControl     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLRoutingControl;
        pW32->ACLBackgroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLBackgroundROP;
        pW32->ACLForegroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLForegroundROP;
        pW32->ACLDestinationAddress = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationAddress;
        pW32->ACLMixAddress         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixAddress;
        pW32->ACLMixYOffset         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixYOffset;
        pW32->ACLErrorTerm          = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLErrorTerm;
        pW32->ACLDeltaMinor         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMinor;
        pW32->ACLDeltaMajor         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMajor;

        // transfer queued regs to internal regs)

        pW32->ACLOperationState = TSENG_ACL_RSO;
        // Put queued copy of status into queue

        pW32->ACLAcceleratorStatus = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLAcceleratorStatus;

    //Write from SAVE2

        // Queued Regs

        pW32->ACLPatternAddress     = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternAddress;
        pW32->ACLSourceAddress      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceAddress;
        pW32->ACLPatternYOffset     = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternYOffset;
        pW32->ACLSourceYOffset      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceYOffset;
        pW32->ACLDestinationYOffset = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationYOffset;
        pW32->ACLPixelDepth         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPixelDepth;
        pW32->ACLXYDirection        = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXYDirection;
        pW32->ACLPatternWrap        = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternWrap;
        pW32->ACLSourceWrap         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceWrap;
        pW32->ACLXCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXCount;
        pW32->ACLYCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLYCount;
        pW32->ACLRoutingControl     = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLRoutingControl;
        pW32->ACLBackgroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLBackgroundROP;
        pW32->ACLForegroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLForegroundROP;
        pW32->ACLDestinationAddress = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationAddress;
        pW32->ACLMixAddress         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixAddress;
        pW32->ACLMixYOffset         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixYOffset;
        pW32->ACLErrorTerm          = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLErrorTerm;
        pW32->ACLDeltaMinor         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMinor;
        pW32->ACLDeltaMajor         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMajor;

        if( (pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSuspendTerminate & (TSENG_ACL_TO + TSENG_ACL_SO)) == 0 &&
            (pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLAcceleratorStatus & (TSENG_ACL_SSO+TSENG_ACL_WRST)) == (TSENG_ACL_SSO+TSENG_ACL_WRST))
                pW32->ACLOperationState = TSENG_ACL_RMO;

}

VOID PRIVENTRY TsengPCRestore(register PVDMDATA pvd, register TSENGMMIO *pW32) /* @senja */
{


    // MMU Regs

        pW32->MMUBasePointer0 = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer0;
        pW32->MMUBasePointer1 = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer1;
        pW32->MMUBasePointer2 = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer2;
        pW32->MMUControl      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUControl;


    // Non-Queued Regs

        pW32->ACLSuspendTerminate    = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSuspendTerminate;
//skip  pW32->ACLOperationState      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLOperationState;
        pW32->ACLSyncEnable          = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSyncEnable;
        pW32->ACLWriteInterfaceValid = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLWriteInterfaceValid;
        pW32->ACLInterruptMask       = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptMask;
//skip  pW32->ACLInterruptStatus     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptStatus;
        pW32->ACLAcceleratorStatus   = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLAcceleratorStatus;
        pW32->ACLXPosition           = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXPosition;
        pW32->ACLYPosition           = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYPosition;


    // Queued Regs

        // write all from SAVE1

        pW32->ACLPatternAddress     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternAddress;
        pW32->ACLSourceAddress      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceAddress;
        pW32->ACLPatternYOffset     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternYOffset;
        pW32->ACLSourceYOffset      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceYOffset;
        pW32->ACLDestinationYOffset = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationYOffset;
        pW32->ACLPixelDepth         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPixelDepth;
        pW32->ACLXYDirection        = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXYDirection;
        pW32->ACLPatternWrap        = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternWrap;
        pW32->ACLSourceWrap         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceWrap;
        pW32->ACLXCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXCount;
        pW32->ACLYCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYCount;
        pW32->ACLRoutingControl     = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLRoutingControl;
        pW32->ACLBackgroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLBackgroundROP;
        pW32->ACLForegroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLForegroundROP;
        pW32->ACLDestinationAddress = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationAddress;
        pW32->ACLMixAddress         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixAddress;
        pW32->ACLMixYOffset         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixYOffset;
        pW32->ACLErrorTerm          = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLErrorTerm;
        pW32->ACLDeltaMinor         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMinor;
        pW32->ACLDeltaMajor         = pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMajor;

        // transfer queued regs to internal regs)

        pW32->ACLOperationState = TSENG_ACL_RSO;

        // Put queued copy of status into queue

        pW32->ACLAcceleratorStatus = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLAcceleratorStatus;

    //Write from SAVE2

        // Queued Regs

        pW32->ACLPatternAddress     = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternAddress;
        pW32->ACLSourceAddress      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceAddress;
        pW32->ACLPatternYOffset     = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternYOffset;
        pW32->ACLSourceYOffset      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceYOffset;
        pW32->ACLDestinationYOffset = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationYOffset;
        pW32->ACLPixelDepth         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPixelDepth;
        pW32->ACLXYDirection        = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXYDirection;
        pW32->ACLPatternWrap        = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternWrap;
        pW32->ACLSourceWrap         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceWrap;
        pW32->ACLXCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXCount;
        pW32->ACLYCount             = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLYCount;
        pW32->ACLRoutingControl     = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLRoutingControl;
        pW32->ACLBackgroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLBackgroundROP;
        pW32->ACLForegroundROP      = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLForegroundROP;
        pW32->ACLDestinationAddress = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationAddress;
        pW32->ACLMixAddress         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixAddress;
        pW32->ACLMixYOffset         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixYOffset;
        pW32->ACLErrorTerm          = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLErrorTerm;
        pW32->ACLDeltaMinor         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMinor;
        pW32->ACLDeltaMajor         = pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMajor;

        if( (pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSuspendTerminate & (TSENG_ACL_TO + TSENG_ACL_SO)) == 0 &&
            (pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLAcceleratorStatus & (TSENG_ACL_SSO+TSENG_ACL_WRST)) == (TSENG_ACL_SSO+TSENG_ACL_WRST))
                pW32->ACLOperationState = TSENG_ACL_RMO;

}








VOID PRIVENTRY TsengICSave(register PVDMDATA pvd, register TSENGMMIO *pW32) /* @senja */
{


    // MMU Regs


        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer0  = pW32->MMUBasePointer0;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer1  = pW32->MMUBasePointer1;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer2  = pW32->MMUBasePointer2;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUControl       = pW32->MMUControl;


    // Non-Queued Regs


        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSuspendTerminate    = pW32->ACLSuspendTerminate;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLOperationState      = pW32->ACLOperationState;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSyncEnable          = pW32->ACLSyncEnable;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLWriteInterfaceValid = pW32->ACLWriteInterfaceValid;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptMask       = pW32->ACLInterruptMask;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptStatus     = pW32->ACLInterruptStatus;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLAcceleratorStatus   = pW32->ACLAcceleratorStatus;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXPosition           = pW32->ACLXPosition;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYPosition           = pW32->ACLYPosition;

    // Queued Regs

        // suspend operation

        pW32->ACLSuspendTerminate = TSENG_ACL_SO;
        pW32->ACLSuspendTerminate = 0;


        // read all to SAVE1

        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternAddress        = pW32->ACLPatternAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceAddress         = pW32->ACLSourceAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternYOffset        = pW32->ACLPatternYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceYOffset         = pW32->ACLSourceYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationYOffset    = pW32->ACLDestinationYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPixelDepth            = pW32->ACLPixelDepth;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXYDirection           = pW32->ACLXYDirection;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternWrap           = pW32->ACLPatternWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceWrap            = pW32->ACLSourceWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXCount                = pW32->ACLXCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYCount                = pW32->ACLYCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLRoutingControl        = pW32->ACLRoutingControl;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLBackgroundROP         = pW32->ACLBackgroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLForegroundROP         = pW32->ACLForegroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationAddress    = pW32->ACLDestinationAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixAddress            = pW32->ACLMixAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixYOffset            = pW32->ACLMixYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLErrorTerm             = pW32->ACLErrorTerm;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMinor            = pW32->ACLDeltaMinor;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMajor            = pW32->ACLDeltaMajor;

        // transfer queued regs to internal regs)

        pW32->ACLOperationState = TSENG_ACL_RSO;

        pW32->ACLOperationState = TSENG_ACL_RSO;

        // get copy of status that was in the queue

        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLAcceleratorStatus = pW32->ACLAcceleratorStatus;

    //read and save SAVE2

        // Queued Regs

        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternAddress        = pW32->ACLPatternAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceAddress         = pW32->ACLSourceAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternYOffset        = pW32->ACLPatternYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceYOffset         = pW32->ACLSourceYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationYOffset    = pW32->ACLDestinationYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPixelDepth            = pW32->ACLPixelDepth;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXYDirection           = pW32->ACLXYDirection;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternWrap           = pW32->ACLPatternWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceWrap            = pW32->ACLSourceWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXCount                = pW32->ACLXCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLYCount                = pW32->ACLYCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLRoutingControl        = pW32->ACLRoutingControl;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLBackgroundROP         = pW32->ACLBackgroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLForegroundROP         = pW32->ACLForegroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationAddress    = pW32->ACLDestinationAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixAddress            = pW32->ACLMixAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixYOffset            = pW32->ACLMixYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLErrorTerm             = pW32->ACLErrorTerm;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMinor            = pW32->ACLDeltaMinor;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMajor            = pW32->ACLDeltaMajor;

        pW32->ACLSuspendTerminate = TSENG_ACL_TO;
        pW32->ACLSuspendTerminate = 0;


}




VOID PRIVENTRY  TsengPCSave(register PVDMDATA pvd, register TSENGMMIO *pW32) /* @senja */
{

    // MMU Regs

        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer0  = pW32->MMUBasePointer0;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer1  = pW32->MMUBasePointer1;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUBasePointer2  = pW32->MMUBasePointer2;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.MMUControl       = pW32->MMUControl;


    // Non-Queued Regs

        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSuspendTerminate    = pW32->ACLSuspendTerminate;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLOperationState      = pW32->ACLOperationState;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSyncEnable          = pW32->ACLSyncEnable;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLWriteInterfaceValid = pW32->ACLWriteInterfaceValid;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptMask       = pW32->ACLInterruptMask;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLInterruptStatus     = pW32->ACLInterruptStatus;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLAcceleratorStatus   = pW32->ACLAcceleratorStatus;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXPosition           = pW32->ACLXPosition;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYPosition           = pW32->ACLYPosition;

    // Queued Regs

        // suspend operation

        pW32->ACLSuspendTerminate = TSENG_ACL_SO;
        pW32->ACLSuspendTerminate = 0;


        // read all to SAVE1


        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternAddress        = pW32->ACLPatternAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceAddress         = pW32->ACLSourceAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternYOffset        = pW32->ACLPatternYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceYOffset         = pW32->ACLSourceYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationYOffset    = pW32->ACLDestinationYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPixelDepth            = pW32->ACLPixelDepth;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXYDirection           = pW32->ACLXYDirection;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLPatternWrap           = pW32->ACLPatternWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLSourceWrap            = pW32->ACLSourceWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLXCount                = pW32->ACLXCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLYCount                = pW32->ACLYCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLRoutingControl        = pW32->ACLRoutingControl;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLBackgroundROP         = pW32->ACLBackgroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLForegroundROP         = pW32->ACLForegroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDestinationAddress    = pW32->ACLDestinationAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixAddress            = pW32->ACLMixAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLMixYOffset            = pW32->ACLMixYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLErrorTerm             = pW32->ACLErrorTerm;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMinor            = pW32->ACLDeltaMinor;
        pvd->VdmSVGA.VdmTSENG.MMIOSave1.ACLDeltaMajor            = pW32->ACLDeltaMajor;

        // transfer queued regs to internal regs)

        pW32->ACLOperationState = TSENG_ACL_RSO;
        pW32->ACLOperationState = TSENG_ACL_RSO;
        // get copy of status that was in the queue

        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLAcceleratorStatus = pW32->ACLAcceleratorStatus;

    //read and save SAVE2

        // Queued Regs

        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternAddress        = pW32->ACLPatternAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceAddress         = pW32->ACLSourceAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternYOffset        = pW32->ACLPatternYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceYOffset         = pW32->ACLSourceYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationYOffset    = pW32->ACLDestinationYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPixelDepth            = pW32->ACLPixelDepth;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXYDirection           = pW32->ACLXYDirection;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLPatternWrap           = pW32->ACLPatternWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLSourceWrap            = pW32->ACLSourceWrap;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLXCount                = pW32->ACLXCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLYCount                = pW32->ACLYCount;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLRoutingControl        = pW32->ACLRoutingControl;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLBackgroundROP         = pW32->ACLBackgroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLForegroundROP         = pW32->ACLForegroundROP;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDestinationAddress    = pW32->ACLDestinationAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixAddress            = pW32->ACLMixAddress;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLMixYOffset            = pW32->ACLMixYOffset;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLErrorTerm             = pW32->ACLErrorTerm;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMinor            = pW32->ACLDeltaMinor;
        pvd->VdmSVGA.VdmTSENG.MMIOSave2.ACLDeltaMajor            = pW32->ACLDeltaMajor;

        pW32->ACLSuspendTerminate = TSENG_ACL_TO;
        pW32->ACLSuspendTerminate = 0;


}
/*****************************************************************************
 *
 * FUNCTION NAME = UpdateMMIO(HVDM hvdm)
 *
 * DESCRIPTION   = determine current offset into memory mapped IO
 *
 * INPUT         = NONE
 * OUTPUT        = NONE   >>> assumes semaphore to MMIO owned <<<<
 *
 * RETURN-NORMAL = TRUE if MMIO map in VGA 128K range enabled
 * RETURN-ERROR  = FALSE if no MMIO or MMIO outside of (A0000-C0000) enabled.
 *
 ****************************************************************************/

BOOL PRIVENTRY UpdateMMIO(HVDM hvdm)            /*            */
{
  USHORT CRTC36Data;
  USHORT GDC6Data;
  USHORT IMAf7Data;
  USHORT MMIOIndex;
  BYTE bIndex;                                                  /*          */
  USHORT IMAPortEnabled = FALSE;
  register PVDMDATA pvd = pVDMData(hvdm);
  BOOL flMMIO = FALSE;

  /* read CRTC Indexed Register 36: Video System Configuration */
  /* assume unlocked                                           */
  bIndex = vvInput(hvdm,&pleCRTIndx);
  vvOutput( hvdm,
            &pleCRTIndx,
            0x36);
  CRTC36Data = ((vvInput(hvdm,&pleCRTData)) >> 3) & 0x07;
  vvOutput( hvdm,
            &pleCRTIndx,
            bIndex);

  if (!(pvd->flVDMVideo & VDM_IOINIT) ||
      !(pvd->aregCRTData[0x36] & 0x38))                          /*            */
    return(flMMIO);

  /* read GDC Indexed Register 6: Miscellaneous */

  bIndex = vvInput(hvdm,&pleGDCIndx);
  vvOutput( hvdm,
            &pleGDCIndx,
            0x06);
  GDC6Data = ((vvInput(hvdm,&pleGDCData)) >> 2) & 0x03;
  vvOutput( hvdm,
            &pleGDCIndx,
            bIndex);


  /* see if IMA (CRTCB) port is enabled, flag it if it is  */
  /* read IMA Indexed Register F7: Image Port Control      */

  bIndex = vvInput(hvdm,&pleTsengCRTCBIndex);
  vvOutput( hvdm,
            &pleTsengCRTCBIndex,
            0xf7);
  IMAf7Data = vvInput(hvdm,&pleTsengCRTCBData);
  vvOutput( hvdm,
            &pleTsengCRTCBIndex,
            bIndex);

  if (IMAf7Data & 0x01)
  {
      IMAPortEnabled = TRUE;
  }


  flMMIO = TRUE;                /*            */
  // has the index changed ?

  MMIOIndex = (CRTC36Data << 3) | (GDC6Data << 1) | (IMAPortEnabled);
  if ( pvd->VdmSVGA.VdmTSENG.uMMIOIndex != MMIOIndex)
  {   /* yes, so must remap */

      /* unmap old mmio if mapped */

      /* pre-init to invalid stuff */

      pvd->VdmSVGA.VdmTSENG.VGABase  = -1;
      pvd->VdmSVGA.VdmTSENG.VGARange =  0;
      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0;               /*            */
      pvd->VdmSVGA.VdmTSENG.MMURange =  0;
      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 0;
      pvd->VdmSVGA.VdmTSENG.MMRBase  = -1;
      pvd->VdmSVGA.VdmTSENG.MMRRange =  0;
      pvd->VdmSVGA.VdmTSENG.EMRBase  = -1;
      pvd->VdmSVGA.VdmTSENG.EMRRange = -0;

      switch(CRTC36Data)
      {
          case 0:
              flMMIO = FALSE;           /*            */
              switch(GDC6Data)
              {
                  case 0:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xBFFFF - 0xA0000;
                  break;

                  case 1:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xAFFFF - 0xA0000;
                  break;

                  case 2:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xB0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xB7FFF - 0xB0000;
                  break;

                  case 3:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xBFFFF - 0xB8000;
                  break;

              }
          break;

          case 1:
              switch(GDC6Data)
              {
                  case 0:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xBFFFF - 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xBDFFF - 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024;
                  break;

                  case 1:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xAFFFF - 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xBDFFF - 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024;
                  break;

                  case 2:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xB0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xB7FFF - 0xB0000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xADFFF - 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024;
                  break;

                  case 3:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xBFFFF - 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xADFFF - 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024;
                  break;

              }
          break;

          case 5:
              switch(GDC6Data)
              {
                  case 0:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xBFFFF - 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xBDFFF - 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024; /*            */
                  break;

                  case 1:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xAFFFF - 0xA0000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xBDFFF - 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMRBase  = 0xBFF00;
                      pvd->VdmSVGA.VdmTSENG.MMRRange = 0xBFFFF - 0xBFF00;
                      pvd->VdmSVGA.VdmTSENG.EMRBase  = 0xBE000;
                      pvd->VdmSVGA.VdmTSENG.EMRRange = 0xBEFFF - 0xBE000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024;
                  break;

                  case 2:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xB0000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xB7FFF - 0xB0000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xADFFF - 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMRBase  = 0xAFF00;
                      pvd->VdmSVGA.VdmTSENG.MMRRange = 0xAFFFF - 0xAFF00;
                      pvd->VdmSVGA.VdmTSENG.EMRBase  = 0xAE000;
                      pvd->VdmSVGA.VdmTSENG.EMRRange = 0xAEFFF - 0xAE000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024;
                  break;

                  case 3:
                      pvd->VdmSVGA.VdmTSENG.VGABase  = 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.VGARange = 0xBFFFF - 0xB8000;
                      pvd->VdmSVGA.VdmTSENG.MMUBase  = 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMURange = 0xADFFF - 0xA8000;
                      pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 8 * 1024;
                      pvd->VdmSVGA.VdmTSENG.MMRBase  = 0xAFF00;
                      pvd->VdmSVGA.VdmTSENG.MMRRange = 0xAFFFF - 0xAFF00;
                      pvd->VdmSVGA.VdmTSENG.EMRBase  = 0xAE000;
                      pvd->VdmSVGA.VdmTSENG.EMRRange = 0xAEFFF - 0xAE000;
                  break;

              }
          break;

          case 2:
              flMMIO = FALSE;           /*            */
              if (IMAPortEnabled)
              {
                  pvd->VdmSVGA.VdmTSENG.VGABase  = 0x00000;
                  pvd->VdmSVGA.VdmTSENG.VGARange = 0xFFFFF - 0x00000;
              }
              else
              {
                  pvd->VdmSVGA.VdmTSENG.VGABase  = 0x00000;
                  pvd->VdmSVGA.VdmTSENG.VGARange = 0x3FFFFF - 0x00000;
              }
          break;

          case 7:
              if (IMAPortEnabled)
              {
                  pvd->VdmSVGA.VdmTSENG.VGABase  = 0x00000;
                  pvd->VdmSVGA.VdmTSENG.VGARange = 0x7FFFF - 0x00000;
                  pvd->VdmSVGA.VdmTSENG.MMUBase  = 0x80000;
                  pvd->VdmSVGA.VdmTSENG.MMURange = 0xDFFFF - 0x80000;
                  pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 128 * 1024;
                  pvd->VdmSVGA.VdmTSENG.MMRBase  = 0xFFF00;
                  pvd->VdmSVGA.VdmTSENG.MMRRange = 0xFFFFF - 0xFFF00;
                  pvd->VdmSVGA.VdmTSENG.EMRBase  = 0xFE000;
                  pvd->VdmSVGA.VdmTSENG.EMRRange = 0xFEFFF - 0xFE000;
              }
              else
              {
                  pvd->VdmSVGA.VdmTSENG.VGABase  = 0x00000;
                  pvd->VdmSVGA.VdmTSENG.VGARange = 0x1FFFFF - 0x00000;
                  pvd->VdmSVGA.VdmTSENG.MMUBase  = 0x200000;
                  pvd->VdmSVGA.VdmTSENG.MMURange = 0x37FFFF - 0x200000;
                  pvd->VdmSVGA.VdmTSENG.MMUApertureSize = 512 * 1024;
                  pvd->VdmSVGA.VdmTSENG.MMRBase  = 0x3FFF00;
                  pvd->VdmSVGA.VdmTSENG.MMRRange = 0x3FFFFF - 0x3FFF00;
                  pvd->VdmSVGA.VdmTSENG.EMRBase  = 0x380000;
                  pvd->VdmSVGA.VdmTSENG.EMRRange = 0x3BFFFF - 0x380000;
              }
          break;

          /* default: _asm int 3;    should not get here */

      }


      pvd->VdmSVGA.VdmTSENG.uMMIOIndex = MMIOIndex;
  }
  return(flMMIO);            /*            */

}

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdateMemoryMapState
 *
 * DESCRIPTION   = Notifies the accelerator if the MMIO pages have been touched.
 *                 so that accelerator can evaluate what mapping option is required.
 *
 * INPUT         = hvdm, pvdm, map flag
 *
 * OUTPUT        = pflOption mapping option
 *
 * RETURN-NORMAL = Action status TRUE if VDM should be frozen, FALSE otherwize
 * RETURN-ERROR  =
 *  Called by:
 *   vvAcceleratorUpdateMemoryMapState
 *   vvFaultHook
 *   vvEnableBuffer
 ****************************************************************************/
BOOL PRIVENTRY vvTsengW32UpdateMemoryMapState(HVDM hvdm, PVDM pvdmTouched, PULONG pflOption)
{
   register PVDMDATA pvd = pVDMData(hvdm);
   BOOL fFreeze = FALSE;
   if (*pflOption == VDHMT_INVALID)
   {
     pvd->VdmSVGA.VdmTSENG.flW32ACLMapped = FALSE;
   }
   /*
   ** VGA BIOS modes will still enable the MMIO just to check if the accelerator
   ** is busy. When running in the background, map the memory to black hole, as
   ** to prevent them from writing to the accelerator state of the current controller
   ** owner. Black hole memory is not initialized and chances are they will find
   ** particular bits reset. However, should BIOS be waiting for a bit to go to 1,
   ** it will spin and hopefully time-out.
   ** A VDM accessing the page after the BIOS has returned will be frozen.
   */
   else if(pvd->flVDMVideo & VDM_FGND)
   {
     *pflOption = VDHMT_PHYSICAL;
     pvd->VdmSVGA.VdmTSENG.flW32ACLMapped = TRUE;
   }
   else if(((pvd->ulBIOSMode & ~BIOSVINFO_DONTCLEAR)<= BIOSVMODE_CO320X200X256) ||
            (pvd->flVDMVideo & VDM_MODECHANGING))               /*            */
   {
     *pflOption = VDHMT_BLACK_HOLE;
     pvd->VdmSVGA.VdmTSENG.flW32ACLMapped = FALSE;
   }
   else
   {
     *pflOption = VDHMT_BLACK_HOLE;
     pvd->VdmSVGA.VdmTSENG.flW32ACLMapped = FALSE;
     fFreeze = TRUE;            /* freeze the VDM */
   }
   return(fFreeze);
}
/***************************************************************************
 *
 * FUNCTION NAME = vvTsengInterlaced
 *
 * DESCRIPTION   = Get Interlaced Status
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = True = interlacing on
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  return( (pvd->aregCRTData [0x35] & 0x80) >> ZEROBITS( 0x80 ) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvTsengStartAddr
 *
 * DESCRIPTION   = Get Display frame start address
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = offset into VRAM for display frame
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  return(  vvCGAStartAddr( hvdm )
           | ((pvd->aregCRTData [0x33]
               & ((ulSVGAChipType >= TSENG_ET4000W32_CHIP)
                  ? 0x0f
                  : 0x03))
              >> ZEROBITS( 0x0f ) << 16) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvTsengVertDspEnd
 *
 * DESCRIPTION   = Get Vertical Display Length
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Vertical Display Length
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  return( vvVGAVertDspEnd( hvdm )
          | ((pvd->aregCRTData [0x35] & 0x04)
             >> ZEROBITS( 0x04 ) << 10) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvTsengVertLineCmp
 *
 * DESCRIPTION   = Get Vertical Line Compare
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Vertical Line Compare (for split screen)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  return( vvVGAVertLineCmp( hvdm )
          | ((pvd->aregCRTData [0x35] & 0x10)
             >> ZEROBITS( 0x10 ) << 10) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvTsengRestoreIoState()
 *
 * DESCRIPTION   = Do adapter-specific register restores that can't be
 *                 handled in the usual way.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvTsengRestoreIoState(
  HVDM hvdm )
{
  if (pVDMData(hvdm)->VdmSVGA.regOrchidClockSelect)             /*          */
    vvOutput( INVALID_HVDM,                                     /*          */
              &pleOrchidClkSelect,                              /*          */
              0xff );                                           /*          */
  else                                                          /*          */
    vvInput( INVALID_HVDM,                                      /*          */
             &pleOrchidClkSelect );                             /*          */
  /*
  ** Check for Diamond SpeedStar (external clock)
  */
  if (!(pVDMData(hvdm)->flVDMXVideo & VDMX_INTRESTOREFGND) &&   /*            */
       (sOEMData.Manufacturer == DIAMOND_MANUFACTURER))            /*          */
  {
     SETDIAMONDCLK(hvdm, pVDMData(hvdm)->ulBIOSMode,            /*          */
                   pVDMData(hvdm)->vvMode.vvm_nBitCount);       /*          */
  } /* endif */                                                 /*          */

  vvAcceleratorRestoreIOState( hvdm );                          /*          */
}
/***************************************************************************
 *
 * FUNCTION NAME = vvTsengSetBank()
 *
 * DESCRIPTION   = Set Tseng bank register
 *
 *                 Tseng Bank Select is done via port 0x3cd (and 3cb on w32x)
 *                 which contain bits to select read and write banks.
 *
 *                 The read and write banks are set up here.
 *
 *                 On the ET3000 the layout is:
 *                              3CD
 *                         bits 0-2 - 3 bit write bank (64k bank)
 *                         bits 3-5 - 3 bit read bank (64k bank)
 *
 *                 On the ET4000 the layout is:
 *                              3CD
 *                         bits 0-3 - 4 bit write bank (64k bank)
 *                         bits 4-7 - 4 bit read bank (64k bank)
 *
 *                 On the ET4000W32, W32i and W32p
 *
 *                        3CB   3CD
 *                   bits 0-1   0-3 - 6 bit write bank (64k bank)
 *                   bits 4-5   4-7 - 6 bit read bank (64k bank)
 *
 * INPUT         = hvdm
 *                 ulBank
 *                 fSetWriteBank
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvTsengSetBank(
  HVDM hvdm,
  ULONG ulBank,
  BOOL fSetWriteBank )
{
  BYTE bReadBank, bWriteBank, bExtBank;

  fSetWriteBank;                                 /* shut the compiler up    */



  bWriteBank = (BYTE) (ulBank & 0x0f);           /* set up write bank       */
  bReadBank = bWriteBank                         /* set up read bank        */
              << (3 + (ulSVGAChipType >= TSENG_ET4000_CHIP));
  vvOutput( hvdm,
            &pleTsengSegSelect,
            (BYTE)(bReadBank | bWriteBank) );    /* write it out            */

  if (ulSVGAChipType >= TSENG_ET4000W32_CHIP)
  {
      bExtBank = (BYTE) (ulBank & 0x30);
      bExtBank |= (BYTE) (bExtBank >> 4);        /* set read = write */
      vvOutput( hvdm,
                &pleTsengSegSelect2,
                (BYTE)(bExtBank));               /* write it out        */
  }
}

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

ULONG PRIVENTRY vvTsengGetBank(
  HVDM hvdm,
  BOOL fGetWriteBank )
{

  ULONG SegSelect;
  ULONG SegSelect2;


  fGetWriteBank;                                 /* shut the compiler up    */

  SegSelect =  vvInput(hvdm, &pleTsengSegSelect)
               & ((ulSVGAChipType >= TSENG_ET4000_CHIP)
                 ? 0x0f
                 : 0x07);

  if (ulSVGAChipType >= TSENG_ET4000W32_CHIP)
  {
      SegSelect2 = (vvInput(hvdm, &pleTsengSegSelect2)) & 0x03;

      return ( (SegSelect2 << 4) | SegSelect );

  }
  else
  {
      return (SegSelect);
  }

}


/***************************************************************************
 *
 * FUNCTION NAME = vvTsengFixSetMode()     jwk03
 *
 * DESCRIPTION   = Fix up registers based on the mode set
 *
 *                 This subroutine fixes up various register states
 *                 after an int 10 set mode request completes.
 *                 Usually this is to fix BIOS bugs.
 *
 *
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvSVGAFixSetMode
 *
 ****************************************************************************/

VOID PRIVENTRY vvTsengFixSetMode(
  HVDM hvdm,
  ULONG ulMode )
{

  register PVDMDATA pvd = pVDMData(hvdm);
  BYTE bIndex;                                                  /*          */
  USHORT CRTC13Data;                                            /*          */
  USHORT CRTC3fData;                                            /*          */

  /*JWK16
  **       need logical line length to equal physical line length
  **       for PM and         drivers.  Tseng Genoa BIOS setting physical
  **       line length to 256 if 16m colors.  Change this to 240 if found.
  **       Works for PM and svga.exe, but         driver overrides this fix.
  **
  */

  switch(ulMode)
  {
    case 0x2e:   /* 640x480x256+  */
    case 0x112:  /* 640x480x16m VESA */


      bIndex = vvInput(hvdm,&pleCRTIndx);

      vvOutput( hvdm,
                &pleCRTIndx,
                0x13);
      CRTC13Data = vvInput(hvdm,&pleCRTData);

      vvOutput( hvdm,
                &pleCRTIndx,
                0x3f);
      CRTC3fData = vvInput(hvdm,&pleCRTData);

      if ( (CRTC3fData & 0x80)   /* if row offset = 0x100 */
           && (!CRTC13Data))
      {
          vvOutput( hvdm,
                    &pleCRTIndx,
                    0x3f);

          vvOutput( hvdm,
                    &pleCRTData,
                    (BYTE)(CRTC3fData & ~0x80));

          vvOutput( hvdm,
                    &pleCRTIndx,
                    0x13);

          vvOutput( hvdm,
                    &pleCRTData,
                    0xf0);                      /* make row offset = 0x0f0 */

      }

      vvOutput( hvdm,
                &pleCRTIndx,
                bIndex);
      break;

    default:
      break;
  }



  vvOutput( hvdm,                       /*            was INVALID_HVDM */
            &pleTsengCRTCBIndex,
            TSENG_IMA_INDEX_IMAGE_PORT_CONTROL);


  if ( (vvInput( hvdm, &pleTsengCRTCBData) & 0x80) )            /*            was INVALID_HVDM */
  {
    pvd->VdmSVGA.VdmTSENG.flW32HardwareCursorEnabled = TRUE;
  }




  return;
}


/***************************************************************************
 *
 * FUNCTION NAME = vvTsengW32SetActiveMemoryMap()     @senja
 *
 * DESCRIPTION   = Depending on the current state of the accelerator/mode
 *                 set the active memory map.
 *                 Memory map is limited to %a0000-Bffff for now, including MMIO.
 *                 MMIO range has to be mutually exlusive with the phys VRAM range
 *
 * INPUT         = HVDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvUpdateMemoryState
 *      vvUpdateAll
 *      vvFaultHook
 *      vvInt10SetModeReturn
 *      vvSetFgnd
 *      vvSetBgnd
 * NOTE: Mapped flag gets set by the UpdateMemoryMapState, called by the fault hook.
 *       It gets reset here if configuration is invalid.
 *
 ****************************************************************************/
VOID PRIVENTRY vvTsengW32SetActiveMemoryMap (HVDM hvdm)         /*            */
{
  register PVDMDATA pvd = pVDMData(hvdm);
  RequestMutexSem(hmxMMIO);
  if (UpdateMMIO(hvdm))                     /*            */
  {
    pvd->VdmSVGA.npgMMIOActive = 0;             //initialize
    /*
    ** Assign the active and check if it is valid. Keep this as single =
    */
    if(((pvd->VdmSVGA.pvdmMMIOActive = (PVDM) pvd->VdmSVGA.VdmTSENG.MMUBase)
       >= (PVDM) VRAM_START) && (pvd->VdmSVGA.pvdmMMIOActive < (PVDM)(VRAM_START+VRAM_LEN)))
    {
      /*
      ** I can't trust the MMUApertureSize, so setting the # of pages to 8.
      ** pvd->VdmSVGA.npgMMIOActive = (pvd->VdmSVGA.VdmTSENG.MMUApertureSize/PAGESIZE);
      */
      pvd->VdmSVGA.npgMMIOActive = 8;
      if( !(((pvd->pvdmPhysVRAMActive+pvd->npgPhysVRAMActive*PAGESIZE) <=
          pvd->VdmSVGA.pvdmMMIOActive) ||
          (pvd->pvdmPhysVRAMActive >=
          (pvd->VdmSVGA.pvdmMMIOActive+pvd->VdmSVGA.npgMMIOActive*PAGESIZE))))
                           //not mutually excl, clip the VRAM, not the MMIO
      {
        pvd->pvdmPhysVRAMActive = (PVDM) pvd->VdmSVGA.VdmTSENG.VGABase;
        pvd->npgPhysVRAMActive = (ULONG) pvd->VdmSVGA.VdmTSENG.VGARange/PAGESIZE;
      }
      if (pvd->VdmSVGA.VdmTSENG.MMRRange)
      {
        pvd->VdmSVGA.VdmTSENG.pW32MMIO = (PTSENGMMIO) (pPhysVRAM + ((ULONG) pvd->VdmSVGA.VdmTSENG.MMRBase - (ULONG) VRAM_START));
        ReleaseMutexSem(hmxMMIO);
        return;
      }
    }
  }
  /*
  ** No valid MMIO mapping detected, reset all data.
  */
  pvd->VdmSVGA.pvdmMMIOActive = 0;
  pvd->VdmSVGA.npgMMIOActive = 0;
  pvd->VdmSVGA.VdmTSENG.flW32ACLMapped = FALSE;

  ReleaseMutexSem(hmxMMIO);
  return;
}
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32ReadWRegByteL()
 *
 * 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 vvTsengW32ReadWRegByteL(
  ULONG port,
  PCRF pcrf )
{

  return( 0 );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32ReadWRegByteH()
 *
 * 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 vvTsengW32ReadWRegByteH(
  ULONG port,
  PCRF pcrf )
{
  return( 0 );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32ReadWRegWord()
 *
 * 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 vvTsengW32ReadWRegWord(
  ULONG port,
  PCRF pcrf )
{
  return( 0 );
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32WriteWRegByteL()
 *
 * 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 vvTsengW32WriteWRegByteL(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
    return;
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32WriteWRegByteH()
 *
 * 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 vvTsengW32WriteWRegByteH(
  BYTE bData,
  ULONG port,
  PCRF pcrf )
{
    return;
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32WriteWRegWord()
 *
 * 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 vvTsengW32WriteWRegWord(
  WORD wData,
  ULONG port,
  PCRF pcrf )
{
    return;
}

#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA

IOH iohTsengW32wreglo =
{
  vvTsengW32ReadWRegByteL, vvTsengW32WriteWRegByteL,
  vvTsengW32ReadWRegWord,  vvTsengW32WriteWRegWord,
  NULL,
};

IOH iohTsengW32wreghi =
{
  vvTsengW32ReadWRegByteH, vvTsengW32WriteWRegByteH,
  NULL,                    NULL,
  NULL,
};

#pragma  END_SWAP_DATA

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

UINT    PRIVENTRY vvTsengW32PortIndex( PORT port )
{
  return( 0 );
}

/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32AcceleratorBusy()
 *
 * 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 vvTsengW32Busy(  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  TSENGMMIO *pW32;
  BOOL Busy = FALSE;


    if (ulSVGAChipType >= TSENG_ET4000W32_CHIP)
    {
        RequestMutexSem(hmxMMIO);

        if (pvd->VdmSVGA.VdmTSENG.flW32ACLMapped)
        {
            pW32 = pvd->VdmSVGA.VdmTSENG.pW32MMIO;
            Busy = (BOOL)(pW32->ACLAcceleratorStatus & TSENG_ACL_RDST); /* @senja */
        }

        ReleaseMutexSem(hmxMMIO);
    }

    return(Busy);
}
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32Reset()
 *
 * DESCRIPTION   = Force the accelerator to be UNbusy, if possible.
 *
 * INPUT         = hvdm -> VDM
 *               = uiWRegSubSysCtrl = index of A8514_SUBSYSCTRL shadow word
 *
 * OUTPUT        = TRUE if busy, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorWaitOnEngine
 *
 ***********************************************************************/

VOID    PRIVENTRY vvTsengW32Reset(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  ULONG iDelayCount = 0x100;
  TSENGMMIO *pW32;

  /*
  ** 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.
  */


  /* jwkbug for now.... */

  if (ulSVGAChipType >= TSENG_ET4000W32_CHIP)
  {
     RequestMutexSem(hmxMMIO);

     if (pvd->VdmSVGA.VdmTSENG.flW32ACLMapped)
     {
         pW32 = pvd->VdmSVGA.VdmTSENG.pW32MMIO;

         // terminate any operation

         pW32->ACLSuspendTerminate = TSENG_ACL_TO;

         // wait on the status for a limited time only.

         while((pW32->ACLAcceleratorStatus & TSENG_ACL_RDST) && --iDelayCount);
         pW32->ACLSuspendTerminate = 0;
     }

     ReleaseMutexSem(hmxMMIO);
  }
  return;
}
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32InstallIoHooks()
 *
 * 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 vvTsengW32InstallIoHooks( VOID )
{
  return;
}

/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32SetBgndOnlyHooks()
 *
 * 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
 *                 portTrap = 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 vvTsengW32SetBgndOnlyHooks(
  FLAGS fl )
{
  return;
}

/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32SetIoHooks()
 *
 * 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 vvTsengW32SetIoHooks(  FLAGS fl )
{
  return;
}
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32UpdateScrnState()
 *
 * 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 vvTsengW32UpdateScrnState(  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return;

}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32UpdateIoState()
 *
 * DESCRIPTION   = Transfer hardware I/O state to virtual
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvS3UpdateIoState
 *      vvAcceleratorUpdateIoState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvTsengW32UpdateIoState(
  HVDM hvdm )
{
  PVDMDATA pvd = pVDMData( hvdm );
  TSENGMMIO *pW32;
  USHORT i;

  /* jwkbug for now.... */

  // if Accelerator Enabled

  RequestMutexSem(hmxMMIO);

  if (vvTsengW32IsOn(hvdm))                   /*            */
  {
      // get addressability

      pW32 = pvd->VdmSVGA.VdmTSENG.pW32MMIO;


      // call Accelerator Save

      pfnTsengACLSave(pvd, pW32);


      // HWCursor ON?? (save if it is )

      if( (pvd->VdmSVGA.VdmTSENG.aregCRTCBData[TSENG_IMA_INDEX_IMAGE_PORT_CONTROL] & 0x80) )
      {

          pvd->VdmSVGA.VdmTSENG.flW32HardwareCursorEnabled = TRUE;

          for (i=TSENG_HWCURSOR_START; i <= TSENG_HWCURSOR_END; i++)
          {
              pvd->VdmSVGA.VdmTSENG.aregHWCursorData[i] = pvd->VdmSVGA.VdmTSENG.aregCRTCBData[i];
          }
      }
      else   /* cursor not enabled */
      {
          pvd->VdmSVGA.VdmTSENG.flW32HardwareCursorEnabled = FALSE;
      }
  }
  ReleaseMutexSem(hmxMMIO);

  return;
}

/***********************************************************************
 *
 * FUNCTION NAME = vvTsengW32RestoreIoState()
 *
 * DESCRIPTION   = Transfer virtual I/O state to hardware
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvS3RestoreIoState
 *      vvAcceleratorRestoreIoState
 *
 ***********************************************************************/

VOID    PRIVENTRY vvTsengW32RestoreIoState(
  HVDM hvdm )
{
  PVDMDATA pvd = pVDMData( hvdm );
  TSENGMMIO *pW32 = pvd->VdmSVGA.VdmTSENG.pW32MMIO;
  USHORT i;
  BYTE   data;

  if (vvTsengW32IsOn(hvdm))                   /*            */
  {

      RequestMutexSem(hmxMMIO);
      // unlock registers

      _asm {
          mov     dx,3bfh         ;unlock registers
          mov     al,03
          out     dx,al
          mov     dx,3d8h
          mov     al,0a0h
          out     dx,al
      };


// enable memory mapped registers and memory management
      if (pvd->VdmSVGA.VdmTSENG.flW32ACLMapped)               /*            */
      {
          pW32 = pvd->VdmSVGA.VdmTSENG.pW32MMIO;


          // Reset the Accel

          pW32->ACLSuspendTerminate = TSENG_ACL_TO;

          pW32->ACLSuspendTerminate = 0;
          while(pW32->ACLAcceleratorStatus & TSENG_ACL_RDST)
               ;

          // call Accelerator Restore

          pfnTsengACLRestore(pvd, pW32);


          /* we may not need this since IMA is being saved/restored, but is it being turned on? */
          /* OR, maybe we should save/restore all of IMA here? */

          if (pvd->VdmSVGA.VdmTSENG.flW32HardwareCursorEnabled)
          {
              /* Restore HW Cursor  */

              for (i = TSENG_HWCURSOR_START; i <= TSENG_HWCURSOR_END; i++)
              {
                  vvOutput( hvdm,
                            &pleTsengCRTCBIndex,
                            (BYTE)i);
                  vvOutput( hvdm,
                            &pleTsengCRTCBData,
                            pvd->VdmSVGA.VdmTSENG.aregHWCursorData[i]);
              }
              vvOutput( hvdm,
                        &pleTsengCRTCBIndex,
                        TSENG_IMA_INDEX_SPRITE_CONTROL);
              vvOutput( hvdm,
                        &pleTsengCRTCBData,
                        (BYTE)((vvInput(hvdm,&pleTsengCRTCBData)) & ~0x01)); // Select sprite

              vvOutput( hvdm,
                        &pleTsengCRTCBIndex,
                        TSENG_IMA_INDEX_IMAGE_PORT_CONTROL);
              vvOutput( hvdm,
                        &pleTsengCRTCBData,
                        (BYTE)((vvInput(hvdm,&pleTsengCRTCBData)) | 0x80)); // Turn it back on
          }
      }
      ReleaseMutexSem(hmxMMIO);
  }
  return;
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengAcceleratorInit()
 *
 * DESCRIPTION   = Initialize addressing of accelerator registers.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvAcceleratorCreate
 *
 ***********************************************************************/

VOID    PRIVENTRY vvTsengW32Init(
  HVDM hvdm )
{

  return;
}
                                                                /*          */
/***********************************************************************
 *
 * FUNCTION NAME = vvTsengWriteOnly()
 *
 * DESCRIPTION   = Mark accelerator register as write only.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvATIAcceleratorInit
 *
 ***********************************************************************/

VOID    PRIVENTRY vvTsengW32WriteOnly(
  PORT port )
{
  return;
}


#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA

SACCELERATORINFO sTsengW32Info =
{
  sTsengW32TrapRegInfo,
  TSENGW32TRAPREGSIZE,
  &vvTsengW32PortIndex,
  &vvTsengW32Chip,
  &vvTsengW32IsOn,
  &vvTsengAcceleratorCreate,                 /*            */
  &vvTsengAcceleratorDestroy,                /*            */
  &vvTsengW32Busy,
  &vvTsengW32Reset,
  &vvTsengW32InstallIoHooks,
  &vvTsengW32SetIoHooks,
  &vvTsengW32SetBgndOnlyHooks,
  &vvTsengW32UpdateScrnState,
  &vvTsengW32UpdateIoState,
  &vvTsengW32RestoreIoState,
  &vvTsengW32Init,
  &vvTsengW32SetActiveMemoryMap,                                /*            */
  &vvTsengW32UpdateMemoryMapState,                              /*            */
};

SSVGAINFO sTsengAdapterInfo =                                   /*          */
{
  { /* SVGAINFO */                                              /*          */
    { /* SEGAINFO */
      { /* SCGAINFO */
        &vvEGAAdjustedPort,
        &vvTsengStartAddr,
        &vvEGAOddEvenMode,
        &vvEGAHighResMode,
        &vvEGAHorzDspEnd,
        &vvEGAHorzLogEnd,
        &vvTsengVertDspEnd,
        &vvVGABitsPerPixel,
        &vvVGAPrepareSetMode,                                   /*          */
      },
      &vvEGAPackedMode,
      &vvTsengVertLineCmp,
    },
    &vvVGADacSave,                                              /*          */
    &vvVGADacRestore,                                           /*          */
  },                                                            /*          */
  &vvTsengEditTables,
  &vvTsengInterlaced,
  &vvVGAUpdateIoState,
  &vvTsengRestoreIoState,
  &vvTsengSetBank,
  &vvTsengGetBank,
  &vvTsengFixSetMode,                                           /*            */
  &vvVGAFixSetBgnd,
  &vvVGAWriteGDCDataFgnd,
  &vvVGAReadSEQDataBgnd,
  &vvVGAWriteSEQDataBgnd,
  &vvVGADacRS2Clear,                                            /*          */
  &vvVGADacRS2Set,                                              /*          */
  &vvVGADacRS3,                                                 /*          */
  &sTsengW32Info,
  pszTsengAdapterName,
  MAX_TSENG_CHIP,
  ppszTsengChipNames,
  &vvTsengW32UpdateModeData,                                    /*            */
  0,                                                            /*            */
};

#pragma  END_SWAP_DATA
