/*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 = VVSVGA.C
 *
 * DESCRIPTIVE NAME = Virtual Video SVGA Specific Processing
 *
 *
 * VERSION = V2.0
 *
 * DATE      02/12/92
 *
 * DESCRIPTION  Virtual Video SVGA Specific Processing
 *
 * FUNCTIONS
 *              vvSVGACleanup()         Process CleanData array to fix registers to VGA defaults.
 *              vvSVGALockPushState()   Push SVGA extended register locks.
 *              vvSVGALockPopState()    Pop SVGA extended register locks.
 *              vvSVGALockRegisters()   Lock SVGA extended registers.
 *              vvSVGAUnLockRegisters() unlock SVGA extended registers.
 *              vvSVGAMaxBanks()        Calculate maximum number of banks
 *              vvSVGAFixSetMode()      Fix up regs based on the mode set
 *              vvSVGAFixSetBgnd()      Fix up reg state for background
 *
 * 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  BEGIN_SWAP_DATA
                                                                /*          */
/*
**     Externals
*/

extern ULONG flVVD;                                             /*            */
extern ULONG ulSVGAAdapterType;
extern ULONG ulSVGAVRAMSize;
extern PLE pleATC0;                                             /*          */
extern PLE pleGDCPos1;                                          /*          */
extern PLE pleMiscOutWrite;                                     /*          */
extern PLE pleFeatureWrite;                                     /*          */
extern BYTE aregSEQInit[];
extern SA8514INFO sA8514Info;                                   /*          */
extern PBYTE pPhysVRAM;
extern PFNINT2FP pfnInt2FProc;                                  /*          */
extern PSADAPTERINFO psCurAdapterInfo;                          /*          */
extern ULONG npgPhysVRAM;                                       /*            */
BOOL    flInt10Disabled = FALSE;                                /*            */
BOOL    fSVGASeqFixups = TRUE;                                  /*          */

BOOL    flBgndExecSupported = FALSE;                            /*          */

PSACCELERATORINFO psCurAcceleratorInfo;                         /*          */

#define AHWCCMDSVGASIZE ((MAX_LOCKUNLOCKCMD * 2) + MAX_CLEANDATA + MAX_SETBANK_CMD + MAX_GETBANK_CMD + 1) /*          */

HWCMD aHWCmdSVGA [AHWCMDSVGASIZE] = {{PMICMD_NONE}};            /*          */
UINT usaHWCmdSVGANext = 1;              /* First already used *//*          */

PHWCMD pHWCmdSVGALockData = aHWCmdSVGA;                         /*          */
PHWCMD pHWCmdSVGAUnLockData = aHWCmdSVGA;                       /*          */
PHWCMD pHWCmdSVGACleanData = aHWCmdSVGA;          /*          *//*          */
PHWCMD pHWCmdSVGASetBankData = aHWCmdSVGA;                      /*          */
PHWCMD pHWCmdSVGAGetBankData = aHWCmdSVGA;                      /*          */

//@V3.0YEE01 BYTE    abAccelGDCReadMask[32] =                        /*            */
//@V3.0YEE01 {
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01 };
//@V3.0YEE01 BYTE    abAccelSEQReadMask[32] =
//@V3.0YEE01 {
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01 };
//@V3.0YEE01 BYTE    abAccelCRTReadMask[32] =
//@V3.0YEE01 {
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
//@V3.0YEE01 };

BYTE abAccelGDCReadMask[MAX_GDCREGS] =                          /*@V3.0YEE01*/
{
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 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 */
};

BYTE abAccelSEQReadMask [MAX_SEQREGS] =                         /*@V3.0YEE01*/
{
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 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 */
};

BYTE abAccelCRTReadMask [MAX_CRTREGS] =                         /*@V3.0YEE01*/
{
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 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 */
};

#pragma  END_SWAP_DATA                                          /*          */
#pragma  BEGIN_SWAP_CODE                                        /*          */
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvSVGAExecCommands()
 *
 * DESCRIPTION   = Execute RegData command array on registers AND/OR shadow.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvSVGACleanup            (for all)
 *      vvSVGALockPushState
 *      vvSVGALockPopState
 *      vvSVGALockRegisters
 *      vvSVGAUnLockRegisters
 *      vvSVGASetBank
 *      vvSVGAGetBank
 *
 ****************************************************************************/

VOID PRIVENTRY vvSVGAExecCommands(                              /*          */
  HVDM hvdm,                                                    /*          */
  PHWCMD pHWCmd,                                                /*          */
  PULONG pulRegs )                                              /*          */
{
  register USHORT wIn;                                          /*          */
  BYTE bIndex;
  USHORT usCurrIndex, usLimitIndex;                             /*          */
  ULONG ulTimeout;                                              /*          */
  ULONG ulCount;                                                /*          */

  for( ;                                                        /*          */
       pHWCmd->usCommand;                                       /*          */
       pHWCmd++ )                                               /*          */
    switch( pHWCmd->usCommand )                                 /*          */
    {
      case PMICMD_INB:                                          /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          vvInput( hvdm,                                        /*          */
                   (PPLE) pHWCmd->hwSource.psTrapRegOperand );  /*          */
        break;                                                  /*          */
      case PMICMD_INW:                                          /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          vvInputWord( hvdm,                                    /*          */
                       pHWCmd->hwSource.psTrapRegOperand );     /*          */
        break;                                                  /*          */
      case PMICMD_OUTB:                                         /*          */
        vvOutput( hvdm,                                         /*          */
                  (PPLE) pHWCmd->hwTarget.psTrapRegOperand,     /*          */
                  (BYTE)                                        /*          */
                  ((pHWCmd->usFlags & PMIFLAG_REGISTER)         /*          */
                   ? pulRegs [pHWCmd->hwSource.ulOperand]       /*          */
                   : pHWCmd->hwSource.ulOperand) );             /*          */
        break;                                                  /*          */
      case PMICMD_OUTW:                                         /*          */
        vvOutputWord( hvdm,                                     /*          */
                      pHWCmd->hwTarget.psTrapRegOperand,        /*          */
                      (WORD)                                    /*          */
                      ((pHWCmd->usFlags & PMIFLAG_REGISTER)     /*          */
                       ? pulRegs [pHWCmd->hwSource.ulOperand]   /*          */
                       : pHWCmd->hwSource.ulOperand) );         /*          */
        break;                                                  /*          */
      case PMICMD_BINB:                                         /*          */
      case PMICMD_BOUTB:                                        /*          */
        /* In case index ple == &pleATC0 */                     /*          */
        if ( ((PPLE) pHWCmd->hwIndex.psTrapRegOperand)->
             sTrapBRegInfo.portTrap == PORT_ATC0)    /*            */
        vvInput( hvdm,                                          /*          */
                 &pleFeatureWrite );    /* =STATUS1 for read */ /*          */
        bIndex = vvInput( hvdm,                                 /*          */
                          (PPLE) pHWCmd->hwIndex.psTrapRegOperand );   /*          */
        /* In case index ple == &pleATC0 */                     /*          */
        if ( ((PPLE) pHWCmd->hwIndex.psTrapRegOperand)->
             sTrapBRegInfo.portTrap == PORT_ATC0)    /*            */
        vvInput( hvdm,                                          /*          */
                 &pleFeatureWrite );    /* =STATUS1 for read */ /*          */
        usCurrIndex = pHWCmd->hwModify.ulOperand;               /*          */
        usLimitIndex =                                          /*          */
          usCurrIndex + pHWCmd->hwCount.ulOperand;              /*          */
        for ( ;                                                 /*          */
              usCurrIndex < usLimitIndex;                       /*          */
              usCurrIndex++ )                                   /*          */
        {                                                       /*          */
          vvOutput( hvdm,                                       /*          */
                    (PPLE) pHWCmd->hwIndex.psTrapRegOperand,    /*          */
                    bIndex );                                   /*          */
          if( pHWCmd->usCommand == PMICMD_BINB )                /*          */
            pulRegs [usCurrIndex] =                             /*          */
              vvInput( hvdm,                                    /*          */
                       (PPLE) pHWCmd->hwSource.psTrapRegOperand );     /*          */
          else                                                  /*          */
            vvOutput( hvdm,                                     /*          */
                      (PPLE) pHWCmd->hwTarget.psTrapRegOperand, /*          */
                      (BYTE) pulRegs [usCurrIndex] );           /*          */
        }                                                       /*          */
        vvOutput( hvdm,                                         /*          */
                  (PPLE) pHWCmd->hwIndex.psTrapRegOperand,      /*          */
                  bIndex );                                     /*          */
        break;                                                  /*          */
      case PMICMD_RMWBI:                                        /*          */
        /* In case index ple == &pleATC0 */                     /*          */
        if ( ((PPLE) pHWCmd->hwIndex.psTrapRegOperand)->
             sTrapBRegInfo.portTrap == PORT_ATC0)    /*            */
        vvInput( hvdm,                                          /*          */
                 &pleFeatureWrite );    /* =STATUS1 for read */ /*          */
        bIndex = vvInput( hvdm,                                 /*          */
                          (PPLE) pHWCmd->hwIndex.psTrapRegOperand );   /*          */
        /* In case index ple == &pleATC0 */                     /*          */
        if ( ((PPLE) pHWCmd->hwIndex.psTrapRegOperand)->
             sTrapBRegInfo.portTrap == PORT_ATC0)    /*            */
        vvInput( hvdm,                                          /*          */
                 &pleFeatureWrite );    /* =STATUS1 for read */ /*          */
        vvOutput( hvdm,                                         /*          */
                  (PPLE) pHWCmd->hwIndex.psTrapRegOperand,      /*          */
                  (BYTE) pHWCmd->hwSource.ulOperand );          /*          */
        wIn = vvInput( hvdm,                                    /*          */
                       (PPLE) pHWCmd->hwTarget.psTrapRegOperand );     /*          */
        wIn &= pHWCmd->hwModify.ulOperand;
        wIn |= pHWCmd->hwCount.ulOperand;
        /* In case index ple == &pleATC0 */                     /*          */
        if ( ((PPLE) pHWCmd->hwIndex.psTrapRegOperand)->
             sTrapBRegInfo.portTrap == PORT_ATC0)    /*            */
        vvInput( hvdm,                                          /*          */
                 &pleFeatureWrite );    /* =STATUS1 for read */ /*          */
        vvOutput( hvdm,                                         /*          */
                  (PPLE) pHWCmd->hwIndex.psTrapRegOperand,      /*          */
                  (BYTE) pHWCmd->hwSource.ulOperand );          /*          */
        /* Cannot write to ATC1 == 0x03c1 on all adapters! */   /*          */
        /* Particularely not on TsengET4000W32!            */   /*          */
        vvOutput( hvdm,                                         /*          */
                  (((PPLE) pHWCmd->hwIndex.psTrapRegOperand ==  /*          */
                    &pleATC0)                                   /*          */
                   ? (PPLE) pHWCmd->hwIndex.psTrapRegOperand    /*          */
                   : (PPLE) pHWCmd->hwTarget.psTrapRegOperand), /*          */
                  (BYTE) wIn );                                 /*          */
        /* In case index ple == &pleATC0 */                     /*          */
        if ( ((PPLE) pHWCmd->hwIndex.psTrapRegOperand)->
             sTrapBRegInfo.portTrap == PORT_ATC0)    /*            */
        vvInput( hvdm,                                          /*          */
                 &pleFeatureWrite );    /* =STATUS1 for read */ /*          */
        vvOutput( hvdm,                                         /*          */
                  (PPLE) pHWCmd->hwIndex.psTrapRegOperand,      /*          */
                  bIndex );                                     /*          */
        break;
      case PMICMD_RMWBN:                                        /*          */
        wIn = vvInput( hvdm,                                    /*          */
                       (PPLE) pHWCmd->hwSource.psTrapRegOperand );     /*          */
        wIn &= pHWCmd->hwModify.ulOperand;
        wIn |= pHWCmd->hwCount.ulOperand;
        vvOutput( hvdm,                                         /*          */
                  (PPLE) pHWCmd->hwTarget.psTrapRegOperand,     /*          */
                  (BYTE) wIn );                                 /*          */
        break;
      case PMICMD_RMWWN:                                        /*          */
        wIn = vvInputWord( hvdm,                                /*          */
                           pHWCmd->hwSource.psTrapRegOperand ); /*          */
        wIn &= pHWCmd->hwModify.ulOperand;                      /*          */
        wIn |= pHWCmd->hwCount.ulOperand;                       /*          */
        vvOutputWord( hvdm,                                     /*          */
                      pHWCmd->hwTarget.psTrapRegOperand,        /*          */
                      wIn );                                    /*          */
        break;                                                  /*          */
     case PMICMD_WAIT:                                          /*          */
        for( ulCount = pHWCmd->hwCount.ulOperand;               /*          */
             ulCount;                                           /*          */
             --ulCount )                                        /*          */
        {                                                       /*          */
          ulTimeout = pHWCmd->hwIndex.ulOperand;                /*          */
          do                                                    /*          */
          {                                                     /*          */
            wIn =                                               /*          */
              vvInput( hvdm,                                    /*          */
                       (PPLE) pHWCmd->hwSource.psTrapRegOperand );/*          */
            wIn &= pHWCmd->hwModify.ulOperand;                  /*          */
          } while( (wIn != pHWCmd->hwTarget.ulOperand)          /*          */
                   && --ulTimeout );                            /*          */
        } /* endfor */                                          /*          */
        break;                                                  /*          */
      case PMICMD_WAITW:                                        /*          */
        ulTimeout = pHWCmd->hwIndex.ulOperand;                  /*          */
        do                                                      /*          */
        {                                                       /*          */
          wIn =                                                 /*          */
            vvInputWord( hvdm,                                  /*          */
                         pHWCmd->hwSource.psTrapRegOperand );   /*          */
          wIn &= pHWCmd->hwModify.ulOperand;                    /*          */
        } while( (wIn != pHWCmd->hwTarget.ulOperand)            /*          */
                 && --ulTimeout );                              /*          */
        break;                                                  /*          */
      case PMICMD_REGOP_ASSIGN:                                 /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          ((pHWCmd->usFlags & PMIFLAG_REGISTER)                 /*          */
           ? pulRegs [pHWCmd->hwSource.ulOperand]               /*          */
           : pHWCmd->hwSource.ulOperand);                       /*          */
        break;                                                  /*          */
      case PMICMD_REGOP_AND:                                    /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          pulRegs [pHWCmd->hwSource.ulOperand]                  /*          */
          & ((pHWCmd->usFlags & PMIFLAG_REGISTER)               /*          */
             ? pulRegs [pHWCmd->hwModify.ulOperand]             /*          */
             : pHWCmd->hwModify.ulOperand);                     /*          */
        break;                                                  /*          */
      case PMICMD_REGOP_OR:                                     /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          pulRegs [pHWCmd->hwSource.ulOperand]                  /*          */
          | ((pHWCmd->usFlags & PMIFLAG_REGISTER)               /*          */
             ? pulRegs [pHWCmd->hwModify.ulOperand]             /*          */
             : pHWCmd->hwModify.ulOperand);                     /*          */
        break;                                                  /*          */
      case PMICMD_REGOP_XOR:                                    /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          pulRegs [pHWCmd->hwSource.ulOperand]                  /*          */
          ^ ((pHWCmd->usFlags & PMIFLAG_REGISTER)               /*          */
             ? pulRegs [pHWCmd->hwModify.ulOperand]             /*          */
             : pHWCmd->hwModify.ulOperand);                     /*          */
        break;                                                  /*          */
      case PMICMD_REGOP_SHL:                                    /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          pulRegs [pHWCmd->hwSource.ulOperand]                  /*          */
          << ((pHWCmd->usFlags & PMIFLAG_REGISTER)              /*          */
              ? pulRegs [pHWCmd->hwModify.ulOperand]            /*          */
              : pHWCmd->hwModify.ulOperand);                    /*          */
        break;                                                  /*          */
      case PMICMD_REGOP_SHR:                                    /*          */
        pulRegs [pHWCmd->hwTarget.ulOperand] =                  /*          */
          pulRegs [pHWCmd->hwSource.ulOperand]                  /*          */
          >> ((pHWCmd->usFlags & PMIFLAG_REGISTER)              /*          */
              ? pulRegs [pHWCmd->hwModify.ulOperand]            /*          */
              : pHWCmd->hwModify.ulOperand);                    /*          */
        break;                                                  /*          */
      default:
        break;
    }
}

/***************************************************************************
 *
 * FUNCTION NAME = vvSVGACleanup()
 *
 * DESCRIPTION   = Process CleanData array to fix registers to VGA defaults.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvCreate                 (for all)
 *      vvWDFixRegs              (for WD only)
 *      vvSVGAFixSetBgnd         (for all)
 *
 ****************************************************************************/

VOID PRIVENTRY vvSVGACleanup(                                   /*          */
  HVDM hvdm,
  BOOL bForVDM )                                                /*          */
{
  register PVDMDATA pvd = pVDMData(hvdm);                       /*          */
  USHORT usDacRegIndex;                                         /*          */

  vvSVGAExecCommands( (bForVDM ? hvdm : INVALID_HVDM),          /*          */
                      pHWCmdSVGACleanData,                      /*          */
                      &pvd->VdmSVGA.aulScratchRegs [0] );       /*          */

  /*!!Expedient fix to save the DAC values which are not */     /*          */
  /*!!currently correctly shadowed by vvInput/vvOutput */       /*          */
  if( bForVDM )                                                 /*          */
    for( usDacRegIndex = 0;                                     /*          */
         usDacRegIndex < MAX_HICOLORDACREGS;                    /*          */
         usDacRegIndex++ )                                      /*          */
      /* Use DAC program parameters from cleanup! */            /*          */
      pvd->VdmSVGA.abregHiColorDac [usDacRegIndex] =            /*          */
        (BYTE) pvd->VdmSVGA.aulScratchRegs[usDacRegIndex];      /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvSVGALockPushState()
 *
 * DESCRIPTION   = Query extended registers lock state, push, and unlock.
 *
 * INPUT         = hvdm = handle to per VDM data
 *
 * OUTPUT        = registers are pushed and unlocked
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vvSVGALockPushState(                             /*          */
  HVDM hvdm )
{
  PVDMDATA pvd = pVDMData( hvdm );
  BOOL bPrevUnlock;

  bPrevUnlock = pvd->flVDMX2Video & VDMX2_LOCKSPUSHED;
  if( !bPrevUnlock )
  {
    pvd->flVDMX2Video |= VDMX2_LOCKSPUSHED;
    vvSVGAExecCommands( hvdm,                                   /*          */
                        pHWCmdSVGAUnLockData,                   /*          */
                        &pvd->VdmSVGA.aulReLockRegs [0] );      /*          */
  }
  return( bPrevUnlock );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvSVGALockPopState()
 *
 * DESCRIPTION   = Pop Lock State
 *
 * INPUT         = hvdm = handle to per VDM data
 *
 * OUTPUT        = registers are popped and (un?)locked
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvSVGALockPopState(                              /*          */
  HVDM hvdm,
  BOOL bPrevUnlock )
{
  USHORT usLockIndex;
  PVDMDATA pvd = pVDMData( hvdm );
  PHWCMD pHWCmd;

  if( !bPrevUnlock )
  {
    for( pHWCmd = pHWCmdSVGALockData;                           /*          */
         pHWCmd->usCommand == PMICMD_REGOP_ASSIGN;              /*          */
         pHWCmd++ )                                             /*          */
    {}                                                          /*          */
    vvSVGAExecCommands( hvdm,                                   /*          */
                        pHWCmd,                                 /*          */
                        &pvd->VdmSVGA.aulReLockRegs [0] );      /*          */
    pvd->flVDMX2Video &= ~VDMX2_LOCKSPUSHED;
  }
}
/***************************************************************************
 *
 * FUNCTION NAME = vvSVGALockRegisters()
 *
 * DESCRIPTION   = Lock SVGA extended registers.
 *
 * INPUT         = ULONG ulLockState    Lock State Mask
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvInt10Initialize
 *
 ****************************************************************************/

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

  vvSVGAExecCommands( (bForVDM ? hvdm : INVALID_HVDM),          /*          */
                      pHWCmdSVGALockData,                       /*          */
                      &pvd->VdmSVGA.aulScratchRegs [0] );       /*          */
}
/***************************************************************************
 *
 * FUNCTION NAME = vvSVGAUnLockRegisters()
 *
 * DESCRIPTION   = unlock SVGA extended registers.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
/****************************************************************************/

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

  vvSVGAExecCommands( (bForVDM ? hvdm : INVALID_HVDM),          /*          */
                      pHWCmdSVGAUnLockData,                     /*          */
                      &pvd->VdmSVGA.aulScratchRegs [0] );       /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvSVGASetBank()
 *
 * DESCRIPTION   = Set bank register
 *
 * INPUT         = hvdm
 *                 ulBank
 *                 fSetWriteBank
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvSVGASetBank(
  HVDM hvdm,
  ULONG ulBank,
  BOOL fSetWriteBank )
{
  register PVDMDATA pvd = pVDMData(hvdm);                       /*          */

  pvd->VdmSVGA.aulScratchRegs [0] = ulBank;
  pvd->VdmSVGA.aulScratchRegs [1] = fSetWriteBank;
  vvSVGAExecCommands( hvdm,                                     /*          */
                      &pHWCmdSVGASetBankData [1],               /*          */
                      &pvd->VdmSVGA.aulScratchRegs [0] );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvSVGAGetBank()
 *
 * DESCRIPTION   = Get bank register
 *
 *
 * INPUT         = hvdm
 *                 fGetWriteBank
 *
 * OUTPUT        = ulBank
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

ULONG PRIVENTRY vvSVGAGetBank(
  HVDM hvdm,
  BOOL fGetWriteBank )
{
  register PVDMDATA pvd = pVDMData(hvdm);                       /*          */

  pvd->VdmSVGA.aulScratchRegs [0] = fGetWriteBank;
  vvSVGAExecCommands( hvdm,                                     /*          */
                      pHWCmdSVGAGetBankData,                    /*          */
                      &pvd->VdmSVGA.aulScratchRegs [0] );
  return( pvd->VdmSVGA.aulScratchRegs [0] );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvInt10SetModePrepare()
 *
 * DESCRIPTION   = Prepare controller registers to Int 10h Setmode can work
 *
 *                 This subroutine is called to initialize the controller
 *                 registers so that Int 10 setmode in the VDM can succeed.
 *                 Generally, a BIOS should NOT need anything so that
 *                 an Int 10 setmode can succeed.
 *                 So this routine is really a concession to allow poorly
 *                 designed BIOSes or adapters to function.
 *                 The general idea is to convert
 *                 the controller states that bvh/svdh and other tasks use
 *                 into a controller state that the BIOS expects.
 *
 * INPUT         = hvdm = handle to VDM data.
 *
 * OUTPUT        = Controller or VDM shadow register changes
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *
 ****************************************************************************/

VOID PRIVENTRY vvInt10SetModePrepare(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData( hvdm );
  BOOL bPrevUnlock;                                             /*          */
  FLAGS flPrevVDMVideo;
  USHORT i;                                                     /*          */
  flPrevVDMVideo = pvd->flVDMVideo;

  /* Allow our routines to access controller as foreground */   /*          */
  pvd->flVDMVideo |= VDM_FGND;               /* force */        /*          */

  /* Read all controller registers to get an initial state */   /*          */
  /* But first unlock the registers to read them */             /*          */
  bPrevUnlock = vvSVGALockPushState( hvdm );                    /*          */
  if (psCurAdapterInfo->flSVGAAdapterFlag & SVGA_INT10INITUPDATEENABLED)        /*            */
     vvUpdateIOState( hvdm, TRUE );                                /*          */
  vvSVGALockPopState( hvdm, bPrevUnlock );                      /*          */
  pvd->flVDMVideo = flPrevVDMVideo;          /* force it back *//*          */

  /* Now we may be in the background: */                        /*          */
  vvSVGAUnLockRegisters( hvdm, TRUE );                          /*          */

  /* Now we want to clean up SVGA video modes */                /*          */
  /* in case the BIOS also does not handle SVGA modes. */       /*          */
  /* This would be particularly true of a standard VGA BIOS */  /*          */
  /* paired with an SVGA chip; */                               /*          */
  /* or a superset SVGA chip, with new functionality, */        /*          */
  /* paired with a BIOS for predecessor SVGA chip. */           /*          */
  /* Although IBM's PMI based BVH routines do this also */      /*          */
  /* before getting here, if your BVH is NOT PMI based */       /*          */
  /* you might not have this done for you already. */           /*          */
  /* Also, the BVH and VVID versions might be mismatched! */    /*          */
  /* Finally, we also want to set the lockable registers  */    /*          */
  /* correctly in case they were locked when we attempted */    /*          */
  /* to read them into the aregXXXInit arrays in VDDInit. */    /*          */
  vvSVGACleanup( hvdm , TRUE );                                 /*          */

  /* At this point OS2 may have adapter & chip unlocked. */     /*          */
  /* Or a different VDM instance many have a them in a */       /*          */
  /* different lock state. */                                   /*          */
  /* A BIOS *SHOULD* not care about the current lock state. */  /*          */
  /* It *SHOULD* unlock (or lock) what it needs to set */       /*          */
  /* a new video mode all by itself. */                         /*          */
  /* It *SHOULD* relock whatever it wants to assume */          /*          */
  /* for every other call EXCEPT setting the video mode. */     /*          */
  /* But many BIOSes will not set the video mode correctly */   /*          */
  /* without the lock state being as they last left it. */      /*          */
  /* This would be particularly true of a standard VGA BIOS */  /*          */
  /* paired with an SVGA chip; */                               /*          */
  /* or a superset SVGA chip, with new locks, */                /*          */
  /* paired with a BIOS for predecessor SVGA chip. */           /*          */
  /* We will be calling the BIOS to set mode 3 */               /*          */
  /* later in the VDM initialization. */                        /*          */
  /* So we restore the lock state to BIOS expectations. */      /*          */
  vvSVGALockRegisters( hvdm, TRUE );                            /*          */

}

/***************************************************************************
 *
 * FUNCTION NAME = vvSVGAMaxBanks()
 *
 * DESCRIPTION   = Calculate maximum number of banks
 *
 *                 Calculate the maximum number of banks used by this mode.
 *                 Note this doesn't take into account that the mode might
 *                 be a planar one.
 *
 *                 This routine is only called when:
 *                 mStateVideo == MEMORY_GRFX or MEMORY_GRFX256
 *
 *                 Note: the fixups for Western Digital and Trident are due
 *                 to CRT values not being 'correct' in the standard
 *                 registers which we use for the calculation.
 *                 Also the test for nBytes == 160 occurs only with certain
 *                 DRAM configurations which result in the CRT horizontal
 *                 Display End register reflecting this value. We therefore
 *                 cannot tell the difference between a normal mode set
 *                 and deliberately altered values which would allow for
 *                 horizontal panning.
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = ulMaxBanks
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvSetFgnd
 *      vvSetBgnd
 *      vvFaultHook
 *
 ****************************************************************************/

VOID PRIVENTRY vvSVGAMaxBanks(                                 /*          */
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  ULONG nBytes;                                                 /*          */
  register ULONG ulMaxBanks;                                    /*          */
  ULONG flFudge = FALSE;                                        /*            */
  /*
  ** We can't use the BIOS mode to determine the number of banks,
  ** BIOS mode in vvdata gets changed before the actual mode set
  ** took place.
  if( (((pvd->ulBIOSMode & ~BIOSVINFO_DONTCLEAR)
       <= BIOSVMODE_CO320X200X256)
       && !(pvd->flVDMXVideo & VDMX_ENHANCEDMODE)) ||
      (pvd->mstateVideo < MEMORY_GRFX))
  */
  /*
  ** If we didn't get far in the mode evaluation, return MAX_VGA_BANK.
  ** If non graphics mode, return MAX_VGA_BANK
  */
  if (!pvd->nBitsPixel ||
      !pvd->vvMode.vvm_nCols ||
      !pvd->nPlanes ||     /*            */
      (pvd->mstateVideo < MEMORY_GRFX))                   /*            */
  {
    pvd->VdmSVGA.usMaxBanks = (USHORT) MAX_VGA_BANK;
    pvd->nModeBytes = 0x0;
    return;
  }
  nBytes = (pvd->vvMode.vvm_nCols / 8) * pvd->nBitsPixel;     /*          *//*          */

  nBytes *= pvd->nPlanes;                                     /*          */
  /*
  ** Check for logical line length
  ** greater than the physical line.
  ** If so, use logical line length in determining
  ** maximum number of banks.
  */
  if ((pvd->mstateVideo == MEMORY_GRFX256) && (pvd->VdmSVGA.ulLogicalBytes > nBytes))                   /*                      */
    nBytes = pvd->VdmSVGA.ulLogicalBytes;                     /*          */
  else
     flFudge = TRUE;
  nBytes *= pvd->vvMode.vvm_nRows;                            /*          */
  /*
  ** If the logical line length didn't extend beyond the columns,
  ** handle some offscreen memory using fudge factor:
  */
  pvd->nModeBytes = nBytes;           /*            */
  if (flFudge)
    nBytes += nBytes >> 2;              /* +25%            */              /*          */
  /* Do sanity check to ensure */
  /* we don't try to save more */
  if( nBytes > ulSVGAVRAMSize )                               /*          */
    nBytes = ulSVGAVRAMSize;                                  /*          */

  /*
  ** Granularity of a bank is 64K in an enhanced mode and
  ** 256K in a planar mode. Two different limits are used for
  ** the page/bank state tables:
  ** 1MB for a planar and 4MB for a linear. Don't overcommit!
  */
  if (pvd->flVDMXVideo & VDMX_ENHANCEDMODE)                     /*            */
  {
    ulMaxBanks = ((nBytes - 1) >> 16) + 1;                      /*          */
    pvd->VdmSVGA.usMaxBanks = (USHORT) ((ulMaxBanks > MAX_LINEAR_BANKS)  ? MAX_LINEAR_BANKS : ulMaxBanks);
    return;   /*            */
  }
  else
  {
    ulMaxBanks = ((nBytes - 1) >> 18) + 1;                      /*          */
    pvd->VdmSVGA.usMaxBanks = (USHORT) ( (ulMaxBanks > MAX_BANKS)  ? MAX_BANKS : ulMaxBanks);
    return;   /*            */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vvTransferLinearBuffer()
 *
 * DESCRIPTION   = Transfer all reqd banks to/from physical VRAM
 *
 * INPUT         = hvdm  -> VDM
 *                 iMaxBanks == no of 64k banks to transfer
 *                 fVRAM == TRUE to transfer TO VRAM, FALSE to transfer FROM
 *
 * OUTPUT        = TRUE if successful, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *      if bank state is NOT INVALID
 *          exchange memory with buffer
 *      otherwise
 *          move memory to/from buffer
 *
 *      for all banks
 *          if bank-state is valid
 *            if bank-state differs from current copy-state
 *              set copy-state according to bank-state
 *            exchange bank with physical VRAM
 *
 ***************************************************************************/

BOOL PRIVENTRY vvTransferLinearBuffer(register HVDM hvdm,INT iMaxBanks,BOOL fVRAM)
{
  register INT    iBank;
  register PVDMDATA pvd = pVDMData(hvdm);
  PBYTE           pbSrc, pbDst;
  PBYTE           pbPhys, pbVirt;
  BYTE            bMiscOut;

  if (!(pvd->flVDMVideo & VDM_FGND) ||            /* must be foreground             */
       (!pvd->pLinearBuffer && fVRAM))            /* must have something to restore */
      return FALSE;

  vvGrowLinearBuffer(hvdm, iMaxBanks);            /*            */

  pvd->mstateCopy = MEMORY_NONE;

  pbPhys = pPhysVRAM;
  pbVirt = pvd->pLinearBuffer;

  /*** Prepare hardware for copy ***/
  vvSetCopyState( hvdm,
                  PAGE_GRFX256,
                  PLANE0 );

  bMiscOut = vvInput( INVALID_HVDM,                             /*          */
                      &pleGDCPos1 );    /* Read MiscOut */      /*          */
  if( !(bMiscOut & 0x02) )              /* VRAM disabled? */    /*          */
    vvOutput( INVALID_HVDM,                                     /*          */
              &pleMiscOutWrite,                                 /*          */
              (BYTE) (bMiscOut | 0x02) ); /* enable VRAM */

  for (iBank=0; iBank < iMaxBanks; iBank++, pbVirt+=BANKSIZE)
  {
    (*psCurAdapterInfo->pfnSVGASetBank)                         /*          */
      ( hvdm,
        iBank,
        fVRAM );
    if( fVRAM )
    {
      pbSrc = pbVirt;
      pbDst = pbPhys;
      pvd->abstate [iBank] |= BANK_INVRAM;
    }
    else
    {
      pbSrc = pbPhys;
      pbDst = pbVirt;
      pvd->abstate [iBank] &= ~BANK_INVRAM;
    }
    if( pvd->abstate [iBank] & BANK_INVALID )
    {
      pvd->abstate[iBank] &= ~BANK_INVALID;
      /*** Move the page to/from physical VRAM ***/
      vdhMoveMem(pbSrc, pbDst, 1, 1, BANKSIZE, FALSE);
    }
    else
      /*** Exchange the page with physical VRAM ***/
      vdhMoveMem(pbSrc, pbDst, 1, 1, BANKSIZE, TRUE);
  }
  if( !(bMiscOut & 0x02) )              /* VRAM disabled? */    /*          */
    vvOutput( INVALID_HVDM,                                     /*          */
              &pleMiscOutWrite,                                 /*          */
              bMiscOut );                                       /*          */
  return( TRUE );
}

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

VOID PRIVENTRY vvSVGAFixSetMode(                                /*          */
  HVDM hvdm )                                                   /*          */
{
  register ULONG ulMode;
  /* BOOL flLocked; */                            /*          *//*          */
  BOOL bPrevUnlock;                                             /*          */

  /* No more locks*/                                            /*          */
  /* if( flLocked = vvSVGAGetLockState(CURRENT_VDM)) */         /*          */
  /*   flLocked = vvSVGAGetLockState( CURRENT_VDM ); */         /*          */
  /* vvUnLockSVGARegisters(); */                                /*          */
  /* Add locks again, but this time, PUSH! */                   /*          */
  bPrevUnlock = vvSVGALockPushState( CURRENT_VDM );             /*          */

  /* Just do the mode check inside the switch */                /*          */
  ulMode = pVDMData(hvdm)->ulBIOSMode & ~BIOSVINFO_DONTCLEAR;   /*          */
  (*psCurAdapterInfo->pfnSVGAFixSetMode)( hvdm, ulMode );       /*          */
  /* No more locks*/                                            /*          */
  /* if (flLocked) */
  /*   vvSVGALockRegisters( flLocked ); */        /*          *//*          */
  /* vvSVGALockRegisters( flLocked ); */          /*          *//*          */
  /* Add locks again, but this time, POP! */                    /*          */
  vvSVGALockPopState( CURRENT_VDM, bPrevUnlock );               /*          */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvSVGAFixSetBgnd()
 *
 * DESCRIPTION   = Fix up register state for background.
 *
 *                 This subroutine fixes up various register states for PM
 *                 when a full screen VDM is going into the background.
 *                 This allows PM the full access to the controller that
 *                 it expects.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      VVSetBgnd
 *
 ****************************************************************************/

VOID PRIVENTRY vvSVGAFixSetBgnd(
  HVDM hvdm )
{
  USHORT i,j;
  /* BOOL flLocked; */                            /*          *//*          */
  BOOL bPrevUnlock;                                             /*          */

  /*
  ** Cleanup is executed at the end of setbgnd. If 2F handler was
  ** invoked, state of the lock registers is not necessarily the
  ** same as set by the SetBgnd (unlocked). Therefore, do an explicit
  ** unlock.                                              
  */
  vvSVGAUnLockRegisters( hvdm, FALSE );                         /*          */

  (*psCurAdapterInfo->pfnSVGAFixSetBgnd)( hvdm );               /*          */
  vvSVGACleanup( hvdm, FALSE );                                 /*          */

  vvSVGALockRegisters( hvdm, FALSE );                           /*          */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvSVGASetBgnd
 *
 * DESCRIPTION   =  SVGA background processing
 *
 *                  This routine is called by vvSetBgnd to take appropriate
 *                  action depending on the video switch property. If set, it
 *                  will delay session switch until INT 2F completes so that
 *                  full foreground video access is given to the VDM.
 *                  This function assumes that mutex sem to instance is
 *                  already acquired and will not release it at the end.
 *                  It also assumes that instance is marked BGND already.
 *
 * INPUT         = hvdm == VDM handle
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      VVSetBgnd
 *
 **************************************************************************/
VOID PRIVENTRY vvSVGASetBgnd(HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  BOOL f2FStatus;                                /*                         */
  BOOL bPrevUnlock;                                             /*          */

  /*
  ** If 2F property exists, we need to delay the session switch
  ** until 2F handler finishes, so that it has full access to
  ** the hardware. When 2F completes, we mark instance as BGND
  ** and setup another appointment to install all the hooks and
  ** perform the mappings in the BgndContext.
  ** If the property is not set, we freeze the modes that can't
  ** be virtualized at this point.
  */

  if (!(pvd->flVDMXVideo & VDMX_INT2F)                          /*          */
      || (pfnInt2FProc != NULL) )                               /*          */
  {

    /*
    ** In another device registered for 2F notification with us, don't
    ** block the switch thread as they may be doing the same, but
    ** setup all the IO hooks and perform the mapping as well as
    ** issue the Int 2F. Don't freeze the VDM for the same reason.
    */
    if((pfnInt2FProc != NULL) && (pvd->flVDMXVideo & VDMX_INT2F))
    {
      pvd->flVDMXVideo |= VDMX_INT2FREGIST;
      pvd->flVDMXVideo &= ~VDMX_INT2FPENDING;
      pvd->flVDMVideo  |= VDM_FGND;                                  /*            */
    }
  }
  else if (pvd->flVDMVideo & VDM_IOINIT)                              /*            */
  {
    /*
    ** Mark the instance as pending and foreground
    ** so that BgndContext knows not to install
    ** the hooks and just call the Int2FNotify routine.
    ** This is not done on instance creation.
    */
    pvd->flVDMXVideo |= VDMX_INT2FPENDING;
    pvd->flVDMVideo  |= VDM_FGND;                                     /*            */
    f2FStatus = TRUE;
    pvd->flVDMVideo &= ~VDM_FROZEN;
    /*
    ** On accelerated adapters, VDM has to be allowed to run until
    ** all engine pending commands are satisfied before switching it into
    ** the background. This is enforced thru block/release of the shell
    ** thread on hev8514Busy semaphore. VDM's access to the accelerator
    ** ports release this semaphore, but block the VDM itself. VDM then must
    ** be allowed to run so that 2F notification is received.
    */
    vvAcceleratorUnlockIO( hvdm );                              /*          */
    ReleaseMutexSem(pvd->hmxVideoState);
    /*
    ** Make sure we thaw the instance completely.
    */
    while (VDHIsVDMFrozen(hvdm))
      VDHThawVDM(hvdm);

    /*
    ** Make sure VDM is not blocked as idle.
    ** Block on the 2F semaphore until either timeout occurs or
    ** 2F successfuly returns.
    */
    VDHWakeIdle(hvdm);                                                /*          */
    VDHResetEventSem( pvd->VdmSVGA.hevDelaySwitch );                      /*          */
    if(!VDHWaitEventSem( pvd->VdmSVGA.hevDelaySwitch,
                         MAX_VDM_WAIT ) )
       f2FStatus = FALSE;
    RequestMutexSem(pvd->hmxVideoState);
    VDHFreezeVDM(hvdm);
    pvd->flVDMVideo &= ~VDM_FGND;                                     /*            */
    pvd->flVDMXVideo &= ~VDMX_INT2FPENDING;
    /*
    ** Instance already marked BGND by the first context.
    ** Setup another appointment for BgndContext to do
    ** all the background preparations.
    */
    if (!vdhBTS(&pvd->flVDMVideo,
                LOG2(VDM_BGNDHOOK))){
      VDHWakeIdle(hvdm);                                              /*            */
      VDHArmContextHook(pvd->hhookBgndContext,
                        hvdm);
    }
  }
}
/***************************************************************************
 *
 * FUNCTION NAME =  vvSVGARestoreFgnd
 *
 * DESCRIPTION   =  SVGA foreground restore processing
 *
 *                  This routine is called by vvSetFgnd to restore the state
 *                  of the VDM to the state of its shadow registers.
 *
 * INPUT         = hvdm == VDM handle
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvSVGARestoreModeReturn (which has already acquired the semaphore)
 *
 **************************************************************************/
VOID PRIVENTRY vvSVGARestoreFgnd(HVDM hvdm, ULONG fRestore)             /*            */
{
  INT iBankNo,iBankEnd;
  BOOL flTransferDone;
  BOOL bPrevUnlock;
  FLAGS flPrevVDMVideo;
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** 1) fRestore & SVGA_RESTORE_FULL_PASS means
  **    RestoreIOState, Transfer, RestoreIOState.
  **    Unlock real regs, shadow, restore lock state as VDM left it
  ** 2) fRestore & SVGA_RESTORE_FIRST_PASS means
  **    RestoreIOState only. Unlock real regs, shadow regs, restore shadow regs
  **    leave VDM locked as BIOS expects it.
  ** 3) fRestore & SVGA_RESTORE_SECOND_PASS means
  **    Transfer, RestoreIOState.
  **    Unlock real regs, shadow regs, restore shadow regs, restore lock regs as VDM left it.
  */
  if (fRestore & SVGA_RESTORE_FIRST_PASS)
  {
     flPrevVDMVideo = pvd->flVDMVideo;
     /* unlock real hardware */
     vvSVGAUnLockRegisters( hvdm, FALSE );
     pvd->flVDMVideo &= ~VDM_FGND;
     /* enforce bgnd flag as to save shadow lock state first and unlock shadow for the restore */
     bPrevUnlock = vvSVGALockPushState( hvdm );
     pvd->flVDMVideo = flPrevVDMVideo;
     /*
     ** Restore physical latches, before I/O state is restored
     */

     vvRestoreLatches(hvdm,
                     FALSE);

     /*
     ** Update physical registers with virtual I/O state
     */

     vvRestoreIOState(hvdm);
  }
  vvDisableDisplay(hvdm);
  if (fRestore & SVGA_RESTORE_SECOND_PASS)
  {

    if (fRestore != SVGA_RESTORE_FULL_PASS)
    {
        /* unlock real hardware */
        vvSVGAUnLockRegisters( hvdm, FALSE );
        flPrevVDMVideo = pvd->flVDMVideo;
        pvd->flVDMVideo &= ~VDM_FGND;
        /* enforce bgnd flag as to save shadow lock state first and unlock shadow for the restore */
        bPrevUnlock = vvSVGALockPushState( hvdm );
        pvd->flVDMVideo = flPrevVDMVideo;
    }
    if( (pvd->mstateVideo == MEMORY_GRFX)
        || (pvd->mstateVideo == MEMORY_GRFX256) )
    {
        vvSVGAMaxBanks(hvdm);
        iBankEnd = pvd->VdmSVGA.usMaxBanks;             /*            */
    }
    else
        iBankEnd = 1;
    /*
    ** Special case mode 13 with CHAIN4 bit reset. Treat it as
    ** a planar mode and update its page states to include all the
    ** planes.                                                             
    */

    if(((pvd->ulBIOSMode&~BIOSVINFO_DONTCLEAR) ==
        BIOSVMODE_CO320X200X256) &&
        !(pvd->aregSEQData[REG_SEQMEMMODE] & SEQMEM_CHAIN4))
        vvPrepareForTransfer(hvdm,TRUE,iBankEnd);

    if (pvd->flVDMXVideo & VDMX_ENHANCEDMODE)
        flTransferDone =
                vvTransferLinearBuffer( hvdm,
                                        iBankEnd,
                                        TRUE);
    else
        flTransferDone =
                vvTransferBuffer( hvdm,
                                iBankEnd,               /*            */
                                TRUE );
    /*
    ** Update physical video memory with virtual memory
    */

    if ((!flTransferDone) &&
    !(pvd->flVDMVideo & VDM_MODECHANGING))
    {
        vvAddEvent(hvdm,
                        VVDEVENT_SWITCHERROR,
                        NULL,
                        0);
        flVVD |= VVD_VRAMISTOAST;      /* tell PM to repaint */ /*          */
        return;
    }

    /*
    ** Restore physical latches, before I/O state is restored
    */

    vvRestoreLatches(hvdm,
                    FALSE);
    /*
    ** Update physical registers with virtual I/O state
    */

    vvRestoreIOState(hvdm);
    /*
    ** Put pointer back on screen, if one exists
    */

    if (!pvd->PtrData.fPtrFrozenVideo && pvd->PtrData.flPtrVideo&PTR_ACTIVE)
    {
            pvd->flVDMVideo |= VDM_IOUPDATED;
            vvPtrDraw(hvdm,
                    pvd->PtrData.xPtrVideo,
                    pvd->PtrData.yPtrVideo);
            pvd->flVDMVideo &= ~VDM_IOUPDATED;
    }

    if(pvd->mstateVideo)
        vvEnableDisplay(hvdm);
  }
  /*
  ** Lock according to the 1), 2) or 3) pass type.
  */
  if (fRestore & SVGA_RESTORE_SECOND_PASS)
     vvSVGALockPopState( hvdm, bPrevUnlock );   //restore the clients hardware lock state
  else
  {
     flPrevVDMVideo = pvd->flVDMVideo;
     pvd->flVDMVideo &= ~VDM_FGND;              /* enforce bgnd flag */
     vvSVGALockPopState( hvdm, bPrevUnlock );   //restore shadow lock state
     pvd->flVDMVideo = flPrevVDMVideo;
     vvSVGALockRegisters( hvdm, FALSE );        //lock the hardware how BIOS expects it
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vvSVGARestoreModeReturn()
 *
 * DESCRIPTION   = Issue Int 10h set mode in VDM's context (return hook)
 *
 *                 This is the return hook from injected restore mode set.
 *                 Its purpose is to restore the shadow VRAM and shadow register
 *                 state as well as enable the buffer.
 *
 * INPUT         = p    == undefined
 *                 pcrf -> VDM register frame (NULL if called from VDD)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID HOOKENTRY vvSVGARestoreModeReturn(PVOID p,PCRF pcrf)      /*            */
{
  PBYTE pData;
  INT i;
  RequestMutexSem(VDMData.hmxVideoState);

  /*
  **            Instead of using VDHPush/VDHPop which in certain instanced
  ** gives corruption of the PCRF_SP, although our calls are matched, I'll
  ** save/restore the AX, BX in the scratch area.
  */

//            VDHPopRegs(VDHREG_AX|VDHREG_BX);
  AX(pcrf) = VDMData.VdmSVGA.regAXSave;
  BX(pcrf) = VDMData.VdmSVGA.regBXSave;
  /*
  ** Restore relevant bytes in the BIOS data.
  */

  pData = &VDMBase.rb_bVMode;
  for (i=0;i<30;i++)
  {
     *pData = VDMData.VdmSVGA.abBiosData_1[i];
     (BYTE *)pData++;
  } /* endfor */

  pData = &VDMBase.rb_nVRows;
  for (i=0;i<7;i++)
  {
     *pData = VDMData.VdmSVGA.abBiosData_2[i];
     (BYTE *)pData++;
  } /* endfor */

  VDMData.PtrData.fPtrFrozenVideo--;
  AssertTRUE(VDMData.PtrData.fPtrFrozenVideo >= 0);

  VDMData.flVDMX2Video  &= ~VDMX2_IGNOREINT10;
  VDMData.nInt10Setmode--;
  VDMData.flVDMVideo &= ~VDM_MODECHANGING;
  /* restore memory mode before the buffer can be restored */
  vvRestoreCopyState(CURRENT_VDM, SETIO_SHADOWED);
  vvSVGARestoreFgnd(CURRENT_VDM,SVGA_RESTORE_SECOND_PASS);
  /*
  ** Install foreground hooks in now.
  */

  if( !(VDMData.flVDMVideo & VDM_FGNDREADY) )
  {
    vvSetIOHooks( FALSE,                /* Fgnd */
                  TRUE,               /* Install */
                  TRUE );             /* Wait */
    VDMData.flVDMVideo |= VDM_FGNDREADY;
  }
  vvEnableIO();
  /*
  ** The VGA aperture was mapped into a black hole, as not to allow the
  ** injected BIOS call to mess up either the VRAM or the shadow.
  ** Make all the pages invalid, as to prepare for the enable buffer,
  ** which will map all of the uvirt pages into the physical.
  */
  for (i = 0; i < npgPhysVRAM; i++)
  {

    if (!VDHMapPages(NULL,
                    &VDMData.avdhmt[i],
                    VDHMT_INVALID))
      VDHGetError();
    VDMData.ulMapCur[i] = VDHMT_INVALID;
  }
  /*
  ** Set up appropriate mappings
  */
  VVEnableBuffer( TRUE,
                  pcrf );
  /*
  ** Post the event semaphore to let the switch thread go.
  */
  VDHPostEventSem(VDMData.VdmSVGA.hevDelaySwitch);         /*          */
  ReleaseMutexSem(VDMData.hmxVideoState);
}

/***************************************************************************
 *
 * FUNCTION NAME = VVSVGAFgndRestoreModeContext()
 *
 * DESCRIPTION   =  Inject either a 2F or an int10 in order to restore the
 *                  VDM's state.
 *
 *                  This is a context hook armed by VVSetFgnd and called in
 *                  the context of the new foreground VDM.
 *
 * INPUT         = p    == undefined
 *                 pcrf -> VDM register frame (NULL if called from VDD)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/
VOID HOOKENTRY vvSVGAFgndRestoreModeContext(PVOID p,PCRF pcrf)
{
  ULONG i;
  RequestMutexSem(VDMData.hmxVideoState);
  if (pcrf)
    VDMData.flVDMVideo &= ~VDM_FGNDHOOK;
  if (VDMData.flVDMVideo&VDM_FGND)
  {
    /*
    ** If background hooks installed, remove
    */

    if( VDMData.flVDMVideo & VDM_BGNDREADY )
    {
      vvSetIOHooks( TRUE,               /* Bgnd */              /*          */
                    FALSE,              /* Remove */
                    TRUE );             /* Wait */
      VDMData.flVDMVideo &= ~VDM_BGNDREADY;
    }

    vvAcceleratorSetBgndOnlyHooks( FALSE );

    /*
    ** If foreground hooks installed, remove them.
    */

    if(VDMData.flVDMVideo & VDM_FGNDREADY)
    {
      vvSetIOHooks( FALSE,              /* Fgnd */
                    FALSE,               /* Remove */
                    TRUE );             /* Wait */
      VDMData.flVDMVideo &= ~VDM_FGNDREADY;
    }
    /*
    ** Map the linear A0000 to physical A0000 address, so that any access by the BIOS
    ** does not affect the shadow VRAM. This will prevent us from handling any fault hooks
    ** which may cause a page state to get corrupted and endanger the transfer of the
    ** shadow VRAM. Note that we do set the IGNORE_FAULT VDM flag, just in case a
    ** fault sneaks in.
    */
    if (VDMData.flVDMXVideo & VDMX_INT10RESTORE)
    {
      INT iMMIOStart = 0xFFFF;
      ULONG flOption;
      VDMData.vdhmt.vdhmt_cpg = 0x1;
      if (VDMData.VdmSVGA.pvdmMMIOActive)
        iMMIOStart = (INT) VDMData.VdmSVGA.pvdmMMIOActive/PAGESIZE;
      for (i = 0; i < npgPhysVRAM; i++)
      {
        if (!VDHMapPages(NULL,
                        &VDMData.avdhmt[i],
                        VDHMT_INVALID))
          VDHGetError();                //get the error for info, not much we can do.
        flOption = VDHMT_BLACK_HOLE;
        if ((iMMIOStart > 0) && (i >= iMMIOStart) &&
           (i < iMMIOStart+VDMData.VdmSVGA.npgMMIOActive))
        {
          flOption = VDHMT_PHYSICAL;
          VDMData.ulMapCur[i] = VDMData.avdhmt[i].vdhmt_laddr | flOption;
        }
        if (!VDHMapPages(NULL,
                        &VDMData.avdhmt[i],
                        flOption))
          VDHGetError();
      }
    }
    if (pcrf)
    {
      if (VDMData.flVDMXVideo & VDMX_INT10RESTORE)               /*            */
      {
        /*
        ** Prepare the hardware for the int 10 set mode.
        */
        vvSVGARestoreFgnd(CURRENT_VDM, SVGA_RESTORE_FIRST_PASS);              /*            */
        vvInt10Initialize(pcrf);                                 /*            */
      }
      else if (VDMData.flVDMXVideo & VDMX_INT2F)
        vvInt2FNotify(INT2F_SYSFGND,                    //this will do its own vvInt10SetModePrepare
                      pcrf);
      else      //we got called by an error, make sure that the switch thread is released.
        VDHPostEventSem(VDMData.VdmSVGA.hevDelaySwitch);         /*            */
    }
    if (vdhBTR(&VDMData.flVDMVideo,
               LOG2(VDM_FROZEN)))
      VDHThawVDM(CURRENT_VDM);
  }
  ReleaseMutexSem(VDMData.hmxVideoState);
}
#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA                                        /*          */

#pragma  END_SWAP_DATA                                          /*          */
