/*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 = VVSTATE.C
 *
 * DESCRIPTIVE NAME = Virtual Video Hardware State routines
 *
 *
 * VERSION = V2.0
 *
 * DATE      11/10/88
 *
 * DESCRIPTION  This module contains the VVD's hardware state routines.
 *
 *
 * FUNCTIONS    vvUpdateAll()          Update all video state information
 *              vvUpdateSVGAIOState()  Update SVGA I/O state
 *              vvRestoreSVGAIOState() Do adapter-specific register restores that can't be
 *              vvUpdateIOState()      Update virtual I/O state from hardware
 *              vvGetIOState()         Get hardware according to specified register list
 *              vvUpdateMemoryState()  Update current memory state
 *              vvUpdateScreenState()  Update current screen state info
 *              vvUpdateModeData()     Update mode data for shield and/or mouse
 *              vvSetCopyState()       Set hardware for specified access
 *              vvRestoreCopyState()   Restore hardware state
 *              vvSetIOState()         Set hardware according to specified register list
 *              vvRestoreIOState()     Transfer virtual I/O state to hardware
 *
 * 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
#pragma  intrinsic(memcmp)
extern ULONG flVVD;
#pragma  BEGIN_SWAP_DATA
extern LONG npgActive[];                                        /*            */
extern PLE apleAll[];
extern PLE apleNoTrap[];

#ifdef   EGAVGA
extern RLE arleMemory[];
#endif
extern HVDD hvddMouse;
extern MSTATE amstateMap[];
extern PBVDM pvdmPhysVRAM;

#ifdef   EGAVGA
extern PBYTE pbSEQExtShadowIndx;
extern PRLE prleSEQExtShadowData[MAX_SEQREGS];
extern PBYTE pbGDCExtShadowIndx;
extern PRLE prleGDCExtShadowData[MAX_GDCREGS];

   #ifdef   SVGA                                 /*                         */
extern BYTE abCRTMask[];                         /*                         */
extern BYTE abGDCMask[];                         /*                         */
extern BYTE abSEQMask[];                         /*                         */
extern BYTE abATCMask[];                         /*                         */
extern BYTE abATIMask[];                         /*                         */
extern ULONG ulSVGAAdapterType;
extern ULONG ulSVGAChipType;
extern OEMINFO sOEMData;                         /*                         */
   #endif                                        /*                         */
#endif
#pragma  END_SWAP_DATA

#ifdef   EGAVGA
   #pragma  BEGIN_GLOBAL_DATA
extern VVDRQ vvdrqVideo;
   #pragma  END_GLOBAL_DATA
#endif
#pragma  BEGIN_SWAP_CODE

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdateAll()
 *
 * DESCRIPTION   = Update all video state information
 *
 *                 This is called at the following times:
 *                     + video page faults
 *                     + screen-switch requests
 *                     + INT 10h mode-change completions
 *                     + INT 10h font-change completions
 *
 * INPUT         = hvdm -> VDM
 *                 fAll == TRUE to read all untrapped registers, FALSE if not
 * OUTPUT        =
 *                 None
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvUpdateAll(HVDM hvdm,BOOL fAll)
{
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** Can't do complete update unless all I/O initialization is done
  */

  if (!(pvd->flVDMVideo&VDM_IOINIT) && fAll)
    return ;
  RequestMutexSem(pvd->hmxVideoState);

#ifdef   EGAVGA

  /*
  ** Update specified set of virtual registers
  */

  vvUpdateIOState(hvdm,
                  fAll);
#endif

  /*
  ** Get new memory state, if any
  */

  vvUpdateMemoryState(hvdm);

  /*
  ** KLUDGE alert: for video cards that have strange tendencies to go
  ** off and write to memory in graphics modes as part of their INT 10h
  ** *text* mode initialization, we pretend that they are writing to
  ** font memory, so that we don't end up freezing them.  This is only
  ** useful for background VDMs in the middle of certain INT 10h mode
  ** changes;  foreground VDMs can already do whatever they want....
  */

  if ((pvd->flVDMVideo&(VDM_FGND|VDM_MODECHANGING)) == VDM_MODECHANGING)
  {

    if (pvd->ulBIOSMode <= BIOSVMODE_CO80 || pvd->ulBIOSMode ==
       BIOSVMODE_MONO80)

      if (pvd->mstateVideo > MEMORY_FONT)
        pvd->mstateVideo = MEMORY_FONT;
  }

  /*
  ** Convert virtual buffer page states to new state, if any
  */

  if (vvUpdatePageStates(hvdm))
  {

#ifdef   EGAVGA

    if (!fAll)
      vvUpdateIOState(hvdm,
                      TRUE);
#endif
    fAll = TRUE;
  }

#ifdef  VTEXT                                                           //J-TS00V
#ifdef SVGA                                                             //J-TS00V
  if ((ulSVGAAdapterType == S3_ADAPTER) &&                              //J-TS00V
      (pvd->GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE)) {             //J-TS00V
    if (v8514UpdateModeData(hvdm))                                      //J-TS00V
      pvd->flVDMXVideo |= VDMX_ENHANCEDMODE;                            //J-TS00V
    else                                                                //J-TS00V
      pvd->flVDMXVideo &= ~VDMX_ENHANCEDMODE;                           //J-TS00V
  }                                                                     //J-TS00V
#endif                                                                  //J-TS00V
#endif  //VTEXT                                                         //J-TS00V

  /*
  ** If we have to update everything
  */

  if (fAll && !(pvd->flVDMVideo&VDM_DYING))
  {

    /*
    ** Update screen state information
    */

    vvUpdateScreenState(hvdm,TRUE);

    /*
    ** See if this is a mode that requires a shadow buffer
    */

    vvAllocShadowBuffer(hvdm);
    pvd->flVDMVideo |= VDM_STATEINIT;
#ifdef  XVIO                                                            //J-TS00V
    vxSetStatus(hvdm, XVIO_STATUS_STATEINIT, XVIO_SET_FLAG);            //J-TS00V
#endif  //XVIO                                                          //J-TS00V

#ifdef   VDDDEBUGALL
    PRINTDEBUG("New video state: %01x (%s)\n",
               pvd->mstateVideo,
               apszPageStates[pvd->mstateVideo]);
#endif
  }

  /*
  ** Special-case I/O trapping may need enabling/disabling
  */

  if (hvdm == CURRENT_VDM)
    VVSpecialCaseIO(NULL,
                    NULL);
  ReleaseMutexSem(pvd->hmxVideoState);
}

#ifdef   SVGA

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdateSVGAIOState()
 *
 * DESCRIPTION   = Update SVGA I/O state
 *
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvUpdateSVGAIOState(register HVDM hvdm)
{
  INT i;
  BYTE bTmp;


  if (ulSVGAAdapterType == TRIDENT_ADAPTER)
  {
    i = INB(PORT_SEQINDX);      /* restore register definition              */
    pVDMData(hvdm)->stateTridentRegDef = VVGetTridentRegDef();
    OUTB(PORT_SEQINDX,
         INDX_TRIDENT_REGDEF);
    OUTB(PORT_SEQDATA,
         0x01);                                  /* set 'old' definition    */
    OUTB(PORT_SEQINDX,
         INDX_TRIDENT_MODECTRL);
    pVDMData(hvdm)->regTridentModeCtrl2 = INB(PORT_SEQDATA);
    OUTB(PORT_SEQINDX,
         INDX_TRIDENT_REGDEF);
    INB(PORT_SEQDATA);                           /* set new for subsequent
                                                    save                    */
    OUTB(PORT_SEQINDX,
         0x0e);                                  /* get bank select         */
    bTmp = (INB(PORT_SEQDATA)^0x02)|0x80;
    OUTB(PORT_SEQDATA,
         bTmp);                                  /* unprotect registers
                                                    0x0c and 0x0f           */
    OUTB(PORT_SEQINDX,
         i);
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vvRestoreSVGAIOState()
 *
 * 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 vvRestoreSVGAIOState(register HVDM hvdm)
{
  INT i;
  BYTE bTmp;
  ULONG uMode;                                                  /*            */

  switch(ulSVGAAdapterType)
  {
    case TRIDENT_ADAPTER:
    i = INB(PORT_SEQINDX);      /* restore register definition              */
    OUTB(PORT_SEQINDX,
         INDX_TRIDENT_REGDEF);
    OUTB(PORT_SEQDATA,
         0x01);                                  /* set 'old' definition    */
    OUTB(PORT_SEQINDX,
         INDX_TRIDENT_MODECTRL);
    OUTB(PORT_SEQDATA,
         pVDMData(hvdm)->regTridentModeCtrl2);
    OUTB(PORT_SEQINDX,
         INDX_TRIDENT_REGDEF);
    INB(PORT_SEQDATA);                           /* set new for restore     */
    OUTB(PORT_SEQINDX,
         0x0e);                                  /* get bank select         */
    bTmp = (INB(PORT_SEQDATA)^0x02)|0x80;
    OUTB(PORT_SEQDATA,
         bTmp);                                  /* unprotect registers
                                                    0x0c and 0x0f           */
    OUTB(PORT_SEQINDX,
         i);
      break;
    case TSENG_ADAPTER:                                         /*            */
      if (pVDMData(hvdm)->regOrchidClockSelect)                 /*            */
        OUTB(0x3dd, 0xff);                                      /*            */
      else                                                      /*            */
        INB(0x3dd);                                             /*            */

  /*
  ** Check for Diamond SpeedStar (external clock)
  */

      if (sOEMData.Manufacturer == DIAMOND_MANUFACTURER)        /*            */
      {
         SETDIAMONDCLK(hvdm, pVDMData(hvdm)->ulBIOSMode,        /*            */
                       pVDMData(hvdm)->vvMode.vvm_nBitCount);   /*            */
      } /* endif */                                             /*            */
      break;
    case WESTERNDIG_ADAPTER:
      /*
      ** Check for Diamond SpeedStar (external clock)
      */

      if (sOEMData.Manufacturer == DIAMOND_MANUFACTURER)        /*            */
      {                            /*            */
         SETDIAMONDCLK(hvdm, pVDMData(hvdm)->ulBIOSMode,        /*            */
                       pVDMData(hvdm)->vvMode.vvm_nBitCount);   /*            */
      } /* endif */                                             /*            */
      break;
    case S3_ADAPTER:                                            /*            */
      if (sOEMData.Manufacturer == DIAMOND_MANUFACTURER)        /*            */
      {
         SETDIAMONDCLK(hvdm, pVDMData(hvdm)->vvMode.vvm_nCols,
                       pVDMData(hvdm)->vvMode.vvm_nBitCount);   /*            */
      } /* endif */

      v8514RestoreIOState(hvdm);

      if (sOEMData.Manufacturer == NUMBER9_MANUFACTURER)        /*            */
        SETNUMBER9CLK(hvdm, pVDMData(hvdm)->vvMode.vvm_nCols);  /*            */

      break;
  }
}

#endif

#ifdef   VGA
/***************************************************************************
 *
 * FUNCTION NAME = vvSaveATCState()                                       
 *
 * DESCRIPTION   = Update virtual ATC register state from hardware
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        =
 *                 None
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *      Scan apleAll[] to find out how many ATCs in use.
 *      Save ATC index
 *      Save all ATC registers
 *      Re-enable display
 *
 ****************************************************************************/

VOID PRIVENTRY vvSaveATCState(HVDM hvdm)
{
  PPLE pple;
  INT i, nRegs;
  register PORT portStatus;
  register PVDMDATA pvd = pVDMData(hvdm);

  if (pvd->flVDMXVideo & VDMX_NOIOTRAPPING)
  {
    /*
    ** Find out how many ATCs to save
    */
    for (pple = apleAll;
         pple->ple_port && (PORT_ATC0 != (pple->ple_port & PORT_MASK));
         pple++);
    nRegs = pple->ple_nRegs;

    portStatus = (INB(0x3CC) & 1) ? PORT_COLRSTATUS1 : PORT_MONOSTATUS1;
    INB(portStatus);                            /* set flip-flop */
    pvd->regATCIndx = INB(PORT_ATC0);           /* save index    */

    for (i = 0; i < nRegs; i++)
    {
        INB(portStatus);
        OUTB(PORT_ATC0, i);
        pvd->aregATCData[i] = INB(PORT_ATC1);
    }
    INB(portStatus);
    OUTB(PORT_ATC0,
         0x20);
  }
}
#endif

#ifdef   EGAVGA

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdateIOState()
 *
 * DESCRIPTION   = Update virtual I/O state from hardware
 *
 *                 This refreshes some or all untrapped registers with their
 *                 current values for the specified VDM.  Only the VGA (and
 *                 some EGAs) have untrapped ports, and only the VGA supports
 *                 a partial update (since the memory-related ports are
 *                 always trapped on non-VGA hardware).
 *
 *                 If ALL, then all CRT, SEQ, and GDC registers are read and
 *                 stored in their appropriate virtual locations (as is the
 *                 DAC Mask register, which is also untrapped).  If not ALL,
 *                 then only the SEQ and GDC registers listed below are read
 *                 and recorded.
 *
 * INPUT         = hvdm -> VDM
 *
 *                 fAll == TRUE is all untrapped registers to be read,
 *                         FALSE if some
 * OUTPUT        =
 *                 None
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *                 if complete untrapped port update
 *                   read all untrapped regs
 *                 else
 *                   read all memory-related untrapped regs
 *
 ****************************************************************************/

VOID PRIVENTRY vvUpdateIOState(register HVDM hvdm,BOOL fAll)
{
  INT i;
  PORT port;
  register PPLE pple;
  register PRLE prle;

   #ifdef   SVGA
  BYTE *pbData;
  BOOL flUnkReg;
   #endif


  if (pVDMData(hvdm)->flVDMVideo&VDM_FGND)
  {

   #ifdef   SVGA
      vvUnLockSVGARegisters();
    vvUpdateSVGAIOState(hvdm);
   #endif

    /*
    ** If complete update requested (for screen-switch or mode reset)
    */

    if (fAll)
    {
     #ifdef   VGA
      vvSaveATCState(hvdm);                             /*            */
     #endif
      pple = apleNoTrap;

      /*
      ** While not yet end of list
      */

      while (port = vvAdjustedPort(hvdm,
                                   pple->ple_port))
      {

        /*
        ** Non-indexed register
        */

        if (!pple->ple_nRegs)
        {                                        /*                         */

          /*
          ** Reset the 32K HiColor DAC just in case                         
          ** it is left in the commnad mode state                           
          */

          if (port == PORT_VGADACMASK)           /*                         */
            INB(PORT_VGADACWRITE);               /*                         */
          *pVDM(hvdm,
                PBYTE,
                pple->ple_pregData) = INB(port);

          /*
          ** Indexed register
          */

        }

        else
        {                                        /*                         */

          /*
          ** Save current index first, before we change it
          */

          *pVDM(hvdm,
                PBYTE,
                pple->ple_pregIndx) = INB(port);

   #ifdef   SVGA
          flUnkReg = FALSE;

          switch (port)
          {
            case  PORT_COLRCRTINDX :
            case  PORT_MONOCRTINDX :
              pbData = abCRTMask;
              break;
            case  PORT_GDCINDX :
              pbData = abGDCMask;
              break;
            case  PORT_SEQINDX :
              pbData = abSEQMask;
              break;
            case  PORT_ATC0 :
              pbData = abATCMask;
              break;
            case  PORT_ATIVGA_INDX :
              pbData = abATIMask;
              break;
            default  :
              flUnkReg = TRUE;
          }                                      /* endswitch               */

          /*
          ** Read all the indexed registers within this port
          */

          for (i = 0; i < pple->ple_nRegs; i++)

            if ((pbData[i >> 3]&(1 << (i&7))) || flUnkReg)
            {

              /*
              ** Set the index
              */

              OUTB(port,
                   i);

              /*
              ** And read the data
              */

              *pVDM(hvdm,
                    PBYTE,
                    pple->ple_pregData+i) = INB(port+1);
            }

   #else

          /*
          ** Read all the indexed registers within this port
          */

          for (i = 0; i < pple->ple_nRegs; i++)
          {

            /*
            ** Set the index
            */

            OUTB(port,
                 i);

            /*
            ** And read the data
            */

            *pVDM(hvdm,
                  PBYTE,
                  pple->ple_pregData+i) = INB(port+1);
          }
   #endif                                        /* SVGA                    */

   /*
   ** Restore current index, leaving hardware state unchanged
   */

   OUTB(port,
        *pVDM(hvdm,
              PBYTE,
              pple->ple_pregIndx));
        }

        /*
        ** Advance to next entry in list
        */

        pple++;
      }
    }

   #ifdef   VGA

    /*
    ** Else partial update only (for page fault or buffer reset)
    */

    else
      vvGetIOState(hvdm,
                   arleMemory);
   #endif

  }
}

#endif                                           /* EGAVGA                  */

#ifdef   VGA

/***************************************************************************
 *
 * FUNCTION NAME = vvGetIOState()
 *
 * DESCRIPTION   = Get hardware according to specified register list
 *
 *                 This worker routine is used by vvUpdateIOState, and by
 *                 the pointer-draw code, to update the hardware shadow
 *                 information.  NOTE that none of the special
 *                 register-access conditions are applied, since we are
 *                 reading registers rather than writing them.
 *
 * INPUT         = hvdm  -> VDM
 *                 prle  -> register list
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvGetIOState(HVDM hvdm,register PRLE prle)
{
  register BYTE b;
  PORT port,portLast = 0;

  AssertTRUE(pVDMData(hvdm)->flVDMVideo&VDM_FGND);

  /*
  ** While not yet end of list
  */

  while (port = vvAdjustedPort(hvdm,
                               prle->rle_port))
  {

#ifdef SVGA
    if (prle->rle_port & PORTF_NOTRAP)           //          
    {
      /*
      ** Advance to next entry in list
      */

      prle++;
      continue;
    }
    /*
    ** Non-indexed register
    */

    if (prle->rle_indx == 0)
#else
    /*
    ** Non-indexed register
    */

    if (prle->rle_indx < 0)
#endif
      *pVDM(hvdm,
            PBYTE,
            prle->rle_pregData) = INB(port);

    /*
    ** Indexed register
    */

    else
    {

      /*
      ** Save current index if new port
      */

      if (port != portLast)
      {

        if (portLast)
          OUTB(portLast,
               b);
        portLast = port;
        b = *pVDM(hvdm,
                  PBYTE,
                  prle->rle_pregIndx) = INB(port);
      }

      /*
      ** Set new index, and read its data
      */

      OUTB(port,
           prle->rle_indx);
      *pVDM(hvdm,
            PBYTE,
            prle->rle_pregData) = INB(port+1);
    }

    /*
    ** Advance to next entry in list
    */

    prle++;
  }

  if (portLast)
    OUTB(portLast,
         b);
}

#endif                                           /* VGA                     */

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdateMemoryState()
 *
 * DESCRIPTION   = Update current memory state
 *
 *                 This function returns a MEMORY_* constant indicating the
 *                 state of the VDM's video memory.
 *
 *                 Determination of video memory state is based on
 *                 registers/bits that define current addressibility.  In
 *                 the following, assume that all registers not specified
 *                 are not important to the state.  Also assume that all
 *                 bits not specified must be clear, unless otherwise noted;
 *                 "None" means that none must be set (all must be clear):
 *
 *
 *                     Register    Requirements for MEMORY_TEXT
 *
 *
 *                     SEQMEMMODE  None (ALPHA and EXTENDED are NOPs)
 *                     GDCESR      None
 *                     GDCROTATE   None
 *                     GDCREADMAP  None
 *                     GDCMODE     GDCMODE_ODDEVENDIFF
 *                     GDCMISC     GDCMISC_ODDTOEVEN (memory location is NOP)
 *                     GDCBITMASK  GDCMASK_ALL
 *
 *                 or:
 *
 *                     Register    Requirements for MEMORY_FONT
 *
 *                     SEQMAPMASK  SEQMAP_PLANE2
 *                     SEQMEMMODE  SEQMEM_ODDEVENSAME (ALPHA and EXTENDED are NOPs)
 *                     GDCESR      None
 *                     GDCROTATE   None
 *                     GDCREADMAP  Ignore(1)
 *                     GDCMODE     None
 *                     GDCMISC     None (memory location is NOP)
 *                     GDCBITMASK  GDCMASK_ALL
 *
 *                     (1) If a VDM tries to read font memory, this register
 *                         should be set to PLANE2.  However, this is
 *                         unenforceable.  There is no way to make memory
 *                         write-only, and disallowing random values in the
 *                         GDCREADMAP register could impact applications
 *                         that never intended to read the memory anyway.
 *
 *
 *                 Any other state is assumed to be MEMORY_GRFX.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = Returns one of the MEMORY_* constants
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *                 update active memory range
 *                 determine memory state by munging all
 *                   pertinent bits into a single dword and
 *                   checking its value
 *
 ****************************************************************************/

#define  SEQMAPMASK_SHIFT 0                     /* 4 bits                   */
#define  SEQMEMMODE_SHIFT (4-2)                 /* 1 bit                    */
#define  GDCREADMAP_SHIFT 5                     /* 3 bits                   */
#define  GDCMODE_SHIFT 8                        /* 7 bits                   */
#define  GDCMISC_SHIFT 15                       /* 2 bits, total of 17 bits */

VOID PRIVENTRY vvUpdateMemoryState(HVDM hvdm)
{
  register ULONG ul;
  register PVDMDATA pvd = pVDMData(hvdm);

  static PBVDM pvdmActive[] =
  {
    (PBVDM)EGAVGAMEM_START,(PBVDM)EGAVGAMEM_START,(PBVDM)MONOMEM_START,(PBVDM)
                CGAMEM_START,
  };

  /*
  ** Reset hardware copy state (unknown)
  */

  pvd->mstateCopy = MEMORY_NONE;

  /*
  ** Flag any change in the active memory range
  */

#ifdef   MONO
  ul = GDCMISC_32K_B0000;
#endif

#ifdef   CGA
  ul = GDCMISC_32K_B8000;
#endif

#ifdef   EGAVGA
  ul = pvd->aregGDCData[REG_GDCMISC]&GDCMISC_ADDRMASK;
#endif

  /*
  **           difference, if any, between the 64k and 128k
  **           addressing modes; so for now, I am mapping the
  **           larger onto the smaller.  We know of no apps that
  **           use the 128k addressing mode anyway....
  */

/* if (ul == GDCMISC_128K_A0000)                                            */
/*     ul = GDCMISC_64K_A0000;                                              */

  ul >>= ZEROBITS(GDCMISC_ADDRMASK);

  if (pvd->pvdmPhysVRAMActive != pvdmActive[ul] || pvd->npgPhysVRAMActive !=
     npgActive[ul])
  {

    /*
    ** Update the active memory range
    */

    pvd->pvdmPhysVRAMActive = pvdmActive[ul];
    pvd->npgPhysVRAMActive = npgActive[ul];
    pvd->offPhysVRAMActive = pvd->pvdmPhysVRAMActive-pvdmPhysVRAM;

    /*
    ** FLAG:  -- Generally, the active memory range will not be
    **           changed without a corresponding change in mode, but
    **           just to be safe, a complete remap should be forced
    **           here....
    */

  }

#ifdef  VTEXT                                                           //J-TS00V
  if ((pvd->GaleData.flVtext & VDMV_VTEXT_INSTALLED) &&                 //J-TS00V
      (pvd->GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE)) {             //J-TS00V
    pvd->mstateVideo = MEMORY_TEXT;                                     //J-TS00V
    return;                                                             //J-TS00V
  }                                                                     //J-TS00V
#endif  //VTEXT                                                         //J-TS00V

#ifdef   MONO
  pvd->mstateVideo = MEMORY_TEXT;
  return ;
#endif                                           /* MONO                    */

#ifdef   CGA

  if (pvd->regMode&CGAMODE_320X200)
    pvd->mstateVideo = MEMORY_CGAX;

  else

    if (pvd->regMode&CGAMODE_640X200)

      pvd->mstateVideo = MEMORY_GRFX2;

    else
      pvd->mstateVideo = MEMORY_TEXT;
  return ;
#endif                                           /* CGA                     */

#ifdef   EGAVGA

  /*
  ** If SET/RESET is enabled, or ROTATE options are enabled,
  ** or BITMASK has bits disabled, we are obviously not TEXT/FONT
  */

  if(!(pvd->aregGDCData[REG_GDCMODE] & GDCMODE_256COLOR) &&     /*            */
      (pvd->aregGDCData[REG_GDCESR] & GDCESR_ALL ||
       pvd->aregGDCData[REG_GDCROTATE] & GDCROTATE_ALL ||
       pvd->aregGDCData[REG_GDCBITMASK] != GDCBITMASK_ALL))
  {
    pvd->mstateVideo = MEMORY_GRFX;
    return ;
  }

  /*
  ** Extract and pack pertinent bits from various registers
  */

  ul = 0;
  ul |= (pvd->aregSEQData[REG_SEQMAPMASK]&SEQMAP_ALL) << SEQMAPMASK_SHIFT;
  ul |= (pvd->aregSEQData[REG_SEQMEMMODE]&SEQMEM_ODDEVENSAME) <<
     SEQMEMMODE_SHIFT;
  ul |= (pvd->aregGDCData[REG_GDCREADMAP]&GDCREADMAP_ALL) << GDCREADMAP_SHIFT;
  ul |= (pvd->aregGDCData[REG_GDCMODE]&GDCMODE_ALL) << GDCMODE_SHIFT;
  ul |= ((pvd->aregGDCData[REG_GDCMISC]&GDCMISC_ODDTOEVEN)|/*               */
     (pvd->aregGDCData[REG_GDCMISC]&             /*                         */
     pvd->aregATCData[REG_ATCMODECTRL]&          /*                         */
     GDCMISC_NOCHARGEN)) << GDCMISC_SHIFT;       /*                         */

/*  ul |= (pvd->aregGDCData[REG_GDCMISC] & (GDCMISC_NOCHARGEN|GDCMISC_ODDTOEVEN))*/
/*          << GDCMISC_SHIFT;                                               */
  /*
  ** Check requirements for being in TEXT-mode
  */

  if (ul == ((SEQMAP_PLANE0|SEQMAP_PLANE1) << SEQMAPMASK_SHIFT|
     (GDCMODE_ODDEVENDIFF) << GDCMODE_SHIFT|(GDCMISC_ODDTOEVEN) <<
     GDCMISC_SHIFT))
  {
    pvd->mstateVideo = MEMORY_TEXT;
    return ;
  }

  /*
  ** Check requirements for being in CGAX-mode
  */

  if (ul == ((SEQMAP_PLANE0|SEQMAP_PLANE1) << SEQMAPMASK_SHIFT|
     (GDCMODE_ODDEVENDIFF|GDCMODE_ODDEVENBITS) << GDCMODE_SHIFT|
     (GDCMISC_ODDTOEVEN|GDCMISC_NOCHARGEN) << GDCMISC_SHIFT))
  {
    pvd->mstateVideo = MEMORY_CGAX;
    return ;
  }

  /*
  ** Nullify setting of GDCREADMAP register (should be ignored)
  */

  ul &= ~(GDCREADMAP_ALL << GDCREADMAP_SHIFT);

  /*
  ** Check requirements for being in FONT-mode
  */

  if (ul == ((SEQMAP_PLANE2) << SEQMAPMASK_SHIFT|(SEQMEM_ODDEVENSAME) <<
     SEQMEMMODE_SHIFT))
  {
    pvd->mstateVideo = MEMORY_FONT;
    return ;
  }

  /*
  ** Check requirements for being in GRFX2-mode
  */

  if (ul == ((SEQMAP_PLANE0) << SEQMAPMASK_SHIFT|(SEQMEM_ODDEVENSAME) <<
     SEQMEMMODE_SHIFT|(GDCMISC_NOCHARGEN) << GDCMISC_SHIFT) &&
     (pvd->aregATCData[REG_ATCPLANEENABLE]&SEQMAP_ALL) == SEQMAP_PLANE0)
  {
    pvd->mstateVideo = MEMORY_GRFX2;
    return ;
  }

  /*
  ** Check requirements for being in GRFX256-mode
  */

/*  if (pvd->aregSEQData[REG_SEQMEMMODE] & SEQMEM_CHAIN4                    */
/*      && pvd->aregGDCData[REG_GDCMODE] & GDCMODE_256COLOR) {              */

  if (pvd->aregGDCData[REG_GDCMODE]&GDCMODE_256COLOR)
  {
    pvd->mstateVideo = MEMORY_GRFX256;
    return ;
  }

   #ifdef   SVGA

  /*
  ** Check requirements for being in GRFX256-mode on ATI/Video7 chipsets (sigh!)
  ** This req'd because the GDC Mode reg doesn't reflect 256-colour modes
  */

  if (vvSVGALinearMode(hvdm))
  {
    pvd->mstateVideo = MEMORY_GRFX256;
    return ;
  }
   #endif

  /*
  ** Check for A000 access while in text mode
  */

  if (!(ul&(GDCMISC_NOCHARGEN << GDCMISC_SHIFT)))
  {                                              /*                         */
    pvd->mstateVideo = MEMORY_FONT;              /*                         */
    return ;                                     /*                         */
  }                                              /*                         */

  /*
  ** We're still here, so it must be some GRFX-mode
  */

  pvd->mstateVideo = MEMORY_GRFX;
#endif                                           /* EGAVGA                  */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdateScreenState()
 *
 * DESCRIPTION   = Update current screen state info
 *
 *                 This function updates the state information for visible
 *                 VDM VRAM.  This should be called only after the memory
 *                 state has been updated.
 *
 *                 Determination of visibility size is based on the number
 *                 of scan lines visible (divided by the number of scan
 *                 lines per character row if in text mode).
 *
 *                     Register        Use
 *
 *                     CRTVERTDSPEND   This (+1) is total scan lines showing
 *
 *                     CRTOVERFLOW     Bit 1 contains bit 8 for CRTVERTDSPEND
 *
 *                     CRTMAXSCAN      This (+1) is total scan lines
 *                                     per character row
 *
 *                     CRTSTARTADDRHI  This is active-relative start
 *                                     address (high byte)
 *
 *                     CRTSTARTADDRLO  This is active-relative start
 *                                     address (low byte)
 *
 *
 * INPUT         = hvdm -> VDM
 *                 fUpdate == TRUE to update mode information, FALSE to not
 *
 * OUTPUT        = Visibility state info updated
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvUpdateScreenState(HVDM hvdm,BOOL fUpdate)
{
  ULONG offset,u;
  register PVDMDATA pvd = pVDMData(hvdm);
  register ULONG nBytes,nRows;
  ULONG iRowSplit;

#ifdef  GALE                                                            //J-TS00V
  if ((pvd->flVDMGale) &&                                               //J-TS00V
      ((pvd->ulBIOSMode == 0x03) || (pvd->ulBIOSMode == 0x73))) {       //J-TS00V
    pvd->nPlanes                 = 1;                                   //J-TS00V
    pvd->nBitsPixel              = 0;                                   //J-TS00V
    pvd->nPixelsByte             = 0;                                   //J-TS00V
    pvd->nbVRAMRow               = 80 * 2;                              //J-TS00V
    pvd->offOddBank              = 0;                                   //J-TS00V
    pvd->pvdmPhysVRAMVisible     = pvd->pvdmPhysVRAMActive;             //J-TS00V
    pvd->offPhysVRAMVisible      = 0;                                   //J-TS00V
    pvd->nbPhysVRAMVisible       = 80 * 25 * 2;                         //J-TS00V
    pvd->vvMode.vvm_ulCellWidth  = 8;                                   //J-TS00V
    pvd->vvMode.vvm_ulCellHeight = 19;                                  //J-TS00V
    pvd->vvMode.vvm_nRows        = 25;                                  //J-TS00V
    pvd->vvMode.vvm_nCols        = 80;                                  //J-TS00V
    if (fUpdate)                                                        //J-TS00V
      vvUpdateModeData(hvdm);                                           //J-TS00V
    return;                                                             //J-TS00V
  }                                                                     //J-TS00V
#endif  //GALE                                                          //J-TS00V
#ifdef  VTEXT                                                           //J-TS00V
  if ((pvd->GaleData.flVtext & VDMV_VTEXT_INSTALLED) &&                 //J-TS00V
      (pvd->GaleData.flVtext & VDMV_SUPPORTED_TEXT_MODE)) {             //J-TS00V
    pvd->vvMode.vvm_ulCellWidth  = 8;                                   //J-TS00V
    pvd->vvMode.vvm_ulCellHeight = pVDMBase(hvdm)->rb_nVCharHeight;     //J-TS00V
    pvd->vvMode.vvm_nRows        = vvGetRowCountVtext(hvdm);            //J-TS00V
    pvd->vvMode.vvm_nCols        = pVDMBase(hvdm)->rb_nVCols;           //J-TS00V
    pvd->nPlanes                 = 1;                                   //J-TS00V
    pvd->nBitsPixel              = 0;                                   //J-TS00V
    pvd->nPixelsByte             = 0;                                   //J-TS00V
    pvd->nbVRAMRow               = pvd->vvMode.vvm_nCols * 2;           //J-TS00V
    pvd->offOddBank              = 0;                                   //J-TS00V
    pvd->pvdmPhysVRAMVisible     = pvd->pvdmPhysVRAMActive;             //J-TS00V
    pvd->offPhysVRAMVisible      = 0;                                   //J-TS00V
    pvd->nbPhysVRAMVisible       = pvd->nbVRAMRow *                     //J-TS00V
                                   pvd->vvMode.vvm_nRows;               //J-TS00V
    if (fUpdate)                                                        //J-TS00V
        vvUpdateModeData(hvdm);                                         //J-TS00V
    return;                                                             //J-TS00V
  }                                                                     //J-TS00V
#endif  //VTEXT                                                         //J-TS00V

  offset = pvd->aregCRTData[REG_CRTSTARTADDRLO]|pvd->aregCRTData
     [REG_CRTSTARTADDRHI] << 8;

/*  @V.2SEN03 reorganizing the function. All SVGA processing extracted */
#ifndef SVGA
#ifdef   MONOCGA

  /*
  ** Get # of bytes across
  */

  nBytes = pvd->aregCRTData[REG_CRTHORZDSPEND];

  /*
  ** Get # of scan lines visible
  */

  nRows = pvd->aregCRTData[REG_CRTVERTTOTAL]*((pvd->aregCRTData[REG_CRTMAXSCAN
     ]&0x1F)+1);

#else                                            /* EGAVGA                  */

  /*
  ** Get # of bytes across
  */

  nBytes = pvd->aregCRTData[REG_CRTHORZDSPEND]+1;

  /*
  ** Get # scan lines visible (all 9 bits)
  */

  nRows = pvd->aregCRTData[REG_CRTVERTDSPEND]+1;
  nRows += ((pvd->aregCRTData[REG_CRTOVERFLOW]&CRTOVFL_VERTDSPEND) >> ZEROBITS
     (CRTOVFL_VERTDSPEND) << 8);


  /*
  ** Get split-screen row #, if any (all 9 (or 10) bits)
  */

   #define  CRTMAXSCAN_LINECMP 0x40              /* FLAG:  - Move to VVD.H  */
  iRowSplit = pvd->aregCRTData[REG_CRTLINECMP]+1;
  iRowSplit += ((pvd->aregCRTData[REG_CRTOVERFLOW]&CRTOVFL_LINECMP) >>
     ZEROBITS(CRTOVFL_LINECMP) << 8);

   #ifdef   VGA
  iRowSplit += ((pvd->aregCRTData[REG_CRTMAXSCAN]&CRTMAXSCAN_LINECMP) >>
     ZEROBITS(CRTMAXSCAN_LINECMP) << 9);
   #endif

  /*
  ** FLAG: 18-Sep-90
  ** This is NOT "support" for split-screen apps;  it simply prevents us
  ** from blowing up on them, by limiting our attention to just the top
  ** portion of the screen.  There is much more work required throughout the
  ** driver to properly reset compare/copy operations at the "spliting"
  ** scanline, and because such apps are almost never encountered, the work
  ** is low priority.
  */

  if (nRows > iRowSplit)
    nRows = iRowSplit;

  if (pvd->aregCRTData[REG_CRTMAXSCAN]&CRTMAXSCAN_200CONV)
    nRows /= 2;
#endif

  /*
  ** If no true screen state exists yet, pick reasonable defaults
  */

  if (nBytes <= 1)
    nBytes = 80;

  if (nRows <= 1)
    nRows = 200;
  pvd->nPlanes = 1;
  pvd->nBitsPixel = 0;

  /*
  ** If text mode, account for attribute bytes and such now
  */

  if (pvd->mstateVideo <= MEMORY_FONT)
  {
    pvd->vvMode.vvm_ulCellWidth = 8;
    pvd->vvMode.vvm_ulCellHeight = (pvd->aregCRTData[REG_CRTMAXSCAN]&0x1F)+1;

    /*
    ** If no true screen state exists yet, pick reasonable defaults
    */

    if (pvd->vvMode.vvm_ulCellHeight <= 1)
      pvd->vvMode.vvm_ulCellHeight = 8;

    if (!(nRows /= pvd->vvMode.vvm_ulCellHeight))/*                         */
      nRows++;                                   /*                         */
    pvd->vvMode.vvm_nRows = nRows;
    pvd->vvMode.vvm_nCols = nBytes;
    nBytes *= 2;
    offset *= 2;
  }

  /*
  ** Must be some graphics mode, so set up defaults for that assumption
  */

  else
  {
    pvd->vvMode.vvm_nRows = nRows;
    pvd->vvMode.vvm_nCols = nBytes *8;
    pvd->vvMode.vvm_ulCellWidth = 1;
    pvd->vvMode.vvm_ulCellHeight = 1;

#ifdef   EGAVGA
    u = pvd->aregATCData[REG_ATCPLANEENABLE]&SEQMAP_ALL;

    if (u == 0x03)
      pvd->nPlanes = 2;

    else

      if (u == 0x07)

        pvd->nPlanes = 3;

      else

        if (u != 0x01)

          pvd->nPlanes = 4;
#endif
    pvd->nBitsPixel = 1;
  }

#ifndef  MONO

  /*
  ** If CGA modes 4/5, make minor adjustments
  */

   #ifdef   EGAVGA

  if (pvd->aregGDCData[REG_GDCMODE]&GDCMODE_ODDEVENBITS)
  {

   #else                                         /* CGA                     */

    if (pvd->regMode&CGAMODE_320X200)
    {
   #endif
      nBytes *= 2;
      pvd->nPlanes = 1;
      pvd->nBitsPixel = 2;
    }
#endif

#ifdef   CGA

    if (pvd->regMode&CGAMODE_640X200)
    {
      pvd->vvMode.vvm_nCols *= 2;
    }
#endif

#ifdef   EGAVGA

    /*
    ** If VGA modes 13h (256-color), make minor adjustments
    */

      if (pvd->aregGDCData[REG_GDCMODE]&GDCMODE_256COLOR)
      {
        nRows /= 2;
        nBytes *= 4;
        pvd->nPlanes = 1;
        pvd->nBitsPixel = 8;

        pvd->vvMode.vvm_nCols /= 2;
        pvd->vvMode.vvm_nRows /= 2;
      }

#endif

      if (!pvd->nBitsPixel)
        pvd->nPixelsByte = 0;

      else
        pvd->nPixelsByte = 8/pvd->nBitsPixel;

      /*
      ** Now get total size by multiplying bytes across by # rows
      */

      pvd->nbVRAMRow = nBytes;
      nBytes *= nRows;

#ifndef  MONO

      /*
      ** If operating in compatibility mode, make odd/even size adjustment
      */

      pvd->offOddBank = 0;

   #ifdef   EGAVGA

      if (!(pvd->aregCRTData[REG_CRTMODECTRL]&CRTMCTRL_COMPAT))
      {

   #else                                         /* MONOCGA                 */

        if (pvd->regMode&CGAMODE_320X200 || pvd->regMode&CGAMODE_640X200)
        {
   #endif
          offset *= 2;
          pvd->offOddBank = 8*1024;
          nBytes = 8*1024+nBytes/2;
        }
#endif
                /*            start of SVGA processing. VGA code included */
#else

  /*
  ** Get # of bytes across
  */

  nBytes = pvd->aregCRTData[REG_CRTHORZDSPEND]+1;

  /*
  ** S3 has 9 bits. Extra bit in CRT 5D, bit 1, so shift by 8
  */
  if (ulSVGAAdapterType == S3_ADAPTER)
    nBytes += (pvd->aregCRTData[0x5D] & 0x02) << 8;             /*            */
  /*
  ** Get # scan lines visible (all 9 bits)
  */

  nRows = pvd->aregCRTData[REG_CRTVERTDSPEND]+1;
  nRows += ((pvd->aregCRTData[REG_CRTOVERFLOW]&CRTOVFL_VERTDSPEND) >> ZEROBITS
     (CRTOVFL_VERTDSPEND) << 8);

  nRows += ((pvd->aregCRTData[REG_CRTOVERFLOW]&CRTOVFL_VERTDSPEND2) >>
     ZEROBITS(CRTOVFL_VERTDSPEND2) << 9);
  /*
  ** S3 has 10 bits. Extra bit in CRT 5E, bit 1, so shift by 9.
  */
  if (ulSVGAAdapterType == S3_ADAPTER)                          /*            */
    nRows += (pvd->aregCRTData[0x5E] & 0x02) << 9;

  /*
  ** Get split-screen row #, if any (all 9 (or 10) bits)
  */

   #define  CRTMAXSCAN_LINECMP 0x40              /* FLAG:  - Move to VVD.H  */
  iRowSplit = pvd->aregCRTData[REG_CRTLINECMP]+1;
  iRowSplit += ((pvd->aregCRTData[REG_CRTOVERFLOW]&CRTOVFL_LINECMP) >>
     ZEROBITS(CRTOVFL_LINECMP) << 8);

  iRowSplit += ((pvd->aregCRTData[REG_CRTMAXSCAN]&CRTMAXSCAN_LINECMP) >>
     ZEROBITS(CRTMAXSCAN_LINECMP) << 9);

  /*
  ** FLAG: 18-Sep-90
  ** This is NOT "support" for split-screen apps;  it simply prevents us
  ** from blowing up on them, by limiting our attention to just the top
  ** portion of the screen.  There is much more work required throughout the
  ** driver to properly reset compare/copy operations at the "spliting"
  ** scanline, and because such apps are almost never encountered, the work
  ** is low priority.
  */

  if (nRows > iRowSplit)
    nRows = iRowSplit;

  if (pvd->aregCRTData[REG_CRTMAXSCAN]&CRTMAXSCAN_200CONV)
    nRows /= 2;

  /*
  ** If no true screen state exists yet, pick reasonable defaults
  */

  if (nBytes <= 1)
    nBytes = 80;

  if (nRows <= 1)
    nRows = 200;
  pvd->nPlanes = 1;
  pvd->nBitsPixel = 0;

  /*
  ** If text mode, account for attribute bytes and such now
  */

  if (pvd->mstateVideo <= MEMORY_FONT)
  {
    pvd->vvMode.vvm_ulCellWidth = 8;
    pvd->vvMode.vvm_ulCellHeight = (pvd->aregCRTData[REG_CRTMAXSCAN]&0x1F)+1;

    /*
    ** If no true screen state exists yet, pick reasonable defaults
    */

    if (pvd->vvMode.vvm_ulCellHeight <= 1)
      pvd->vvMode.vvm_ulCellHeight = 8;

    if (!(nRows /= pvd->vvMode.vvm_ulCellHeight))/*                         */
      nRows++;                                   /*                         */
    pvd->vvMode.vvm_nRows = nRows;
    pvd->vvMode.vvm_nCols = nBytes;
    nBytes *= 2;
    offset *= 2;
  }

  /*
  ** Must be some graphics mode, so set up defaults for that assumption
  */

  else
  {
    pvd->vvMode.vvm_nRows = nRows;
    pvd->vvMode.vvm_nCols = nBytes *8;
    pvd->vvMode.vvm_ulCellWidth = 1;
    pvd->vvMode.vvm_ulCellHeight = 1;

    u = pvd->aregATCData[REG_ATCPLANEENABLE]&SEQMAP_ALL;

    if (u == 0x03)
      pvd->nPlanes = 2;
    else
      if (u == 0x07)
        pvd->nPlanes = 3;
      else
        if (u != 0x01)
          pvd->nPlanes = 4;

    pvd->nBitsPixel = 1;
  }


  if (pvd->aregGDCData[REG_GDCMODE]&GDCMODE_ODDEVENBITS)
  {

      nBytes *= 2;
      pvd->nPlanes = 1;
      pvd->nBitsPixel = 2;
   }

  if ((pvd->aregGDCData[REG_GDCMODE]&GDCMODE_256COLOR) || (vvSVGALinearMode
  (hvdm)))
  {

    /*
    ** If VGA modes 13h (256-color), make minor adjustments
    */

    if (((pvd->ulBIOSMode&~BIOSVINFO_DONTCLEAR)
        == BIOSVMODE_CO320X200X256)   &&                        /*            */
        !(ulSVGAAdapterType == IBM_ADAPTER &&                   /*            */
          (pvd->aregXGAData[AXGA_OPERATING_MODE] & 0x10)))      /*            */
    {
      nRows /= 2;
      nBytes *= 4;
      pvd->vvMode.vvm_nCols /= 2;
      if (pvd->aregSEQData[REG_SEQMEMMODE] & SEQMEM_CHAIN4)     /*            */
         pvd->vvMode.vvm_nRows /= 2;
    }

    if (ulSVGAAdapterType == TRIDENT_ADAPTER)
    {                                          /* ALERT:640x480x256             */

      if ((nBytes > 128) &&
         ((pvd->ulBIOSMode&~BIOSVINFO_DONTCLEAR) != BIOSVMODE_CO320X200X256))/*            */
      {                                        /* detects 160 bytes             */
        nBytes /= 2;
        pvd->vvMode.vvm_nCols /= 2;            /* =================             */
      }

      if (nBytes == 128)
      {
        nRows = 768;
        pvd->vvMode.vvm_nRows = nRows;
      }
    }

    pvd->nPlanes = 1;
    pvd->nBitsPixel = 8;

  }

  /*
  ** Hi-color support. 16 bpp and 32bpp                                   
  */
  if(ulSVGAAdapterType == S3_ADAPTER)
  {
    if ((pvd->ulBIOSMode == 0x112) ||                        /*            */
        (pvd->ulBIOSMode == 0x70))                           /*            */
      pvd->nBitsPixel = 24;                                  /*            */
    else
      if((pvd->aregCRTData[0x43] & 0x80) || (pvd->aregCRTData[0x50] & 0x10))
        pvd->nBitsPixel = 16;
//  if (pvd->aregCRTData[0x50] & 0x30)
//    pvd->nBitsPixel = 24;            /*          */
  }
  if (!pvd->nBitsPixel)
    pvd->nPixelsByte = 0;

  else
    pvd->nPixelsByte = 8/pvd->nBitsPixel;

  /*
  ** Now get total size by multiplying bytes across by # rows
  */

  pvd->nbVRAMRow = nBytes;
  nBytes *= nRows;

  /*
  ** If operating in compatibility mode, make odd/even size adjustment
  */

  pvd->offOddBank = 0;

  if (!(pvd->aregCRTData[REG_CRTMODECTRL]&CRTMCTRL_COMPAT))
  {

      offset *= 2;
      pvd->offOddBank = 8*1024;
      nBytes = 8*1024+nBytes/2;
  }
  /*
  ** ulLogicalBytes represents the screen width in bytes, not in pixels.
  */
  if (pvd->flVDMVideo & VDM_MODECHANGING)                       /*            */
      pvd->ulLogicalBytes = 0;                                  /*            */
  else
  {
      pvd->ulLogicalBytes = pvd->aregCRTData[REG_CRTOFFSET] << 1;       /*            */
      if (!(pvd->aregCRTData[REG_CRTMODECTRL] & 0x40))          /*            */
          pvd->ulLogicalBytes <<= 1;                            /*                        */

      if (pvd->mstateVideo == MEMORY_GRFX256)
          pvd->ulLogicalBytes <<= 1;

      switch (ulSVGAAdapterType)
      {
        case ATI_ADAPTER:
          if ((pvd->mstateVideo == MEMORY_GRFX256) &&
              (pvd->vvMode.vvm_nCols > 320))                    /*            */
            pvd->ulLogicalBytes <<= 2;
          break;
        case TRIDENT_ADAPTER:                                   /*            */
          if ((pvd->mstateVideo == MEMORY_GRFX) &&              /* This required with certain */
              (pvd->vvMode.vvm_nCols == 1024))                  /* DRAM configurations where  */
              pvd->ulLogicalBytes >>= 1;                        /* CRT offset reflects double.*/
          else if ((pvd->mstateVideo == MEMORY_GRFX256) &&      /*            */
                   (pvd->vvMode.vvm_nCols < 1024) &&            /*            */
                  ((pvd->ulBIOSMode&~BIOSVINFO_DONTCLEAR) ==
                    BIOSVMODE_CO320X200X256))                   /*            */
              pvd->ulLogicalBytes <<= 1;                        /*            */
          break;
        case VIDEO7_ADAPTER:                                    /*            */
        case WESTERNDIG_ADAPTER:
        case CIRRUS_ADAPTER:                                    /*            */
          if (pvd->mstateVideo == MEMORY_GRFX256)
            pvd->ulLogicalBytes <<= 1;
          break;
        case S3_ADAPTER:                                        /*            */
          /*
          ** If accelerated, it is in a doubleword mode, but not
          ** necessarely set for 1024 logical line length. This
          ** depends on the memory configuration as well.
          */
          if (v8514Accelerated(hvdm))
            pvd->ulLogicalBytes = v8514ReturnLineLen(hvdm);
          break;
        default:
          break;
      }         /*            end */
  }             /*            end */
  /*
  ** Fixups for SVGA 800x600 or 1024x768 modes.
  */
  switch(ulSVGAAdapterType)
  {
        case CIRRUS_ADAPTER:            /*                        */
                                        /* troblesome identification of 16/256 1024x768 mode */
          if ((pvd->mstateVideo == MEMORY_GRFX256) &&
              (pvd->vvMode.vvm_nCols==512))
          {
              pvd->vvMode.vvm_nCols *= 2;
              if (pvd->vvMode.vvm_nRows != 768)
              {
                 pvd->vvMode.vvm_nRows = 768;
              }
              break;
          }
        case WESTERNDIG_ADAPTER:        /*                         */
        case TRIDENT_ADAPTER:           /*                         */
        case VIDEO7_ADAPTER:            /*                         */
          if (pvd->vvMode.vvm_nRows == 384)
          {                       
              pvd->vvMode.vvm_nRows *= 2;
          }
          break;
        case ATI_ADAPTER:               /*                         */
          if (pvd->vvMode.vvm_nRows==300)
          {                       
              pvd->vvMode.vvm_nRows *= 2;
          }
          else                          /*                         */
          if (pvd->vvMode.vvm_nCols==512) {       
              pvd->vvMode.vvm_nCols *= 2;
          }
          break;
        case S3_ADAPTER:                /*            */
          if (pvd->vvMode.vvm_nRows == 768)                /*            */
              pvd->vvMode.vvm_nCols = 1024;                /*            */
          else if (pvd->vvMode.vvm_nRows == 1024)          /*            */
              pvd->vvMode.vvm_nCols = 1280;                /*            */
          else if (pvd->vvMode.vvm_nRows == 480)           /*            */
              pvd->vvMode.vvm_nCols = 640;                 /*            */
          else if (pvd->vvMode.vvm_nRows == 600)           /*            */
              pvd->vvMode.vvm_nCols = 800;                 /*            */

          /***
           *** if the above tests didn't make it,                       
           *** look at the cols now
           ***/
          if (pvd->vvMode.vvm_nCols == 1024)
              pvd->vvMode.vvm_nRows = 768;
          else if (pvd->vvMode.vvm_nCols == 1280)
              pvd->vvMode.vvm_nRows = 1024;
          break;
        default:
          break;
  }
#endif          /*            end of SVGA specifics */
  /*
  ** Sanity check: visible range must be restricted to active memory
  */

  if (offset+nBytes > pvd->npgPhysVRAMActive *PAGESIZE)
    nBytes = pvd->npgPhysVRAMActive *PAGESIZE-offset;

  /*
  ** Now to answer the all-important question:  what's visible?
  */

  pvd->pvdmPhysVRAMVisible = pvd->pvdmPhysVRAMActive+offset;
  pvd->offPhysVRAMVisible = offset;
  pvd->nbPhysVRAMVisible = nBytes;

  /*
  ** Now that we have all the heights and widths worked out,
  ** update the rest of the mode data structure and post mode event
  */

  if (fUpdate)
    vvUpdateModeData(hvdm);
}

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdateModeData()
 *
 * DESCRIPTION   = Update mode data for shield and/or mouse
 *
 *                  Note this is not only called by UpdateScreenState, but
 *                  also anywhere where new mode information needs to be
 *                  posted to Shield.  Currently, the only such places are
 *                  where we freeze/thaw a VDM (since that indicator is part
 *                  of the mode event data).
 *
 * INPUT         = hvdm  -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvUpdateModeData(HVDM hvdm)
{
  VMSSIZE vmssNew;
  register PVDMDATA pvd = pVDMData(hvdm);

#ifdef SVGA                                             /*            */
  USHORT fl8514Mode = FALSE;
  if (ulSVGAAdapterType == S3_ADAPTER)
     fl8514Mode = v8514UpdateModeData(hvdm);         /* if in VGA mode */
  if (!fl8514Mode)
  {
#endif
  pvd->vvMode.vvm_ulAdapter = ADAPTER_TYPE;
  pvd->vvMode.vvm_ulFormat = FORMAT_CGA;
  pvd->vvMode.vvm_ulDDFormat = 0;
  pvd->vvMode.vvm_flMode = 0;
  pvd->vvMode.vvm_nPlanes = 0;
  pvd->vvMode.vvm_nBitCount = 0;
  pvd->vvMode.vvm_fSuspended = SUSPEND_NONE;

#ifdef SVGA                                     /*            */
  }
#endif
#ifdef  GALE                                                            //J-TS00V
  pvd->vvMode.vvm_FormatID      = 0;                                    //J-TS00V
  pvd->vvMode.vvm_GridColor     = 0xfefefe;                             //J-TS00V
  pvd->vvMode.vvm_nRows2        = 0;                                    //J-TS00V
  pvd->vvMode.vvm_nCols2        = 0;                                    //J-TS00V
  pvd->vvMode.vvm_ulCellWidth2  = 0;                                    //J-TS00V
  pvd->vvMode.vvm_ulCellHeight2 = 0;                                    //J-TS00V
  pvd->vvMode.vvm_ulFormat2     = 0;                                    //J-TS00V
#endif  //GALE                                                          //J-TS00V
  if ((pvd->flVDMVideo & VDM_FROZEN) ||         /*            */
      (pvd->flVDMX2Video & VDMX2_8514BLOCKED))  /*            */
  {
    pvd->vvMode.vvm_fSuspended = SUSPEND_OUT_OF_MEMORY;

    if (!(pvd->flVDMVideo&VDM_GRFXALLOWED)

#ifdef   EGAVGA
        || !(flVVD&VVD_PMBGND) && vvdrqVideo.vvd_nbReserved ==
           ALL_RESERVED
#endif
         )
    {
       pvd->vvMode.vvm_fSuspended = SUSPEND_UNSUPPORTED_MODE;
    }
  }

#ifdef  GALE                                                            //J-TS00V
  if ((!pvd->flVDMGale ||                                               //J-TS00V
       ((pvd->ulBIOSMode != 0x03) &&                                    //J-TS00V
        (pvd->ulBIOSMode != 0x73))) &&                                  //J-TS00V
      (pvd->mstateVideo >= MEMORY_CGAX))                                //J-TS00V
#else   //GALE                                                          //J-TS00V
  if (pvd->mstateVideo >= MEMORY_CGAX)
#endif  //GALE                                                          //J-TS00V
  {
    pvd->vvMode.vvm_ulFormat = FORMAT_BITMAP;
    pvd->vvMode.vvm_flMode |= MODE_SUP_YSCALE2;

    if (pvd->vvMode.vvm_nCols == 320)
      pvd->vvMode.vvm_flMode |= MODE_SUP_XSCALE2;
    pvd->vvMode.vvm_nPlanes = 1;
    pvd->vvMode.vvm_nBitCount = pvd->nBitsPixel *pvd->nPlanes;

    if (pvd->mstateVideo == MEMORY_GRFX && pvd->vvMode.vvm_nBitCount ==
       4)
    {

      /* FLAG:  - Until the DDBitmap code supports scaling,           */
      /*          it must be disabled for all cases....               */

      pvd->vvMode.vvm_ulDDFormat = DDFORMAT_4PLANE;
      pvd->vvMode.vvm_flMode &= ~(MODE_SUP_XSCALE2|MODE_SUP_YSCALE2);
    }

    /*
    ** Convert actual bitcount into a supported value
    */

    if (pvd->vvMode.vvm_nBitCount > 1)

      if (pvd->vvMode.vvm_nBitCount <= 4)
        pvd->vvMode.vvm_nBitCount = 4;

      else

        if (pvd->vvMode.vvm_nBitCount <= 8)

          pvd->vvMode.vvm_nBitCount = 8;
  }
#ifdef  GALE                                                            //J-TS00V
  else if (pvd->flVDMGale &&                                            //J-TS00V
           ((pvd->ulBIOSMode == 0x03) ||                                //J-TS00V
            (pvd->ulBIOSMode == 0x73))) {                               //J-TS00V
    pvd->vvMode.vvm_FormatID  = FORMATID_CommonFMT;                     //J-TS00V
    pvd->vvMode.vvm_ulFormat  = FORMAT_4BYTE;                           //J-TS00V
    pvd->vvMode.vvm_GridColor = 0x7e7e7e;                               //J-TS00V
    pvd->vvMode.vvm_AttrFlag  = 0;                                      //J-TS00V
  }                                                                     //J-TS00V
#endif  //GALE                                                          //J-TS00V
#ifdef  VTEXT                                                           //J-TS00V
  if (pvd->GaleData.flVtext & VDMV_VTEXT_INSTALLED) {                   //J-TS00V
    if ((pvd->ulBIOSMode == 0x03) ||                                    //J-TS00V
        (pvd->ulBIOSMode == 0x70)) {                                    //J-TS00V
      pvd->vvMode.vvm_ulFormat   = FORMAT_CGA;                          //J-TS00V
      pvd->vvMode.vvm_ulDDFormat = 0;                                   //J-TS00V
      pvd->vvMode.vvm_flMode     = 0;                                   //J-TS00V
      pvd->vvMode.vvm_nPlanes    = 0;                                   //J-TS00V
      pvd->vvMode.vvm_nBitCount  = 0;                                   //J-TS00V
      pvd->vvMode.vvm_FormatID   = 0;                                   //J-TS00V
    } else if ((pvd->ulBIOSMode == 0x71) ||                             //J-TS00V
               (pvd->ulBIOSMode == 0x73)) {                             //J-TS00V
      pvd->vvMode.vvm_ulFormat   = FORMAT_4BYTE;                        //J-TS00V
      pvd->vvMode.vvm_ulDDFormat = 0;                                   //J-TS00V
      pvd->vvMode.vvm_flMode     = 0;                                   //J-TS00V
      pvd->vvMode.vvm_nPlanes    = 0;                                   //J-TS00V
      pvd->vvMode.vvm_nBitCount  = 0;                                   //J-TS00V
      pvd->vvMode.vvm_FormatID   = FORMATID_CommonFMT;                  //J-TS00V
      pvd->vvMode.vvm_GridColor  = 0x7e7e7e;                            //J-TS00V
    }                                                                   //J-TS00V
  }                                                                     //J-TS00V
#endif  //VTEXT                                                         //J-TS00V

  /*
  ** Refresh mode data for Shield
  */

  vvAddEvent(hvdm,
             VVDEVENT_MODE,
             &pvd->vvMode,
             0);
#ifdef  XVIO                                                            //J-TS00V
  if (pvd->flVDMGale) {                                                 //J-TS00V
    vvGetVIOModeData(hvdm, &pvd->XVIOData.vxMode);                      //J-TS00V
    pvd->XVIOData.vxMode.vxm_FormatID = 0x70;                           //J-TS00V
    pvd->XVIOData.vxMode.vxm_attrib   = 3;                              //J-TS00V
    vxAddEvent(hvdm, VXEVENT_MODE, &pvd->XVIOData.vxMode, 0);           //J-TS00V
  }                                                                     //J-TS00V
#endif  //XVIO                                                          //J-TS00V

  /*
  ** Refresh cursor data since visibility can change based on mode
  */

  vvUpdateCursorData(hvdm);
#ifdef  XVIO                                                            //J-TS00V
  if (pvd->flVDMGale)                                                   //J-TS00V
    vxUpdateCursorData(hvdm);                                           //J-TS00V
#endif  //XVIO                                                          //J-TS00V

  /*
  ** Don't tell the mouse driver *anything* unless we're active
  */

  if (pvd->flVDMVideo&VDM_IOINIT && pvd->flVDMXVideo&VDMX_ACTIVE)
  {
    vmssNew.vmss_nb = sizeof(VMSSIZE);
    vmssNew.vmss_lMode = pVDMBase(hvdm)->rb_bVMode&~BIOSVINFO_DONTCLEAR;
    vmssNew.vmss_ulWidth = pvd->vvMode.vvm_nCols
       *pvd->vvMode.vvm_ulCellWidth;
    vmssNew.vmss_ulHeight = pvd->vvMode.vvm_nRows
       *pvd->vvMode.vvm_ulCellHeight;
    vmssNew.vmss_ulCellWidth = pvd->vvMode.vvm_ulCellWidth;
    vmssNew.vmss_ulCellHeight = pvd->vvMode.vvm_ulCellHeight;

    /*
    ** If this is a complete state reinitialization (eg, mode changed
    ** or if the first 6 (mode-related) fields of vmssNew differ...
    */

#ifdef  VTEXT                                                       //J-TS0922
    if (!(pvd->GaleData.flVtext & VDMV_REDRAW_SCREEN))              //J-TS0922
#endif  //VTEXT                                                     //J-TS0922
    if (!(pvd->flVDMVideo&VDM_STATEINIT) || memcmp
       (&pvd->PtrData.vmssVideo,
        SSToDS(&vmssNew),
        6*sizeof(ULONG)))
    {

      /*
      ** Make sure the mouse is in a stable state
      */

      pvd->PtrData.fPtrFrozenVideo++;

      /*
      ** Update the mouse mode data
      */

      pvd->PtrData.vmssVideo = *(PVMSSIZE)SSToDS(&vmssNew);

      /*
      ** Initialize the pointer-specific portions of the data
      */

      vvPtrReset(hvdm);

      /*
      ** And finally, notify the virtual mouse driver
      */

      if (hvddMouse)
        VDHRequestVDD(hvddMouse,
                      hvdm,
                      VMDEVREQ_SETSIZE,
                      &pvd->PtrData.vmssVideo,
                      NULL);
      pvd->PtrData.fPtrFrozenVideo--;
    }
  }

       #ifdef SVGA                                              /*            */

  if (fl8514Mode ||                                         /*            */
     ((pvd->mstateVideo == MEMORY_GRFX256) &&               /*            */
      (((pvd->ulBIOSMode&~BIOSVINFO_DONTCLEAR) != BIOSVMODE_CO320X200X256) ||
        (ulSVGAAdapterType == IBM_ADAPTER &&                /*            */
        (pvd->aregXGAData[AXGA_OPERATING_MODE] & 0x10)))))  /*            */
    pvd->flVDMXVideo |= VDMX_ENHANCEDMODE;
  else
    pvd->flVDMXVideo &= ~VDMX_ENHANCEDMODE;

       #endif                                                   /*            */
}

#ifdef   EGAVGA

/***************************************************************************
 *
 * FUNCTION NAME = vvSetCopyState()
 *
 * DESCRIPTION   = Set hardware for specified access
 *
 *                 Depending on the given state (MEMORY_TEXT, MEMORY_FONT, or
 *                 MEMORY_GRFX), the video hardware is programmed for copying
 *                 memory in that state.  This involves reprogramming all the
 *                 registers listed in arleMemory.
 *
 * INPUT         = hvdm   -> VDM
 *                 ms     == either MEMORY_TEXT, MEMORY_FONT or MEMORY_GRFX
 *                 iPlane == desired plane
 *
 * OUTPUT        = Newly selected memory state
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvSetCopyState(HVDM hvdm,
                              register MSTATE ms,
                              INT iPlane)
{
  BYTE b;
  register PRLE prle;
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** If we're not already in desired state
  */

  if (ms != MEMORY_NONE && ms != pvd->mstateCopy)
  {
    vvSetIOState(hvdm,
                 arleMemory,
                 amstateMap[ms]);
    pvd->mstateCopy = ms;
  }

  /*
  ** When ALL_PLANES is specified, set "latch" read/write mode
  */

  if (iPlane == ALL_PLANES)
  {
    vvShadowOutput(hvdm,
                   PORT_SEQINDX,
                   PORT_SEQDATA,
                   REG_SEQMAPMASK,
                   SEQMAP_ALL,
                   pbSEQExtShadowIndx,
                   prleSEQExtShadowData[REG_SEQMAPMASK]->
                      rle_pbExtShadowData,
                   0);
    vvShadowOutput(hvdm,
                   PORT_GDCINDX,
                   PORT_GDCDATA,
                   REG_GDCMODE,
                   GDCMODE_WRITE1|GDCMODE_READ0|!GDCMODE_ODDEVENDIFF,
                   pbGDCExtShadowIndx,
                   prleGDCExtShadowData[REG_GDCMODE]->
                      rle_pbExtShadowData,
                   0);

    if (pvd->mstateCopy == MEMORY_NONE)
      pvd->mstateCopy = MEMORY_LATCH;
  }

  /*
  ** For graphics modes, set up specified plane for read/write
  */

  else

    if (ms == MEMORY_GRFX)
    {

      /*
      ** Set up plane for writing
      */

      vvShadowOutput(hvdm,
                     PORT_SEQINDX,
                     PORT_SEQDATA,
                     REG_SEQMAPMASK,
                     1 << iPlane,
                     pbSEQExtShadowIndx,
                     prleSEQExtShadowData[REG_SEQMAPMASK]->
                        rle_pbExtShadowData,
                     0);

      /*
      ** Set up same plane for reading
      */

      vvShadowOutput(hvdm,
                     PORT_GDCINDX,
                     PORT_GDCDATA,
                     REG_GDCREADMAP,
                     iPlane,
                     pbGDCExtShadowIndx,
                     prleGDCExtShadowData[REG_GDCREADMAP]->
                        rle_pbExtShadowData,
                     0);
    }

    else

      if (ms == MEMORY_GRFX256)
      {
        vvShadowOutput(hvdm,
                       PORT_SEQINDX,
                       PORT_SEQDATA,
                       REG_SEQMAPMASK,
                       SEQMAP_ALL,
                       pbSEQExtShadowIndx,
                       prleSEQExtShadowData[REG_SEQMAPMASK]->
                          rle_pbExtShadowData,
                       0);
        vvShadowOutput(hvdm,
                       PORT_GDCINDX,
                       PORT_GDCDATA,
                       REG_GDCMODE,
                       GDCMODE_256COLOR,
                       pbGDCExtShadowIndx,
                       prleGDCExtShadowData[REG_GDCMODE]->
                          rle_pbExtShadowData,
                       0);
      }
}
#endif                                           /* EGAVGA                  */

#ifdef   EGAVGA

/***************************************************************************
 *
 * FUNCTION NAME = vvRestoreCopyState()
 *
 * DESCRIPTION   = Restore hardware state
 *
 *                 This basically undoes the work done by vvSetCopyState.
 *                 For every register in the arleMemory list, the virtual
 *                 values for those registers is written back to the
 *                 hardware.  This is done for all the registers listed in
 *                 arleMemory.
 *
 * INPUT         = hvdm -> VDM
 *                 iMode == Restore mode (SETIO_SHADOWED or SETIO_LIMIT_SHADOWED)
 * OUTPUT        =
 *                 None
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvRestoreCopyState(register HVDM hvdm,
                                  INT iMode)
{
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** If we were in "latch" mode, then just fix the two registers
  */

  if (pvd->mstateCopy == MEMORY_LATCH)
  {
    vvShadowOutput(hvdm,
                   PORT_SEQINDX,
                   PORT_SEQDATA,
                   REG_SEQMAPMASK,
                   pvd->aregSEQData[REG_SEQMAPMASK],
                   pbSEQExtShadowIndx,
                   prleSEQExtShadowData[REG_SEQMAPMASK]->
                      rle_pbExtShadowData,
                   0);
    vvShadowOutput(hvdm,
                   PORT_GDCINDX,
                   PORT_GDCDATA,
                   REG_GDCMODE,
                   pvd->aregGDCData[REG_GDCMODE],
                   pbGDCExtShadowIndx,
                   prleGDCExtShadowData[REG_GDCMODE]->
                      rle_pbExtShadowData,
                   0);
  }

  else

    if (pvd->mstateCopy != MEMORY_NONE)

      vvSetIOState(hvdm,
                   arleMemory,
                   iMode);
  pvd->mstateCopy = MEMORY_NONE;
}
#endif                                           /* EGAVGA                  */

#ifdef   EGAVGA

/***************************************************************************
 *
 * FUNCTION NAME = vvSetIOState()
 *
 * DESCRIPTION   = Set hardware according to specified register list
 *
 *                 This worker routine is used by vvSetCopyState and
 *                 vvRestoreCopyState, and by the pointer-draw code, to
 *                 reprogram the hardware according to the given list.
 *
 * INPUT         = hvdm  -> VDM
 *                 prle  -> register list
 *                 iMode == index of mode-byte to output
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvSetIOState(HVDM hvdm,
                            register PRLE prle,
                            INT iMode)
{
  BYTE b,d;
  FLAGS flCond;
  PORT port,portLast = 0;
  register PBYTE pbShadowLast;
  register PVDMDATA pvd = pVDMData(hvdm);

  AssertTRUE(pvd->flVDMVideo&(VDM_FGND|VDM_PHYSPAGE));

  /*
  ** While more register-list entries
  */

  while (port = vvAdjustedPort(hvdm,
                               prle->rle_port))
  {

#ifdef  GALE                                                            //J-TS00V
    if (pvd->flVDMGale && pvd->GaleData.GaleInternalAccess &&           //J-TS00V
        ((prle->rle_indx == REG_SEQMEMMODE) ||                          //J-TS00V
         (prle->rle_indx == REG_GDCMISC))) {                            //J-TS00V
       ++prle;                                                          //J-TS00V
       continue;                                                        //J-TS00V
    }                                                                   //J-TS00V
#endif  //GALE                                                          //J-TS00V

    /*
    ** Reprogram port only if we have to
    */

    if (iMode == SETIO_LIMIT_SHADOWED || prle->rle_port&PORTF_REQUIRED)
    {

      /*
      ** Determine data to output (assume SETIO_SHADOWED)
      */

      flCond = prle->rle_fbCond;
      d = (BYTE)(*pVDM(hvdm,
                       PBYTE,
                       prle->rle_pregData));

      if (iMode > SETIO_SHADOWED)
      {

        /*
        ** Clear bits in VDM's setting we need to change
        */

        d &= ~prle->rle_fbMask;

        /*
        ** and OR in the appropriate bits from our mode table
        */

        d |= (prle->rle_bMode[iMode]&prle->rle_fbMask);
      }

      if (pvd->flVDMVideo&VDM_PHYSPAGE)
      {
        flCond = 0;     /* FLAG: -- Probably shouldn't do this! */
        d = vvAdjustShadowOutput(prle,
                                 d);
      }

      /*
      ** Non-indexed register
      */

      if (prle->rle_indx < 0)
        vvShadowOutput(hvdm,
                       0,
                       port,
                       -1,
                       d,
                       NULL,
                       prle->rle_pbExtShadowData,
                       flCond);

      /*
      ** Indexed register
      */

      else
      {

        /*
        ** Save current index if new port
        */

        if (port != portLast && iMode <= SETIO_SHADOWED)
        {

          if (portLast)
            vvShadowOutput(hvdm,
                           0,
                           portLast,
                           -1,
                           b,
                           NULL,
                           pbShadowLast,
                           0);
          portLast = port;
          b = *pVDM(hvdm,
                    PBYTE,
                    prle->rle_pregIndx);
          pbShadowLast = prle->rle_pbExtShadowIndx;
        }
        vvShadowOutput(hvdm,
                       port,
                       port+1,
                       prle->rle_indx,
                       d,
                       prle->rle_pbExtShadowIndx,
                       prle->rle_pbExtShadowData,
                       flCond);
      }
    }

    /*
    ** Advance to next register-list entry
    */

    ++prle;
  }

  if (portLast)
    vvShadowOutput(hvdm,
                   0,
                   portLast,
                   -1,
                   b,
                   NULL,
                   pbShadowLast,
                   0);
}
#endif                                           /* EGAVGA                  */

/***************************************************************************
 *
 * FUNCTION NAME = vvRestoreIOState()
 *
 * DESCRIPTION   = Transfer virtual I/O state to hardware
 *
 *                 ATI requires that registers be set in a particular order.
 *                 After loading the ATI extended registers, the Misc Output
 *                 must be set before any reset condition clears out CLK
 *                 sensitive bits in the extended register range.  By virtue
 *                 of the apleAll[] ordering, the ATI regs are restored
 *                 last, and we can then do the Misc.  Output register load
 *                 at the end of this routine.  The desired ordering as per
 *                 their documentation is:
 *
 *                     Start synchronous reset (Sequencer reg 0)
 *                     ATI Extended regs
 *                     Miscellaneous Output reg
 *                     Sequencers (1-4)
 *                     End Sequencer reset
 *                     Load CRT, ATC, GDC and then DACs
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvRestoreIOState(register HVDM hvdm)
{
  FLAGS flCond;
  register PPLE pple;
  register INT i,j;
  PORT portIndx,portData;

#ifdef   SVGA
  BYTE *pbData;
  BOOL flUnkReg;
#endif


  if (pVDMData(hvdm)->mstateVideo == MEMORY_NONE)
  {
#ifdef  SVGA
    pVDMData(hvdm)->flVDMXVideo &= ~VDMX_RESTOREBTDAC;    /*            */
#endif
    return ;
  }

#ifdef   SVGA
  vvUnLockSVGARegisters();
  vvRestoreSVGAIOState(hvdm);
#endif
  pple = apleAll;

  while (portData = vvAdjustedPort(hvdm,
                                   pple->ple_port))
  {

    if (pple->ple_nRegs == 0)
    {

      /*
      ** Non-indexed port
      */

      flCond = 0;

      if (pple->ple_flResetSeq)
        flCond |= REGCOND_RESETSEQ;

      if (pple->ple_flWaitVert)
        flCond |= REGCOND_WAITVERT;

      if (pple->ple_flWaitHorz)
        flCond |= REGCOND_WAITHORZ;

#ifdef   EGAVGA

      /*
      ** Use vvShadowOutput since it handles register conditions
      */

      vvShadowOutput(hvdm,
                     0,
                     portData,
                     -1,
                     *pVDM(hvdm,
                           PBYTE,
                           pple->ple_pregData),
                     NULL,
                     NULL,
                     flCond);

#else

      /*
      ** On MONO/CGA cards, there are no conditions to worry about
      */

      OUTB(portData,
           *pVDM(hvdm,
                 PBYTE,
                 pple->ple_pregData));
#endif
    }

    else
    {

      /*
      ** Indexed port
      */

      portIndx = portData;

      if (pple->ple_port&PORTF_INDEXDATA)
      {

        /*
        ** Ports used for both index and data
        ** need their flip-flop reset, like so
        */

        INB(PORT_COLRSTATUS1);
        INB(PORT_MONOSTATUS1);
      }

      else
      {

        /*
        ** Normal case is for data port to be (index + 1)
        */

        ++portData;
      }

      if (!(pple->ple_port&PORTF_AUTOINC))
      {

#ifdef   SVGA
        flUnkReg = FALSE;

        switch (portIndx)
        {
          case  PORT_COLRCRTINDX :
          case  PORT_MONOCRTINDX :
            pbData = abCRTMask;
            break;
          case  PORT_GDCINDX :
            pbData = abGDCMask;
            break;
          case  PORT_SEQINDX :
            pbData = abSEQMask;
            break;
          case  PORT_ATC0 :
            pbData = abATCMask;
            break;
          case  PORT_ATIVGA_INDX :
            pbData = abATIMask;
            break;
          default  :
            flUnkReg = TRUE;
        }                                  /* endswitch               */
#endif

        /*
        ** Normal case (non-auto-increment)
        */

#ifdef   VGA

        if (pple->ple_port&PORTF_CRTCTRL)
        {

          /*
          ** On VGA, insure CRT controller not write-protected
          */

          OUTW(portIndx,
               REG_CRTVERTENDRTRC|(pVDM(hvdm,
                                        PBYTE,
                                        pple->ple_pregData)
                                           [REG_CRTVERTENDRTRC]&0x7F) <<
                                           8);
        }
#endif



#ifdef   MONO                                                        /* 73042 */
        /*                                                              73042
        ** Only restore cursor related register values                  73042
        */                                                           /* 73042 */

        for (i = 0xe,                                                /* 73042 */
             j = 1; i <= 0xf;++i,                                    /* 73042 */
             j <<= 1)                                                /* 73042 */
#else                                                                /* 73042 */
        for (i = 0,
             j = 1; i < pple->ple_nRegs; ++i,
             j <<= 1)
#endif                                                               /* 73042 */
        {
          flCond = 0;

          if (pple->ple_flResetSeq&j)
            flCond |= REGCOND_RESETSEQ;

          if (pple->ple_flWaitVert&j)
            flCond |= REGCOND_WAITVERT;

          if (pple->ple_flWaitHorz&j)
            flCond |= REGCOND_WAITHORZ;

#ifdef   EGAVGA

   #ifdef   SVGA                                 /*                         */

          /* do some specifics, see 'Port-list entry' in vvdp.h*/
          /* Sensitive registers are indices: 0xA4, 0xF8, 0xFD.*/

          if ((ulSVGAAdapterType == VIDEO7_ADAPTER) && (portIndx ==
          PORT_SEQINDX))
          {

            if ((i == 0xA4) || (i == 0xF8) || (i == 0xFD))
              flCond |= REGCOND_RESETSEQ;
          }
          flCond |= REGCOND_USEINDEX;

          if ((pbData[i >> 3]&(1 << (i&7))) || flUnkReg)
   #endif                                        /* SVGA                    */

          /*
          ** Use vvShadowOutput since it handles reg. conditions
          */

          vvShadowOutput(hvdm,
                     portIndx,
                     portData,
                     i,
                     pVDM(hvdm,
                          PBYTE,
                          pple->ple_pregData)[i],
                     NULL,
                     NULL,
                     flCond);

#else

          /*
          ** On MONO/CGA cards, there are no conditions to worry about
          */

          OUTW(portIndx,
               pVDM(hvdm,
                    PBYTE,
                    pple->ple_pregData)[i] << 8|i);
#endif
        }
      }

      else
      {

        /*
        ** The AUTOINC case (only used for DAC registers)
        */

        OUTB(portIndx,
             0);
        OUTSB(portData,
              pVDM(hvdm,
                   PBYTE,
                   pple->ple_pregData),
              pple->ple_nRegs,
              FALSE);
      }

      /*
      ** In ANY indexed case, don't forget to leave
      ** the index register at the last programmed value
      */

      if (portIndx != PORT_ATC0)           /* ATC0 set by
                                              vvEnableDisplay()       */
        OUTB(portIndx,
             *pVDM(hvdm,
                   PBYTE,
                   pple->ple_pregIndx));
    }

    /*
    ** Advance to next port-list entry
    */

    ++pple;
  }

#ifdef   SVGA

  switch (ulSVGAAdapterType)
  {
    case  ATI_ADAPTER :                    /* see note above          */
      OUTB(PORT_MISCOUT,
           pVDMData(hvdm)->regMiscOut);
      break;
    case  TSENG_ADAPTER :
      OUTB(PORT_TSENG_SEGSELECT,
           pVDMData(hvdm)->regTsengSegSelect);
      break;
    case  TRIDENT_ADAPTER :
      i = INB(PORT_SEQINDX);               /* restore register
                                              definition              */
      OUTB(PORT_SEQINDX,
           INDX_TRIDENT_REGDEF);

      if (pVDMData(hvdm)->stateTridentRegDef)
        INB(PORT_SEQDATA);                 /* set new                 */

      else
        OUTB(PORT_SEQDATA,
             0x01);                        /* set old                 */
      OUTB(PORT_SEQINDX,
           i);
      break;
  }

#endif

#ifdef   VGA
  vvRestoreDACState(hvdm);                 /* special DAC restoration */
#endif
}
#pragma  END_SWAP_CODE

