/*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 = VVUSER.C
 *
 * DESCRIPTIVE NAME = Virtual Video Device Driver User-event Processing
 *
 *
 * VERSION = V2.0
 *
 * DATE      11/10/88
 *
 * DESCRIPTION  This module contains the VVD's user-event handlers.
 *
 *
 * FUNCTIONS    VVCreate()              VDM creation notification
 *              VVCreateDone()          VDM creation done notification
 *              vvSVGAEditVideoTables() Called once to do SVGA-specific
 *                                      initialisation
 *              VVSetFgnd()             VDM foreground notification
 *              VVSetBgnd()             VDM background notification
 *              VVChangeCodePage()      VDM codepage change notification
 *              VVChangeTitle()         VDM title change notification
 *              VVDestroy()             VDM termination notification
 *              VVSetInt10Emulation     Set per-VDM INT 10h emulation flag
 *              VVSetRetraceEmulation   Set per-VDM retrace emulation flag
 *              VVSetUpdateFrequency    Set per-VDM graphics update frequency
 *              VVSetInt2F              Set per-VDM INT 2Fh flag
 *              VVSetOnDemandAlloc      Set per-VDM on-demand allocation flag
 *              VVFgndContext()         Finish foreground switch in VDM's context
 *              VVBgndContext()         Finish background switch in VDM's context
 *              vvFreezeVDM()           Worker to freeze VDM/notify Shield
 *              vvThawVDM()             Worker to thaw VDM/notify Shield
 *              vvInt2FNotify()         Worker to issue INT 2Fh to VDM
 *              vvInt2FReturn()         Return hook for our INT 2Fh calls
 *              VDHRegisterInt2FProc    INT 2F registration routine
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#include <mvdm.h>
#include <vvd.h>
#include "vvdp.h"

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif
extern ULONG flVVD;
/*extern BOOL  flBigSel = FALSE;                            73541           */

#ifdef   VGA                                     /*                         */
extern BOOL   flDualDisplayConf;                 /*          */
extern FLAGS flNotifyType;                       /*                         */
extern PFNINT2FP pfnInt2FProc;                   /*                         */
#endif                                           /*                         */
#pragma  BEGIN_SWAP_DATA
extern HVDM hvdmFocus;
extern HVDM hvdmUpdate;
extern PSZ pszVVDName;
extern PBVDM pvdmROMFont;
extern ULONG nbROMFontEntry;
extern ULONG npgPhysVRAM;
extern HVDD hvddMouse;
extern VMREG vmreg;
extern VMFUNC vmfunc;
extern PLE apleAll[];                                           /*          */
extern PLE apleNoTrap[];                                        /*          */
extern PLE pleVGADACRead;                                       /*          */
extern PLE pleVGADACData;                                       /*          */

extern LSENTRY lseHeadActive;
extern ULONG nWindowedEvents;
extern HMXSEM hmxWindowedEvent;
extern PBVDM pvdmPhysVRAM;
extern ULONG nWindowedVDMs;
extern ULONG nPMWindowedVDMs;
extern ULONG nMinWindowedVDMs;

#ifdef   VGA
extern BYTE aregSEQInit[];
extern BYTE aregGDCInit[];                                      /*          */
extern BYTE aregCRTInit[];                                      /*          */
extern PSADAPTERINFO psCurAdapterInfo;                          /*          */
#endif

#ifdef   SVGA
extern BYTE aregATIInit[ATI_TOTAL_INITREGS];
extern BOOL     flBgndExecSupported;                            /*          */
extern BOOL     flInt10Disabled;                                /*            */
extern BYTE aregCRTCBInit[TOTAL_TSENG_CRTCBREGS];               /* JWK01 */
#endif

#ifdef   PROPERTIES
extern SZ szPropInt10Emulate;
extern SZ szPropRtrcEmulate;
extern SZ szPropModeRestrict;
extern SZ szPropNoRestrict;
extern SZ szPropCGARestrict;
extern SZ szPropIOTrap;                                         /*          */
extern SZ szDOSBgndExec;                                        /*          */

   #ifndef  CGA
extern SZ szPropMONORestrict;
   #endif
extern SZ szPropUpdateWindow;

extern SZ szPropInt2F;
extern SZ szPropOnDemandAlloc;
extern SZ szVMBoot;
#endif

#pragma  END_SWAP_DATA

#ifdef   EGAVGA
   #pragma  BEGIN_GLOBAL_DATA
extern HVDM hvdmController;
   #pragma  END_GLOBAL_DATA
#endif
#pragma  BEGIN_SWAP_CODE

/***************************************************************************
 *
 * FUNCTION NAME = VVCreate()
 *
 * DESCRIPTION   = VDM creation notification
 *
 *                 This registered subroutine is called each time a new VDM
 *                 is created (see VDHInstallUserHook for complete
 *                 semantics).
 *
 *                 Virtual memory buffer(s) are fully allocated at this time
 *                 to insure the system *could* bring the VDM foreground
 *                 later.  If the VDM is being started in the foreground,
 *                 then when SetFgnd grows the buffers, effectively nothing
 *                 happens, since they were already grown here; if the VDM is
 *                 being started in the background, then when SetBgnd shrinks
 *                 the buffers, they will be shrunken normally.  "Spiking"
 *                 the system's memory overcommit in this way should help
 *                 eliminate the chance of an interactive DOS application,
 *                 started in the background, beginning some critical
 *                 operation which must be brought foreground and yet can't.
 *                 Forcing the user to kill off such a VDM is highly
 *                 undesirable.
 *
 *
 *
 *
 * INPUT         = hvdm -> new VDM
 *
 * OUTPUT        = SUCCESS
 *                     TRUE (new VDM accepted)
 *                 FAILURE
 *                     FALSE (eg, not enough memory)
 *                     It is assumed that
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 *  PSEUDO-CODE
 *                 determine ownership
 *                 allocate maximum background storage for VDM
 *                 if error
 *                   fail the creation
 *                 define video software interrupt hook
 *                 establish communication with virtual mouse driver
 *
 **************************************************************************/

BOOL EXPENTRY VVCreate(HVDM hvdm)
{
  register INT i;
  PSZ pszTmp;
  PBVDM pvdmEBIOS;
  ULONG nbRMSize,nbTotalSize;
  INT iVirt, tmp;   //V2.0JWK61
  HHOOK hhook;      //V2.0JWK61

#ifdef   SVGA
  USHORT svga;
  BYTE bIndex;                                                  /*          */
#endif

#ifdef   SVGA
  vvPMIProcessFile( SVGA_PMIFILENAME );                         /*          */
#endif

  /*
  ** NOTES ON SEMAPHORE HIERARCHY
  ** (maintained in vvinit.c and vvuser.c)
  **
  ** The Video VDD's semaphore hierarchy is as follows:
  **
  **  1. hmxWindowedState
  **  2. hmxVideoState
  **  3. hvdmController
  **  4. hmxPhysPageEvent
  **  5. hmxWindowedEvent
  **  6. hmxPhysLatch
  **
  ** The per-VDM semaphores are first, because we generally enter the VDD
  ** in (or on behalf of) a VDM's context.  hvdmController is next because
  ** of the constraints of our interface with the PM display driver (see
  ** vvGetPhysBytes and vvFreePhysBytes for more details).  From that point
  ** on, the semaphores are basically in order of high-level to low-level
  ** operation.
  **
  ** Note that driver entry points can enter the hierarchy at any point,
  ** but must take care to not call routines that require semaphores at some
  ** higher point.  I need to eventually build some assertion checking into
  ** the RequestMutexSem macro, but because some are per-vdm and some are
  ** not conventional (ie, hvdmController), it'll take some time....
  */

  /*
  ** Allocate all per-VDM semaphores
  */

  if (!CreateMutexSem(&pVDMData(hvdm)->hmxWindowedState))
    return  FALSE;


  if (!CreateMutexSem(&pVDMData(hvdm)->hmxVideoState))
    return  FALSE;


  if (!CreateEventSem(&pVDMData(hvdm)->hevFreezeThaw))
    return  FALSE;


  if (!CreateEventSem(&pVDMData(hvdm)->hevShieldSynced))
    return  FALSE;

#ifdef SVGA
  if (!CreateEventSem(&pVDMData(hvdm)->VdmSVGA.hevDelaySwitch))
    return  FALSE;

  if( !vvAcceleratorCreate( hvdm ) )                            /*          */
    return( FALSE );
#endif /* SVGA */

  /*
  ** Allocate context hook handles
  */

  if ((VDMData.hhookFgndContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                               (PFNARM)VVFgndContext,
                                               0)) == NULL)
  {
    return  FALSE;
  }
#ifdef SVGA

  if ((VDMData.hhookFgndRestoreContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                               (PFNARM)vvSVGAFgndRestoreModeContext,
                                               0)) == NULL)
  {
    return  FALSE;
  }
#endif


  if ((VDMData.hhookBgndContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                               (PFNARM)VVBgndContext,
                                               0)) == NULL)
  {
    return  FALSE;
  }


  if ((VDMData.hhookInitContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                               (PFNARM)VVInitContext,
                                               sizeof(BOOL))) == NULL)
  {
    return  FALSE;
  }


  if ((VDMData.hhookUpdatePtrContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                                    (PFNARM)VVUpdatePtrContext,
                                                    sizeof(ULONG))) == NULL)
  {
    return  FALSE;
  }

#ifdef   EGAVGA

  if ((VDMData.hhookUpdateContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                                 (PFNARM)VVUpdateContext,
                                                 0)) == NULL)
  {
    return  FALSE;
  }


  if ((VDMData.hhookUpdatePhysContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                                     (PFNARM)
                                                        VVUpdatePhysContext,
                                                     0)) == NULL)
  {
    return  FALSE;
  }

  if (ALLOCHOOK((PFNARM)VVUnmapPhysContext, 1,VDMData.hhookUnMapPhysContext , tmp))      //V2.0JWK61
  {                                                                                      //V2.0JWK61
     HOOKDATA(VDMData.hhookUnMapPhysContext, 0) = 0;                                     //V2.0JWK61
  }                                                                                      //V2.0JWK61
  else                                                                                   //V2.0JWK61
  {                                                                                      //V2.0JWK61
      return FALSE;                                                                      //V2.0JWK61
  }                                                                                      //V2.0JWK61
#endif /* EGAVGA */   //V2.0JWK61 need only if egavga

   /*
   ** Allocate return hook handles
   */

  if ((VDMData.hhookInt10SetModeReturn = VDHAllocHook(VDH_RETURN_HOOK,
                                                      (PFNARM)
                                                      VVInt10SetModeReturn,
                                                      0)) == NULL)
  {
    return  FALSE;
  }
#ifdef SVGA             /*            */
  if ((VDMData.hhookRestoreModeReturn = VDHAllocHook(VDH_RETURN_HOOK,
                                                      (PFNARM)
                                                      vvSVGARestoreModeReturn,
                                                      0)) == NULL)
  {
    return  FALSE;
  }

#endif


  if ((VDMData.hhookInt10Return = VDHAllocHook(VDH_RETURN_HOOK,
                                               (PFNARM)VVInt10Return,
                                               sizeof(VVINT10S))) == NULL)
  {                                              /*                         */
    return  FALSE;
  }


  if ((VDMData.hhookInt2FReturn = VDHAllocHook(VDH_RETURN_HOOK,
                                               (PFNARM)VVInt2FReturn,
                                               0)) == NULL)
  {
    return  FALSE;
  }

  VDMData.pInt10ReturnData = VDHQueryHookData(VDMData.hhookInt10Return);
  ((PVVINT10S)(VDMData.pInt10ReturnData))->func_type = 0;/*                 */

  /*
  ** Stash the handle and SGID away immediately
  */

  VDMData.hvdmVideo = hvdm;
  VDMData.sgIDVideo = VDHQuerySysValue(hvdm,
                                       VDHLSV_SESSIONID);

  /*
  ** Initial pointer state is "frozen" **
  */

  VDMData.PtrData.fPtrFrozenVideo++;

  /*
  ** Primary display is by default the active display
  */

#ifdef   MONO
  VDMData.flVDMXVideo |= (VDMX_DEVOWNER|VDMX_DSPOWNER|/*                    */
     VDMX_SAVERESTORE);                          /*                         */

#else /* NOT MONO */
  VDMData.flVDMXVideo |= (VDMX_ACTIVE|VDMX_DEVOWNER|/*                      */
     VDMX_DSPOWNER|VDMX_SAVERESTORE);            /*                         */
#endif /* MONO */

  /*
  ** Initialize map target structures
  */

  for (i = 0; i < npgPhysVRAM; i++)
  {
    VDMData.ulMapCur[i] = VDMData.avdhmt[i].vdhmt_laddr | VDHMT_INVALID; /*            */
    VDMData.avdhmt[i].vdhmt_laddr = (ULONG)pvdmPhysVRAM+i *PAGESIZE;
    VDMData.avdhmt[i].vdhmt_cpg = 1;
    VDMData.avdhmt[i].vdhmt_hmap = 0;
  }
#ifdef PROPERTIES

  /*
  ** Obtain all the correct property settings
  */

  if (VDHQueryProperty(szPropInt10Emulate))
    VDMData.flVDMXVideo |= VDMX_INT10EMULATE;

  if (VDHQueryProperty(szPropRtrcEmulate))
    VDMData.flVDMXVideo |= VDMX_RTRCEMULATE;

  if (!VDHQueryProperty(szPropIOTrap))                          /*            */
    VDMData.flVDMXVideo |= VDMX_NOIOTRAPPING;                   /*            */


  if (VDHQueryProperty(szPropOnDemandAlloc))
    VDMData.flVDMXVideo |= VDMX_ONDEMAND;

  if (VDHQueryProperty(szPropInt2F))
  {
    VDMData.flVDMXVideo |= VDMX_INT2F;
#ifdef SVGA                                                     /*            */                
    /*
    ** On SVGA, INT 2F environments are not saved/restored so, don't bother
    ** doing the ON_DEMAND which causes horrendous allocation (upto 2M on
    ** 1280 resolutions).
    */
    VDMData.flVDMXVideo &= ~VDMX_ONDEMAND;                      /*            */
#endif 
  }
#ifdef   SVGA
  VDMData.VdmSVGA.flBgndExecEnabled =
    flBgndExecSupported                                         /*          */
    && (BOOL)VDHQueryProperty(szDOSBgndExec);
  VDMData.flVDMXVideo |=
     (!flInt10Disabled && !(VDMData.flVDMXVideo & VDMX_INT2F)) ?
      VDMX_INT10RESTORE : 0x0;    /*            */

#endif /* SVGA */
  if (pszTmp = (PSZ)VDHQueryProperty(szVMBoot))

    if (*pszTmp)
      VDMData.flVDMX2Video |= VDMX2_V86MACHINE;         /*            */

  if (pszTmp)
  {                                              /* ssloop                  */
    VDHFreeMem(pszTmp);                          /* ssloop                  */
    pszTmp = NULL;                               /* ssloop                  */
  }                                              /* ssloop                  */
  VDMData.nPeriodicLimit = (VDHQueryProperty(szPropUpdateWindow)*100)/
     TIMER_CHECK;
#endif

  /*
  ** Allocate maximum background storage for VDM
  */

  if (!(VDMData.flVDMXVideo&VDMX_ONDEMAND)
    && !vvGrowBuffer(hvdm, ALL_PLANES, GROW_MAXIMUM, BANK0))  /*           */
    return  FALSE;

  /*
  ** Hook all page faults
  */

  if( !vvSetFaultHooks( TRUE,
                        FALSE ) )
    return  FALSE;

  /*
  ** Hook all I/O ports
  */

  if( !vvSetIOHooks( TRUE,              /* Bgnd */              /*          */
                     TRUE,              /* Install */
                     FALSE ) )          /* NO Wait */
    return  FALSE;

#ifdef SVGA
  /*
  ** Install all I/O handlers.
  ** This will enable IO trapping for all ports except
  ** any write once ports.
  ** If there is no IOTRAPPING in foreground,
  ** the trapping will be disabled on the first trapped port access.
  */
  vvAcceleratorInstallIOHooks( hvdm );            /*          *//*          */
#endif /* SVGA */
  /*
  ** Hook video software interrupt
  */

  if (!VDHInstallIntHook(CURRENT_VDM,
                         BIOSINT_VIDEO,
                         VVInt10Hook,
                         VDH_ASM_HOOK))
    return  FALSE;

  VDMData.flVDMVideo |= VDM_BGNDREADY;

#ifdef   PROPERTIES

  /*
  ** Get the current RMSIZE, and convert to bytes
  */

  pvdmEBIOS = NULL;
  nbTotalSize = nbRMSize = BYTESFROMKB(VDHQuerySysValue(CURRENT_VDM,
                                                        VDHLSV_RMSIZE));

  if (VDHQuerySysValue(CURRENT_VDM,
                       VDHGSV_MACHINETYPE) == MACHINE_TYPE_PS2)
  {
    pvdmEBIOS = (PBVDM)nbRMSize;
  }

  /*
  ** RMSize is returned as (A0000 - EBIOSDATA_LEN) for both MCA and
  ** ISA. Yet ISA doesn't have EBIOS area!  This fixes the "MODE RESTRICTION"
  ** lack of extra memory, but it would seem that this next line should
  ** be placed back in the PS2 conditional, QuerySysValue should return
  ** A0000 for ISA RM_SIZE.                                       
  */

  /*
  **            - Only add the 1K memory adjustment if the RMSize equals
  ** 639K.  OEM machines often return 640K and do need to be set to 641K.
  */

  if (nbTotalSize == EGAVGAMEM_START-EBIOSDATA_LEN)       /*            */
  {
    nbTotalSize += EBIOSDATA_LEN;                         /*            */
  }

  /*
  ** If VDM size at max, then CGA/MONO restriction makes sense
  */

  if (nbTotalSize >= EGAVGAMEM_START)                   /*            */
  {

    if (pszTmp = (PSZ)VDHQueryProperty(szPropModeRestrict))
    {

   #ifndef  CGA

      if (!strcmp(pszTmp+1,
                  szPropMONORestrict+1))
      {
        VDMData.flVDMXVideo |= VDMX_MONORESTRICT;
        VDMData.npgBonusBuffer = PAGESFROMBYTES(MONOMEM_START-EGAVGAMEM_START);
      }

      else
   #endif

        if (!strcmp(pszTmp,
                    szPropCGARestrict))
        {
          VDMData.flVDMXVideo |= VDMX_CGARESTRICT;
          VDMData.npgBonusBuffer = PAGESFROMBYTES(CGAMEM_START-EGAVGAMEM_START);

   #ifdef   VGA
          VDMBase.rb_bVMode = BIOSVMODE_CO80;
          VDMBase.rb_fsEquip &= ~BIOSEQUIP_VIDEOMASK;
          VDMBase.rb_fsEquip |= BIOSEQUIP_COLOR80VIDEO;
   #endif
        }
      VDHFreeMem(pszTmp);                        /* ssloop                  */
    }

    /*
    ** If CGA/MONO restriction was specified...
    */

    if (VDMData.npgBonusBuffer)
    {
#ifdef SVGA
       VDMData.flVDMXVideo &= ~VDMX_INT10RESTORE;               /*            */
#endif
      /*
      ** Allocate memory to fill in the reserved video region
      */

      VDMData.pBonusBuffer = VDHAllocPages(NULL,
                                           VDMData.npgBonusBuffer,
                                           VDHAP_SWAPPABLE);

      if (!VDMData.pBonusBuffer)
        return  FALSE;

      nbRMSize += VDMData.npgBonusBuffer *PAGESIZE;

      /*
      ** Copy EBIOS data from the page VBIOS allocated to the last
      ** page in our buffer
      */


      if (pvdmEBIOS)
      {
        VDHCopyMem((PVOID)(pvdmEBIOS),
                   (PVOID)(VDMData.pBonusBuffer+VDMData.npgBonusBuffer
                      *PAGESIZE-EBIOSDATA_LEN),
                   EBIOSDATA_LEN);

        /*
        ** Fix up the ROM BIOS pointer to new EBIOS data area
        */

        VDMBase.rb_awLPT[3] = HISEG(nbRMSize);
      }

      /*
      ** Allocate memory for a stack we can switch to on SetMode
      */

      if (VDMData.flVDMX2Video&VDMX2_V86MACHINE)        /*            */
      {
        VDMData.pvdmAltStack = (PBVDM)nbRMSize;
        nbRMSize -= KBFROMBYTES(MAX_ALTSTACK)*KSIZE;
      }

      else
      {
        VDMData.pvdmAltStack = VDHAllocDosMem(MAX_ALTSTACK);

        if (!VDMData.pvdmAltStack)
          return  FALSE;

        VDMData.pvdmAltStack += MAX_ALTSTACK;
      }

      /*
      ** Update all the memory size fields
      */

      VDMBase.rb_wMemSize = (USHORT)KBFROMBYTES(nbRMSize);
      VDHPutSysValue(VDHLSV_RMSIZE,
                     VDMBase.rb_wMemSize);

      /*
      ** Lastly, because our fault hooks will not be installed
      ** in time to catch any kernel faults, we must map the memory.
      ** Remember: INVALID means invalid video page but VALID DOS page.
      */

      for (i = 0; i < VDMData.npgBonusBuffer; i++)
        vvMapPage((PBVDM)(EGAVGAMEM_START+i *PAGESIZE),
                  NULL,
                  ALL_PLANES,
                  BANK0,                                        /*            */
                  MAX_VGA_BANK,                                 /*            */
                  VDHMT_INVALID);
    }
  }
#endif                                           /* PROPERTIES              */

  /*
  ** Add this VDM's list-entry to the active VDM list
  */

  RequestMutexSem(hmxWindowedEvent);
  ADDENTRY( hvdm,                       /* uses lseHeadActive */
            Active );
  ReleaseMutexSem(hmxWindowedEvent);

  /*
  ** Provide some fake instance data until the VDM's mode is set
  */

#ifdef   MONO
  VDMData.regMode = BIOSVMODE_MONO80;
#endif

#ifdef   CGA
  VDMData.regMode = VDMBase.rb_bVModeByte;
#endif

  /*
  ** Preset the Compaq mode control register shadow to allow correct output
  ** when coming full-screen from an initial windowed or iconized state.
   */

#ifdef   EGA                                     /*                         */
  VDMData.regCompaqCtrl = 1;                     /* Compaq Control Mode register*/
#endif /* EGA */                                 /*                         */

#ifdef   EGAVGA

  if (!(VDMBase.rb_bVInfo&BIOSVINFO_EGAMONO))
    VDMData.regMiscOut |= MISCOUT_COLRPORTS;     /* FLAG: - not good enough */
  VDMData.aregSEQData [REG_SEQRESET] = SEQRESET_ASYNC | SEQRESET_SYNC;
  VDMData.stateATC = ATC_INDEX;                  /* Init ATC to INDEX state
                                                                            */
#endif /* EGAVGA */

#ifdef   VGA
  for (i = 0; i < MAX_SEQREGS; i++)
    VDMData.aregSEQData[i] = aregSEQInit[i];

  for (i = 0; i < MAX_GDCREGS; i++)                             /*          */
    VDMData.aregGDCData[i] = aregGDCInit[i];                    /*          */

  for (i = 0; i < MAX_CRTREGS; i++)                             /*          */
    VDMData.aregCRTData[i] = aregCRTInit[i];                    /*          */

  /* Although some VGAs can read these ports, some cannot.    *//*          */
  /* So this port is best treated as write only internally.   *//*          */
  /* And so we must also provide an initial value, in case    *//*          */
  /* INT10SetMode and PMI Cleanup do not provide any.         *//*          */
  /* Enable video subsystems but not setup mode.              *//*          */
  VDMData.regVSE = 0x09;                                        /*          */
  VDMData.regVSEAlternate = 0x09;                               /*          */
  VDMData.regVVReserved = 0x82;         /* Defaults enabled   *//*          */
#endif /* VGA */

#ifdef   SVGA
                                                        /*            start */
  /* Moved */                                                   /*          */
  for (i = ATI_START_EXTREGS; i < ATI_END_EXTREGS; i++)
    VDMData.VdmSVGA.aregATIData[i] = aregATIInit[i-ATI_START_EXTREGS];

  /* JWK01 start (may not need) */
  for (i = TSENG_CRTCB_START; i <= TSENG_CRTCB_END; i++)
    VDMData.VdmSVGA.VdmTSENG.aregCRTCBData[i] = aregCRTCBInit[i];
  /* JWK01 end (may not need) */

  /*
  ** If VDM is started in the bgnd in a way that VRAMISTOAST flag is
  ** reset before the first foreground for the VDM happens, the
  ** desktop will not be repainted although we are not capable of
  ** restoring its VRAM state. To circumvent this, on our first
  ** foreground, we make sure that VRAM is toasted. Hence, this flag
  ** needs to be set on VDM creation.
  */
  VDMData.flVDMX2Video |= VDMX2_FIRSTFGND;                      /*          */

  /* Note that this is done in the BACKGROUND to shadow only! *//*          */
  vvInt10SetModePrepare( hvdm );                                /*          */

                                            /*            end *//*          */
  /* enable VGA addressing. */
  VDMData.VdmSVGA.aregXGAData [AXGA_OPERATING_MODE] = 1;
#endif /* SVGA */

  /*
  ** Initialize per-VDM GRFXALLOWED bit to global state.
  ** (currently, there is no mechanism to change the
  ** per-VDM state, but we may add one eventually)
  */

  if (flVVD&VVD_GRFXALLOWED)
    VDMData.flVDMVideo |= VDM_GRFXALLOWED;

#ifdef   EGAVGA                                  /*                         */

  /*
  ** Setup codepage buffer from the VDM space.                            
  */

  if ((VDMData.vvMode.vvm_cpID =                 /*                         */
  VDHQuerySysValue(CURRENT_VDM,
                   VDHLSV_CODEPAGEID)) != 0)
  {                                              /*                         */
    VDMData.pCPBuff = VDHAllocDosMem(PAGESIZE);  /*                         */
 /*                                                                         
  * VDMData.ROMint1fSeg = SEGMENTOF16(VDMBase.rb_avpIVT[BIOSINT_VIDEOGRAPH]);
  */
  }                                              /*                         */
#endif /* EGAVGA */                              /*                         */

    /*
    ** Establish communication with virtual mouse driver
    */

    if (!hvddMouse)
    {
      hvddMouse = VDHOpenVDD(VMD_NAME);

      if (hvddMouse)

        if (!VDHRequestVDD(hvddMouse,
                           hvdm,
                           VMDEVREQ_REGISTER,
                           &vmreg,
                           &vmfunc))
          hvddMouse = FALSE;
    }
  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME = VVCreateDone()
 *
 * DESCRIPTION   = VDM creation done notification
 *
 *                 This registered subroutine is called each time a new VDM
 *                 successfully complete all parts of VDM creation (see
 *                 VDHInstallUserHook for complete semantics).
 *
 *                 This routine is neccessary because during creation of a
 *                 VDM, an error can occur anywhere within the Create VDM
 *                 path causing confusion over whether the VDM is currently
 *                 foreground.  To insure we can maintain a VDM completion
 *                 state, a per VDM flag will be used to indicate that the
 *                 VDM had successfully complete creation.
 *
 * INPUT         = hvdm -> new VDM
 *
 * OUTPUT        = don't care
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *                 set a per VDM flag bit to indicate
 *                   VDM creation complete
 *
 **************************************************************************/

VOID EXPENTRY VVCreateDone(HVDM hvdm)            /*                         */
{                                                /*                         */
  VDMData.flVDMXVideo |= VDMX_CREATEDONE;        /*                         */
}                                                /*                         */

/***************************************************************************
 *
 * FUNCTION NAME = VVSetFgnd()
 *
 * DESCRIPTION   = VDM foreground notification
 *
 *                 This registered subroutine is called each time a VDM is
 *                 switched to foreground.  It adjusts the level of
 *                 virtualization so that I/O commands are directed to the
 *                 hardware instead of being virtualized (see
 *                 VDHInstallUserHook for complete semantics).
 *
 * INPUT         = hvdm -> new foreground VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *                 if no ownership
 *                   return
 *                 update all state information
 *                 set foreground mode
 *                 disable video signal
 *                 update physical video memory with virtual
 *                 if mouse pointer enabled
 *                   draw pointer
 *                 update physical registers with virtual state
 *                 enable video signal
 *
 *                 thaw VDM if previously frozen
 *                   due to unsupported background access
 *                 arm context hook to grow buffer/enable pages
 *
 *
 **************************************************************************/

VOID EXPENTRY VVSetFgnd(register HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  INT i;                                         /*                         */
#ifdef SVGA                                     /*            */
  ULONG fRestore;
#endif
  /*
  ** If we own the device and the VDM is not already foreground
  */

  if (pvd->flVDMXVideo&VDMX_DEVOWNER && !(pvd->flVDMVideo&VDM_FGND))
  {
    RequestMutexSem(pvd->hmxVideoState);
    VDHFreezeVDM(hvdm);

#ifdef   VGA                                     /*                         */

    if (!(pvd->flVDMXVideo&VDMX_SAVERESTORE))    //           moved this up
    {                                            /*                         */
      pvd->flVDMVideo |= VDM_FGND;               /*                         */

      /*
      ** Send INT 2F if required                                            
      */

      if (!vdhBTS(&pvd->flVDMVideo,
                  LOG2(VDM_FGNDHOOK)))           /*                         */
        VDHArmContextHook(pvd->hhookFgndContext,
                          hvdm);                 /*                         */
    } /* pvd->flVDMXVideo & VDMX_SAVERESTORE */  /*                         */
    else
    {
#endif                                           /*                         */
#ifdef SVGA
    if (!(pvd->flVDMXVideo&VDMX_INT2F))          /*            */
#endif                                           /*            */
      if (!(pvd->flVDMXVideo&VDMX_ONDEMAND) && !vvGrowBuffer(hvdm,
                                                             ALL_PLANES,
                                                             GROW_MAXIMUM,
                                                             BANK0))
      {                                          /*                         */
        vvAddEvent(hvdm,
                   VVDEVENT_SWITCHERROR,
                   NULL,
                   0);
        flVVD |= VVD_VRAMISTOAST;           /* tell PM to repaint           */
        goto error;
      }
#ifndef SVGA                    //           pulling together all non-SVGA vs SVGA only
#ifdef   EGAVGA

      /*
      ** Since we're foreground, we own the controller by default
      */

      hvdmController = hvdm;
#endif /* EGAVGA */

      /*
      ** Update our assumptions about the state of the VDM
      */

      vvUpdateAll( hvdm, TRUE );
      pvd->flVDMVideo |= VDM_FGND;

      /*
      ** Turn the screen off while we're updating things;
      ** in the MONO (secondary display) case, there's no need to if
      ** the display hasn't been initialized yet .
      */

#ifdef   MONO
      /*                                                                73042
      ** Enable the display                                             73042
      */                                                             /* 73042 */

      vvEnableDisplay(hvdm);                                         /* 73042 */

      if (pvd->mstateVideo)
#endif /* MONO */

#ifdef   VGA                                     /*                         */

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

      vvRestoreLatches(hvdm,
                    FALSE);

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

      vvRestoreIOState(hvdm);
#endif /* VGA */
      vvDisableDisplay(hvdm);

      /*
      ** Update physical video memory with virtual memory
      */

      if (!vvTransferBuffer(hvdm,
                            MAX_VGA_BANK,                       /*            */
                            TRUE))
      {
        vvAddEvent(hvdm,
                   VVDEVENT_SWITCHERROR,
                   NULL,
                   0);
        flVVD |= VVD_VRAMISTOAST;          /* tell PM to repaint            */
        goto error;
      }
#ifdef   EGAVGA

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

      vvRestoreLatches(hvdm,
                       FALSE);
#endif /* EGAVGA */

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

      vvRestoreIOState(hvdm);
      pvd->PtrData.fPtrFrozenVideo--;
      AssertTRUE(pvd->PtrData.fPtrFrozenVideo >= 0);

      /*
      ** 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;
      }

      /*
      ** Enable the screen if there's something to look at yet
      */

      if (pvd->mstateVideo)
        vvEnableDisplay(hvdm);

      /*
      ** Make an appointment to set up VDM's VRAM mappings, etc
      */

      if (!vdhBTS(&pvd->flVDMVideo,
                  LOG2(VDM_FGNDHOOK)))
        VDHArmContextHook(pvd->hhookFgndContext,
                          hvdm);
#else           //           start of SVGA only
      /*
      ** State of the VDM is restored in the following fashion:
      ** if 2F is enabled, int 2F is injected and the switch held until 2f returns.
      ** No additional state is restored.
      ** if 2F is not enabled, but int10restore is enabled, the last int 10 is injected and
      ** the switch held until int 10 returns. The state of vdm is then restore on top of it.
      ** if neither is enabled, the state of vdm is restored right here.
      ** VDMX2_INTRESTOREFGND means either INT 2F or INT 10 is used to restore.
      */

      if (!(pvd->flVDMXVideo & VDMX_INT2F))             /*            */
        vvUpdateAll( hvdm, TRUE );
      pvd->flVDMVideo |= VDM_FGND;
      vvDisableDisplay(hvdm);

      /*
      ** If VDM is started in the bgnd in a way that VRAMISTOAST flag is
      ** reset before the first foreground for the VDM happens, the
      ** desktop will not be repainted after our next Bgnd switch,
      ** although we are not capable of restoring its VRAM state.
      ** To circumvent this, on our first foreground, we make sure
      ** that VRAM is toasted.
      */

      if(pvd->flVDMX2Video & VDMX2_FIRSTFGND)              /*            */
      {
          flVVD |= VVD_VRAMISTOAST;      /* tell PM to repaint */
          pvd->flVDMX2Video &= ~VDMX2_FIRSTFGND;
      }
      /*
      ** Note on the restore policy:
      ** 1) VDM doesn't have init state: do first pass restore here.
      ** 2) VDM has an init state but is int10 or int 2f enabled:
      **    do full pass only if switched while changing the mode.
      **    Otherwise, no restore is done here, but in the context
      ** 3) VDM is not int10 or int2f enabled:
      **    do full pass restore here.
      */
      fRestore = SVGA_RESTORE_FULL_PASS;

      if (!(pvd->flVDMVideo & VDM_IOINIT))
         fRestore = SVGA_RESTORE_FIRST_PASS;
      /*
      ** Make an appointment to set up VDM's VRAM mappings, etc
      ** 2F and non-int10/2F use vvFgndContext
      ** int10 used vvSVGAFgndRestoreModeContext if the VDM has been initialized
      ** and is not currently in a mode change.
      */
      if (!vdhBTS(&pvd->flVDMVideo,
                  LOG2(VDM_FGNDHOOK)))
      {
        if ((pvd->flVDMXVideo & VDMX_INT10RESTORE) &&
            ((pvd->flVDMVideo & (VDM_IOINIT|VDM_MODECHANGING)) == VDM_IOINIT))
           VDHArmContextHook(pvd->hhookFgndRestoreContext,
                          hvdm);
        else
        {
           VDHArmContextHook(pvd->hhookFgndContext,
                          hvdm);
        }
      }
      pvd->PtrData.fPtrFrozenVideo--;
      AssertTRUE(pvd->PtrData.fPtrFrozenVideo >= 0);

      /*
      ** Release the accelerator, mark it unblocked.
      */
      vvAcceleratorUnlockIO( hvdm );                            /*          */
      /*
      ** If 2F registered or INT10 is used to restore
      ** and this is not creation, delay the
      ** return from the SetFgnd until INT 2F or INT 10 is finished.
      ** This is to ensure proper order of the
      ** notifications and to avoid nesting. WINOS2 doesn't handle
      ** nesting or out of order notifications very well.
      */
      if (((pvd->flVDMXVideo & VDMX_INT2F) && (pvd->flVDMVideo & VDM_IOINIT)) ||                    /*            */
          ((pvd->flVDMXVideo & VDMX_INT10RESTORE) &&
          ((pvd->flVDMVideo & (VDM_IOINIT|VDM_MODECHANGING)) == VDM_IOINIT)))
      {
        pvd->flVDMVideo &= ~VDM_FROZEN;
        ReleaseMutexSem(pvd->hmxVideoState);
        /*
        ** Make sure we thaw the instance completely.
        */
        ResetEventSem(pvd->hevFreezeThaw);
        while (VDHIsVDMFrozen(hvdm))
          VDHThawVDM(hvdm);

        /*
        ** Make sure VDM is not blocked as idle.
        ** Block on the delay switch semaphore until either timeout occurs or
        ** 2F successfuly returns.
        */
        VDHWakeIdle(hvdm);
        VDHResetEventSem(pvd->VdmSVGA.hevDelaySwitch);
        /*                                                          
        ** It is possible that the VDM is blocked in such a way that it
        ** will not be given context until the switch thread returns. For
        ** example, during a "dir a:" pop-up, the VDM is blocked in the file
        ** system and will not be released until the harderror has returned,
        ** which involves a foreground switch. Since we have no way of
        ** detecting that VDM will not run, we set the time-out as low as
        ** possible. Making it too low for background 2F notifications is
        ** dangerous, since 2F has to be guaranteed the ownership of the
        ** device until it returns. Therefore we work with two different timeouts.
        */
        VDHWaitEventSem( pvd->VdmSVGA.hevDelaySwitch,
                            MAX_VDM_INT10_WAIT );
        VDHThawVDM(hvdm);
        return;
      }
      else
        vvSVGARestoreFgnd(hvdm,fRestore);     //done only if no context was used for restore.

      /*
      ** Enable the screen if there's something to look at yet
      */

      if(pvd->mstateVideo)
        vvEnableDisplay(hvdm);
#endif                  /*            */

// @@@@@
#ifdef VGA
      /*
      ** We undid the screen-switch freeze, but there may be others
      */
      vvThawVDM(hvdm);
    }
#endif                  /* VGA   */

error:
    VDHThawVDM(hvdm);
    ReleaseMutexSem(pvd->hmxVideoState);
  }
}
/***************************************************************************
 *
 * FUNCTION NAME = VVSetBgnd()
 *
 * DESCRIPTION   = VDM background notification
 *
 *                 This registered subroutine is called each time a VDM is
 *                 switched to background.  It adjusts the level of
 *                 virtualization so that I/O commands are virtualized
 *                 instead of being allowed to go to the hardware (see
 *                 VDHInstallUserHook for complete semantics).
 *
 *                 Note that we also leave the video signal OFF after we are
 *                 done exchanging VRAM contents.  This is because, although
 *                 VRAM for the previous session is now restored, we do not
 *                 know what the I/O state for that session was.
 *                 Furthermore, that session may not be the one returning to
 *                 the foreground anyway.  Hence, it is best to leave the
 *                 screen disabled.
 *
 * INPUT         = hvdm -> new background VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *                 if no ownership
 *                   return
 *                 update all virtual regs from physical state
 *                 disable video signal
 *
 *                 if mouse pointer enabled
 *                   remove pointer
 *                 save physical video memory to virtual
 *                 set background mode
 *                 thaw VDM if previously frozen
 *                   due to error to growing background buffer
 *                 arm context hook to shrink background buffer
 *
 **************************************************************************/

VOID EXPENTRY VVSetBgnd(register HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  INT i;                                                        /*          */
  BYTE bOperMode;                                               /*          */
  BOOL flFrozenOnEntry;                                         /*          */

#ifdef   SVGA
  INT iBankNo,iBankEnd;
  BOOL flWindow = FALSE;                                        /*          */
  BOOL bPrevUnlock;                                             /*          */
#endif

  /*
  ** If we own the device and the VDM is in the
  ** foreground *or* does not have a valid video state yet.
  */

  if( pvd->flVDMXVideo & VDMX_DEVOWNER
      && (pvd->flVDMVideo & VDM_FGND
          || !pvd->mstateVideo) )
  {
    RequestMutexSem(pvd->hmxVideoState);
    /*
    ** Query the frozen state in order to restore it.
    */
    flFrozenOnEntry = VDHIsVDMFrozen( hvdm );     /*          *//*          */
    /* Must freeze other thread to have clear access to regs */ /*          */
    /* Otherwise lock/unlock/index to busy may not work right *//*          */
    if( !flFrozenOnEntry )                        /*          *//*          */
      VDHFreezeVDM( hvdm );
#ifdef SVGA
    if( (pvd->flVDMVideo & VDM_FGND)                            /*          */
        && (pvd->flVDMXVideo & VDMX_SAVERESTORE) )              /*          */
      /*
      ** Make sure that engine has completed all pending commands           
      ** before permanently freezing.
      */
      vvAcceleratorWaitOnEngine( hvdm, flFrozenOnEntry );       /*          */
#endif /* SVGA */

#ifdef VGA                                                      /*          */
    if (pvd->flVDMXVideo&VDMX_SAVERESTORE)
    {                                                           /*          */
#endif /* VGA */                                                /*          */

      /*
      ** If there's a foreground state to save, save it
      */
      if( pvd->flVDMVideo & VDM_FGND )
      {

#ifdef SVGA
      /* vvUnLockSVGARegisters( hvdm ); */                      /*          */
      bPrevUnlock = vvSVGALockPushState( hvdm );                /*          */
      /*
      **            If 2F processing enabled, don't save/restore the
      ** adapter's video state.
      */
      if (!(pvd->flVDMXVideo & VDMX_INT2F))
      {
#endif /* SVGA */

        /*
        ** Update our assumptions about the state of the VDM
        */
        vvUpdateAll( hvdm, TRUE );
        /*
        ** Turn the screen off while we're updating things
        */
        vvDisableDisplay(hvdm);
        /*
        ** Freeze the pointer
        */
        pvd->PtrData.fPtrFrozenVideo++;
        /*
        ** Take pointer off the screen, if one exists
        */
        if (pvd->PtrData.flPtrVideo&PTR_ACTIVE)
          vvPtrErase(hvdm);

#ifdef   EGAVGA

#ifdef VGA
#ifdef SVGA                                                     /*          */
        if( !(pvd->flVDMVideo & VDM_WINDOWED)
            && ((pvd->mstateVideo == MEMORY_GRFX)               /*          */
                || (pvd->mstateVideo == MEMORY_GRFX256)) )      /*          */
        {
          vvSVGAMaxBanks( hvdm );      /*          *//*          */
          iBankEnd = (USHORT) pvd->VdmSVGA.usMaxBanks;          /*            */
        }
        else
          iBankEnd = MAX_VGA_BANK;                           /*          *//*          */
#endif /* SVGA */
        vvVGAEnableBankAddr( hvdm );                            /*          */
#endif /* VGA */

        /*
        ** Save the physical latches, now that I/O state can be changed
        */
        vvSaveLatches(hvdm,
                      FALSE);
#endif /* EGAVGA */

#ifdef   SVGA
        /*
        ** 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,FALSE,iBankEnd);           /*          */

        if (pvd->flVDMXVideo & VDMX_ENHANCEDMODE)               /*          */
            vvTransferLinearBuffer(hvdm, iBankEnd, FALSE);      /*          */
        else
            vvTransferBuffer(hvdm, iBankEnd, FALSE);            /*            */

        (*psCurAdapterInfo->pfnSVGASetBank)                     /*          */
          ( hvdm,
            pvd->VdmSVGA.usCurrentBank,                         /*            */
            TRUE );
#else /* NOT SVGA */
        /*
        ** Update virtual video memory with physical memory
        */
        vvTransferBuffer(hvdm,
                         MAX_VGA_BANK,          /*            */
                         FALSE);
#endif /* SVGA */

#ifdef   EGAVGA

#ifdef   VGA                                     /*                         */
          if (pvd->mstateVideo <= MEMORY_TEXT)   /*                         */
            vvRestoreIOState(hvdm);              /*                         */
          if (flDualDisplayConf)                   /*            */
            vvEnableDisplay(hvdm);                 /*             */
   #endif                                        /*                         */
#endif /* VGA */

#ifdef SVGA
        } /* !(pvd->flVDMXVideo & VDMX_INT2F) */ /*                         */
        else                                     /* INT 2F enabled */
        {                                        /*            start */
           /*
           ** Freeze the pointer
           */

           pvd->PtrData.fPtrFrozenVideo++;

           /*
           ** Take pointer off the screen, if one exists
           */

           if (pvd->PtrData.flPtrVideo&PTR_ACTIVE)
             vvPtrErase(hvdm);                   /*            end */

           vvDisableDisplay(hvdm);
           flVVD |= VVD_VRAMISTOAST;             /* tell PM to repaint           */
        } /* endif( !(pvd->flVDMXVideo & VDMX_INT2F) ) */
#endif /* SVGA */

#ifdef   EGAVGA
        if (hvdmController == hvdm)
          vvFreeController(hvdm);                /*                         */
#endif

        /*
        ** Reenable display if the VDM failed to complete create
        */

        if (!(pvd->flVDMXVideo&VDMX_CREATEDONE))
        {                                        /*                         */

#ifdef   EGAVGA                                  /*                         */
           pvd->regATCIndx = ATCPAL_ENABLE;      /*                         */
#endif                                           /*                         */
           vvEnableDisplay(hvdm);                /*                         */
        }                                        /*                         */

#ifdef VGA
        vvDisableVRAM(hvdm);
#endif

        pvd->flVDMVideo &= ~VDM_FGND;
#ifdef SVGA
        /* Since we are NOT in the foreground any more: */      /*          */
        /* Current hardware state belongs to someone else! */   /*          */
        /* We are popping BANKGROUND shadow lock info here! */  /*          */
        vvSVGALockPopState( hvdm, bPrevUnlock );                /*          */
#endif
      } /*  pvd->flVDMVideo & VDM_FGND */
#ifdef SVGA
      else                                       /* It was not foreground */
        flWindow = TRUE;                         /*            */
#endif

      /*
      ** For dying VDMs, this is all we need to do (saves time)
      */

      if (!(pvd->flVDMVideo & VDM_DYING))        /*                         */
      {

        /*
        ** Make an appointment to set up VDM's VRAM mappings, etc
        */

        if (!vdhBTS(&pvd->flVDMVideo,
                    LOG2(VDM_BGNDHOOK)))
        {
          VDHWakeIdle(hvdm);                              /*            */
          VDHArmContextHook(pvd->hhookBgndContext,
                            hvdm);
        }

        /*
        ** Note that if the VDM is in MEMORY_GRFX mode, then we should
        ** leave it frozen, and let either (1) PM thaw it when PM switches
        ** foreground, or (2) let our own SetFgnd thaw him later.
        */

        if (pvd->mstateVideo == MEMORY_GRFX && pvd->flVDMXVideo&VDMX_DSPOWNER)
          vvFreezeVDM(hvdm,
                      FALSE);

#ifdef  SVGA
        /*
        ** Depending on the INT 2F, take action.
        */
        if (pvd->flVDMVideo & VDM_IOINIT)                       /*          */
          vvSVGASetBgnd(hvdm);                                  /*          */
        /*
        ** Don't allow any enhanced access in the background.
        */
        vvAcceleratorLockIO( hvdm );              /*          *//*          */
#endif /* SVGA */
      } /* !(pvd->flVDMVideo & VDM_DYING) */
#ifdef SVGA
      /*
      ** Cleanup is executed only for full screen VDM's.
      */
      if (!flWindow)
        vvSVGAFixSetBgnd(hvdm);                  /*                         */
#endif
#ifdef   VGA                                     /*                         */
    } /* pvd->flVDMXVideo & VDMX_SAVERESTORE */

    else                                         /* nothing to save restore */
    {                                                           /*          */
      pvd->flVDMVideo &= ~VDM_FGND;                             /*          */
      /*** Send INT 2F if required ***/                         /*          */

      if (!vdhBTS(&pvd->flVDMVideo,
                  LOG2(VDM_BGNDHOOK)))                          /*          */
        VDHArmContextHook(pvd->hhookBgndContext,
                          hvdm);                                /*          */
    }  /* pvd->flVDMXVideo & VDMX_SAVERESTORE */                /*          */
#endif                                                          /*          */

    if (!flFrozenOnEntry)                                       /*          */
      VDHThawVDM(hvdm);                                         /*          */
    ReleaseMutexSem(pvd->hmxVideoState);
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VVChangeCodePage()
 *
 * DESCRIPTION   = VDM codepage change notification
 *
 *                 This registered subroutine is called each time a VDM
 *                 changes codepages.  It is always called in the context of
 *                 the VDM that changed.
 *
 * INPUT         = cpID == codepage ID
 *
 * OUTPUT        = TRUE if codepage supported, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

BOOL EXPENTRY VVChangeCodePage(
  ULONG cpID )
{

#ifdef   EGAVGA
  if( !vvLoadCodePageFont() )
    return( FALSE );
#endif

  VDMData.vvMode.vvm_cpID = cpID;
  vvUpdateModeData( CURRENT_VDM );
  return( TRUE );
}

/***************************************************************************
 *
 * FUNCTION NAME = VVChangeTitle()
 *
 * DESCRIPTION   = VDM title change notification
 *
 *                 This registered subroutine is called each time a VDM
 *                 changes its title.  It is always called in the context of
 *                 the VDM that changed.
 *
 * INPUT         = pszTitle -> new title (NULL if back to default)
 *
 * OUTPUT        = TRUE (always indicate success)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

BOOL EXPENTRY VVChangeTitle(PSZ pszTitle)
{
  vvAddEvent(CURRENT_VDM,
             VVDEVENT_TITLECHANGE,
             pszTitle,
             0);
  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME = VVDestroy()
 *
 * DESCRIPTION   = VDM termination notification
 *
 *                 This registered subroutine is called each time an
 *                 existing VDM is destroyed (see VDHInstallUserHook for
 *                 complete semantics).
 *
 *                 The only work we need to perform at this time is freeing
 *                 the virtual memory buffer(s).  We'll let the process
 *                 termination code throw away semaphore info, and any other
 *                 per-task data.
 *
 * INPUT         = hvdm -> dying VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID EXPENTRY VVDestroy(HVDM hvdm)
{
  VDHSEMSTATE vss;                               /*                         */

  RequestMutexSem(hmxWindowedEvent);

  /*
  ** If this VDM died windowed or with focus, clean up
  */

  if ((VDMData.flVDMVideo&VDM_WINDOWED) &&       /*                         */
     (!(VDMData.flVDMXVideo&VDMX_SEAMLESS)))     /*                         */
  {                                              /*                         */
    /*
    ** If the dying windowed VDM has the VGA Controller, remove it.
    ** So we don't mistakenly touch its VDM data after the VDM is gone
    */
   #ifdef EGAVGA
    if (hvdm == hvdmController)                  /*                         */
        vvFreeController(hvdm);                  /*                         */
   #endif
    nWindowedVDMs--;
  }                                              /*                         */

  if (hvdm == hvdmFocus)
    hvdmFocus = NULL;

  if (hvdm == hvdmUpdate)
    hvdmUpdate = NULL;

  if( VDMData.flVDMVideo & VDM_PMWINDOWED )
    nPMWindowedVDMs--;

  if( VDMData.flVDMVideo & VDM_MINIMIZED )
    nMinWindowedVDMs--;

  while (VDMData.flEventsPending)
  {
    VDMData.flEventsPending &= ~(1 << vdhBSF(VDMData.flEventsPending));
    nWindowedEvents--;
  }

  /*
  ** Make sure VDM's list-entries are removed from all lists
  */

  REMOVEENTRY( hvdm,                    /* uses lseHeadActive */
               Active );
  /*
  ** Mark the VDM as dying before the windowed semaphore is released, as
  ** to prevent updates after the pages have been released. Defect 98511.           
  */
  VDMData.flVDMVideo |= VDM_DYING;
  ReleaseMutexSem(hmxWindowedEvent);

#ifdef   EGAVGA
  vvFreeAllPhysPages(hvdm,
                     TRUE);

/*  if (hvdm == hvdmController)                                             */
/*      hvdmController = NULL;                                              */

#endif

  /*
  ** Reset VRAMISTOAST bit after destruction of a foreground              
  */

  /*
  ** XGA application                                                      
  */

  if ((VDMData.flVDMVideo&VDM_FGND) && (flVVD&VVD_REPAINT))
  {
    flVVD &= ~VVD_REPAINT;
  }                                              /* endif                   */

  /*
  ** Even for dying fgnd VDMs, we should restore previous VRAM
  */

//            VDMData.flVDMVideo |= VDM_DYING;
  VVSetBgnd(hvdm);

  /*
  ** Free buffer
  */

  vvShrinkBuffer(CURRENT_VDM,
                 TRUE);

  /*
  ** Note: no concept of per-VDM semaphores; must free ourselves
  */

  if (VDMData.hmxVideoState)
  {
    VDHQuerySem(VDMData.hmxVideoState,
                SSToDS(&vss));                   /*                         */

    if (vss.vss_fOwned)
    {                                            /*                         */
      RequestMutexSem(VDMData.hmxVideoState);    /*                         */
      ReleaseMutexSem(VDMData.hmxVideoState);    /*                         */
    }
    DestroyMutexSem(VDMData.hmxVideoState);
  }

  if (VDMData.hmxWindowedState)
    DestroyMutexSem(VDMData.hmxWindowedState);

  if (VDMData.hevFreezeThaw)
    DestroyEventSem(VDMData.hevFreezeThaw);

#ifdef  SVGA
  if (VDMData.VdmSVGA.hevDelaySwitch)
    DestroyEventSem(VDMData.VdmSVGA.hevDelaySwitch);       /*          */
  vvAcceleratorDestroy( hvdm );                                 /*          */
#endif /* SVGA */

  if (VDMData.hevShieldSynced)
    DestroyEventSem(VDMData.hevShieldSynced);
}

#ifdef   PROPERTIES

/***************************************************************************
 *
 * FUNCTION NAME = VVSetInt10Emulation
 *
 * DESCRIPTION   = Set per-VDM INT 10h emulation flag
 *
 *                 This routine is called when the user alters an existing
 *                 VDM's INT 10h emulation "advanced property" setting.
 *
 * INPUT         = op - operation to perform (set)
 *                 hvdm - target VDM
 *                 cb - length of value
 *                 psz - ptr to BOOL value
 *
 * OUTPUT        = returns 0 (no error)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

ULONG EXPENTRY VVSetInt10Emulation(ULONG op,HVDM hvdm,ULONG cb,PSZ psz)
{
  AssertTRUE(op == VDHPROP_SET);
  SETBIT(pVDMData(hvdm)->flVDMXVideo,
         VDMX_INT10EMULATE,
         (BOOL)psz);
  return 0;
}

/***************************************************************************
 *
 * FUNCTION NAME = VVSetRetraceEmulation
 *
 * DESCRIPTION   = Set per-VDM retrace emulation flag
 *
 *                 This routine is called when the user alters an existing
 *                 VDM's horz/vert retrace emulation "advanced property"
 *                 setting.
 *
 * INPUT         = op - operation to perform (set)
 *                 hvdm - target VDM
 *                 cb - length of value
 *                 psz - ptr to BOOL value
 *
 * OUTPUT        = returns 0 (no error)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

ULONG EXPENTRY VVSetRetraceEmulation(ULONG op,HVDM hvdm,ULONG cb,PSZ psz)
{
  HHOOK hhook;

  AssertTRUE(op == VDHPROP_SET);
  SETBIT(pVDMData(hvdm)->flVDMXVideo,
         VDMX_RTRCEMULATE,
         (BOOL)psz);

  if (ALLOCHOOK((PFNARM)VVSpecialCaseIO,
                0,
                hhook,
                cb))
    ARMHOOK(hhook,
            hvdm);
  return 0;
}

/***************************************************************************
 *
 * FUNCTION NAME = VVSetUpdateFrequency
 *
 * DESCRIPTION   = Set per-VDM graphics update frequency
 *
 *                 This routine is called when the user alters an existing
 *                 VDM's graphics update frequency "advanced property"
 *                 setting.
 *
 * INPUT         = op - operation to perform (set)
 *                 hvdm - target VDM
 *                 cb - length of value
 *                 psz - ptr to BOOL value
 *
 * OUTPUT        = returns 0 (no error)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

ULONG EXPENTRY VVSetUpdateFrequency(ULONG op,HVDM hvdm,ULONG cb,PSZ psz)
{
  AssertTRUE(op == VDHPROP_SET);
  pVDMData(hvdm)->nPeriodicLimit = ((ULONG)psz *100)/TIMER_CHECK;
  return 0;
}

/***************************************************************************
 *
 * FUNCTION NAME = VVSetInt2F
 *
 * DESCRIPTION   = Set per-VDM INT 2Fh flag
 *
 *                 This routine is called when the user alters an existing
 *                 VDM's INT 2Fh setting.
 *
 * INPUT         = op - operation to perform (set)
 *                 hvdm - target VDM
 *                 cb - length of value
 *                 psz - ptr to BOOL value
 *
 *
 * OUTPUT        = returns 0 (no error)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

ULONG EXPENTRY VVSetInt2F(ULONG op,HVDM hvdm,ULONG cb,PSZ psz)
{
  FLAGS fSet = (BOOL) psz;                      /*            */
  AssertTRUE(op == VDHPROP_SET);
  SETBIT(pVDMData(hvdm)->flVDMXVideo,
         VDMX_INT2F,
         fSet);                                 /*            */

   #ifdef   VGA                                  /*                         */
#ifdef SVGA                                      /*            */
  SETBIT(pVDMData(hvdm)->flVDMXVideo,
         VDMX_ONDEMAND,
         (BOOL) !fSet);
  SETBIT(pVDMData(hvdm)->flVDMXVideo,
         VDMX_INT10RESTORE,
         (BOOL) (!fSet & !flInt10Disabled));     /*            */
#endif                                           /*            */
  /*
  ** send INT 2F ON/OFF notification                                        
  */

  if ((pfnInt2FProc) &&                          /*                         */
  (flNotifyType&VDHVVD_NOTIFY_ON_OFF))           /*                         */
    (*pfnInt2FProc)(hvdm,
                    (ULONG)fSet,                /*            */
                    (PCRF)NULL);                 /*                         */
   #endif                                        /*                         */
   return 0;
}

/***************************************************************************
 *
 * FUNCTION NAME = VVSetOnDemandAlloc
 *
 * DESCRIPTION   = Set per-VDM on-demand allocation flag
 *
 *                 This routine is called when the user alters an existing
 *                 VDM's on-demand allocation setting.
 *
 * INPUT         = op - operation to perform (set)
 *                 hvdm - target VDM
 *                 cb - length of value
 *                 psz - ptr to BOOL value
 *
 * OUTPUT        = returns 0 (no error)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

ULONG EXPENTRY VVSetOnDemandAlloc(ULONG op,HVDM hvdm,ULONG cb,PSZ psz)
{
  AssertTRUE(op == VDHPROP_SET);
  SETBIT(pVDMData(hvdm)->flVDMXVideo,
         VDMX_ONDEMAND,
         (BOOL)psz);
  return 0;
}

#endif                                           /* PROPERTIES              */

/***************************************************************************
 *
 * FUNCTION NAME = VVFgndContext()
 *
 * DESCRIPTION   = Finish foreground switch in VDM's context
 *
 *                  This is a context hook armed by VVSetFgnd and called in
 *                  the context of the new foreground VDM.  Its purpose is
 *                  to update the video memory mappings, and to initialize
 *                  the display via INT 10h if that has not been done yet.
 *
 * INPUT         = p    == undefined
 *                 pcrf -> VDM register frame (NULL if called from VDD)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID HOOKENTRY VVFgndContext(PVOID p,PCRF pcrf)
{
  BYTE sav_PORT_VGADACREAD;                      /*                         */
  USHORT i;                                      /*                         */

  RequestMutexSem(VDMData.hmxVideoState);

  if (pcrf)
    VDMData.flVDMVideo &= ~VDM_FGNDHOOK;

  /*
  ** Check session state in case hook was postponed so long that
  ** we are once again background (which can happen with pop-ups).
  */

  if (VDMData.flVDMVideo&VDM_FGND)
  {

/*   #ifdef VGA                                                             */
/*    if (VDMData.flVDMXVideo & VDMX_SAVERESTORE) {                         */
/*   #endif                                                                 */

    /*
    ** If background hooks installed, remove
    */

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

#ifdef SVGA
    vvAcceleratorSetBgndOnlyHooks( FALSE );       /*          *//*          */
#endif /* SVGA */
    /*
    ** If foreground hooks not installed, install
    */

    if( !(VDMData.flVDMVideo & VDM_FGNDREADY) )
    {
      vvSetIOHooks( FALSE,              /* Fgnd */              /*          */
                    TRUE,               /* Install */
                    TRUE );             /* Wait */
      VDMData.flVDMVideo |= VDM_FGNDREADY;
    }

    /*
    ** Disable fgnd and special I/O trapping where appropriate
    */

    vvEnableIO();

    /*
    ** Set up appropriate mappings
    */
    VVEnableBuffer( TRUE,
                      pcrf );

#ifndef  MONO             /* ** for primary adapter only ** */  /*          */
    if (pcrf)
      vvInt2FNotify(INT2F_SYSFGND,
                    pcrf);
#endif /* MONO */                                               /*          */

    /*
    ** Force VDM to call INT 10h if it has no I/O state yet.
    */

    if (!(VDMData.flVDMVideo&(VDM_IOINIT|VDM_MODECHANGING)))
    {
      vvInt10Initialize(pcrf);

#ifdef   VGA                                                    /*          */

      /*
      ** Update virtual dac registers with physical regs                    
      ** TO INSURE AN ACCURATE SHADOW IN INSTANCE DATA                      
      */

      if (!(VDMData.flVDMVideo&VDM_WINDOWED))
      {                                                         /*          */
        /*!!Shouldn't this use a DAC save routine? */           /*          */
        sav_PORT_VGADACREAD =                                   /*          */
          vvInput( INVALID_HVDM,                                /*          */
                   &pleVGADACRead );                            /*          */
        vvOutput( INVALID_HVDM,                                 /*          */
                  &pleVGADACRead,                               /*          */
                  0 );                                          /*          */
        for( i = 0;
             i < MAX_DACREGS;
             i++ )
        {                                                       /*          */
          VDMData.adacDACData[i].dac_bRed                       /*          */
            = vvInput( INVALID_HVDM,                            /*          */
                       &pleVGADACData );                        /*          */
          VDMData.adacDACData[i].dac_bGreen                     /*          */
            = vvInput( INVALID_HVDM,                            /*          */
                       &pleVGADACData );                        /*          */
          VDMData.adacDACData[i].dac_bBlue                      /*          */
            = vvInput( INVALID_HVDM,                            /*          */
                       &pleVGADACData );                        /*          */
        }                                                       /*          */
        vvOutput( INVALID_HVDM,                                 /*          */
                  &pleVGADACRead,                               /*          */
                  sav_PORT_VGADACREAD );                        /*          */
      }                                                         /*          */
#endif                                                          /*          */
    }                                                           /*          */

#ifdef   SVGA

    if (vdhBTR(&VDMData.flVDMVideo,
               LOG2(VDM_FROZEN)))
      VDHThawVDM(CURRENT_VDM);

#endif

  }
  ReleaseMutexSem(VDMData.hmxVideoState);
}

/***************************************************************************
 *
 * FUNCTION NAME = VVBgndContext()
 *
 * DESCRIPTION   = Finish background switch in VDM's context
 *
 *                 This is a context hook armed by VVSetBgnd and called in
 *                 the context of the new background VDM.  Its purpose is to
 *                 shrink the video buffers down to a reasonable size, and
 *                 update the video memory mappings.
 *
 * INPUT         = p    == undefined
 *                 pcrf -> VDM register frame (NULL if called from VDD)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID HOOKENTRY VVBgndContext(PVOID p,PCRF pcrf)
{
  RequestMutexSem(VDMData.hmxVideoState);

  if (pcrf)
    VDMData.flVDMVideo &= ~VDM_BGNDHOOK;

  /*
  ** Check session state in case hook was postponed so long that
  ** we are once again foreground (which can happen with pop-ups).
  */

  /*           
  ** If another device registered for 2F notification, setup the hooks and
  ** issue the 2F. Otherwise, either issue the 2F or setup the hooks depending
  ** on the 2FPENDING flag. If 2FPENDING is set, FGND flag is still set.
  */
  if (!(VDMData.flVDMVideo&VDM_FGND))
  {

/*   #ifdef VGA                                                             */
/*    if (VDMData.flVDMXVideo & VDMX_SAVERESTORE) {                         */
/*   #endif                                                                 */

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

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

    /*
    ** If background hooks not installed, install
    */

    if( !(VDMData.flVDMVideo & VDM_BGNDREADY) )
    {
      vvSetIOHooks( TRUE,               /* Bgnd */              /*          */
                    TRUE,               /* Install */
                    TRUE );             /* Wait */
      VDMData.flVDMVideo |= VDM_BGNDREADY;
    }

#ifdef SVGA
    /*
    ** Install background only hooks on accelerator.
    ** If NOIOTRAPPING in foreground is set,
    ** install the hooks for other IO ports.
    ** Once the VDM goes foreground,
    ** the ports will be disabled by the first trapped IO access.
    */
    vvAcceleratorSetIOHooks( TRUE );              /*          *//*          */
    vvAcceleratorSetBgndOnlyHooks( TRUE );        /*          *//*          */
#endif
    /*
    ** Disable special VDM I/O trapping where appropriate
    */

    VVSpecialCaseIO( NULL,
                     NULL );

    /*
    ** Shrink memory down (this could be done out-of-context
    ** now, but we might as well do it at the leisure of the VDM).
    */

    vvShrinkBuffer(CURRENT_VDM, FALSE);

    /*
    ** Set up appropriate mappings
    */
    VVEnableBuffer( TRUE, pcrf );
                                                              /*            */
#ifndef  MONO             /* ** for primary adapter only **                 */

#ifdef SVGA                                                     /*            */
    if(VDMData.flVDMXVideo & VDMX_INT2FREGIST)
#endif
    if (pcrf)
      vvInt2FNotify(INT2F_SYSBGND,
                    pcrf);
#endif                                           /*                         */

    /*
    ** Force VDM to call INT 10h if we don't have state yet
    */

    if (!(VDMData.flVDMVideo&(VDM_IOINIT|VDM_MODECHANGING)))
      vvInt10Initialize(pcrf);


#ifdef   SVGA
    /*
    ** Freeze SVGA modes
    */
    if( !(VDMData.flVDMXVideo & VDMX_INT2F)
        && (VDMData.flVDMXVideo & VDMX_ENHANCEDMODE)
        && !VDMData.VdmSVGA.flBgndExecEnabled
        || (((VDMData.ulBIOSMode & ~BIOSVINFO_DONTCLEAR)
             == BIOSVMODE_CO320X200X256)
            && !(VDMData.aregSEQData [REG_SEQMEMMODE] & SEQMEM_CHAIN4 )))
    {
      if (!vdhBTS(&VDMData.flVDMVideo, LOG2(VDM_FROZEN)))
        VDHFreezeVDM( CURRENT_VDM );
      vvAddEvent( CURRENT_VDM,
                  VVDEVENT_MODE,
                  NULL,
                  0 );
    }
#endif

  }
#ifdef SVGA
  else
    if (VDMData.flVDMXVideo & VDMX_INT2FPENDING && pcrf)       /*          */
      vvInt2FNotify(INT2F_SYSBGND,
                    pcrf);
#endif /* SVGA */

  ReleaseMutexSem(VDMData.hmxVideoState);
}

/***************************************************************************
 *
 * FUNCTION NAME = vvFreezeVDM()
 *
 * DESCRIPTION   = Worker to freeze VDM/notify Shield
 *
 * INPUT         = hvdm  == VDM handle
 *                 fWait == TRUE to wait for thaw, FALSE to simply freeze and return
 *
 * OUTPUT        = TRUE if freeze succeeded, FALSE if error occurred (ie, VDM was killed)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

BOOL PRIVENTRY vvFreezeVDM(
  HVDM hvdm,
  BOOL fWait )
{
  register INT i;
  VDHSEMSTATE vss;
  BOOL fSuccess = TRUE;
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** Reset semaphore before forcing FROZEN bit on, to guarantee
  ** the WaitEventSem will not miss any posting done in vvThawVDM.
  */

  ResetEventSem(pvd->hevFreezeThaw);

  /*
  ** Test-and-set frozen state, to minimize nested freezing and
  ** redundant/confusing user notifications .
  */

  if (!vdhBTS(&pvd->flVDMVideo,
              LOG2(VDM_FROZEN)))
  {

    /*
    ** Freeze first
    */

    AssertRC(VDHFreezeVDM(hvdm));

    /*
    ** Post the event to the Shield
    */

    vvUpdateModeData( hvdm );

    /*
    ** If VDM is foreground, then we have a REAL problem
    */

    if (pvd->flVDMVideo&VDM_FGND)
      vvAddEvent(hvdm,
                 VVDEVENT_SWITCHERROR,
                 NULL,
                 0);
  }

  if (fWait)
  {

    /*
    ** Get # times we grabbed this semaphore
    */

    VDHQuerySem(pvd->hmxVideoState,
                SSToDS(&vss));

    for (i = 0; i < vss.vss_cRequest; i++)
      ReleaseMutexSem(pvd->hmxVideoState);
    fSuccess = WaitEventSem(pvd->hevFreezeThaw);

    /*
    ** Regrab this semaphore the appropriate number of times
    */

    while (i--)
      RequestMutexSem(pvd->hmxVideoState);
  }
  return  fSuccess;
}

/***************************************************************************
 *
 * FUNCTION NAME = vvThawVDM()
 *
 * DESCRIPTION   = Worker to thaw VDM/notify Shield
 *
 * INPUT         = hvdm == VDM handle
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

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


  if (vdhBTR(&pvd->flVDMVideo,
             LOG2(VDM_FROZEN)))
  {

    /*
    ** Post the event to the Shield
    */

    vvUpdateModeData( hvdm );

    /*
    ** Thaw last
    */

    VDHThawVDM(hvdm);

    /*
    ** In case there's anyone blocked in vvFreezeVDM, wake them up
    */

    PostEventSem(pvd->hevFreezeThaw);
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vvInt2FNotify()
 *
 * DESCRIPTION   = Worker to issue INT 2Fh to VDM
 *
 * INPUT         = ulFunc == INT 2Fh code
 *                 pcrf   -> VDM register frame
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID PRIVENTRY vvInt2FNotify(ULONG ulFunc,register PCRF pcrf)
{

#ifndef  MONO                 /* any primary device except MONO             */

  if (VDMData.flVDMXVideo&VDMX_INT2F)
  {                                              /*                         */

#ifdef   VGA                                     /*                         */
#ifdef SVGA                                                     /*          */
    /*
    ** If we are switching the VDM into the foreground before it completed
    ** a mode set, do not prepare, since the VDM has a difficult task of
    ** handling an embedded mode set.
    */
//              if(( ulFunc == INT2F_SYSFGND ) && !(VDMData.flVDMVideo & VDM_MODECHANGING))
    if( ulFunc == INT2F_SYSFGND )
      /* Note that this is done in the FOREGROUND! */           /*          */
      vvInt10SetModePrepare( CURRENT_VDM );                     /*          */
#endif /* SVGA */                                               /*          */

    /*
    ** send start of INT 2F notification                                    
    */

    if( (pfnInt2FProc)                           /*                         */
        && (flNotifyType&VDHVVD_NOTIFY_START) )  /*                         */
      (*pfnInt2FProc)(VDMData.hvdmVideo,         /*                         */
                      (VDMData.flVDMVideo&VDM_FGND)?/*                      */
                         VDHVVD_INT2F_FG_START:  /*                         */
                         VDHVVD_INT2F_BG_START,  /*                         */
                      pcrf);                     /*                         */
#endif /* VGA */                                 /*                         */
    VDHPushRegs(VDHREG_AX);
    AX(pcrf) = ulFunc;

    if( VDMData.flV86mode = ((flVdmStatus & VDM_STATUS_VPM_APP)
                             && !(flVdmStatus & VDM_STATUS_VPM_EXEC)) )
    {                                            /*                         */
      VDHSwitchToVPM();                          /*                         */
    }                                            /*                         */
#ifdef V21YEE07
     /*            
     **  Fix removed because it requires MR1 kernel.  This way
     **  video drivers based on the DDK will run on both GA and MR1.
     */
    if (flVdmStatus&VDM_STATUS_VPM_EXEC)         /*                  73541  */
    {                                            /*                  73541  */
       if (em86Is32Sel(SS(pcrf)))                /* is stack big?    73541  */
       {                                         /*                  73541  */
          VDHBeginUseVPMStack();                 /* switch stacks    73541  */
          flBigSel = TRUE;                       /*                  73541  */
       }                                         /*                  73541  */
    }                                            /*                  73541  */
#endif /*V21YEE07*/
    VDHArmReturnHook(VDMData.hhookInt2FReturn,
                     VDHARH_RECURSIVE_CSEIP_HOOK);
    VDHPushInt(INT2F_INT);
  }
#endif                                           /*                         */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvInt2FReturn()
 *
 * DESCRIPTION   = Return hook for our INT 2Fh calls
 *
 * INPUT         = pvoid == undefined
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID HOOKENTRY vvInt2FReturn(PVOID p,register PCRF pcrf)
{

#ifdef   VGA                                     /*                         */

  /*
  ** send end of INT 2F notification                                        
  */

  if ((pfnInt2FProc) &&                          /*                         */
     (flNotifyType&VDHVVD_NOTIFY_END))           /*                         */
    (*pfnInt2FProc)(VDMData.hvdmVideo,           /*                         */
                    (VDMData.flVDMVideo&VDM_FGND)?/*                        */
                       VDHVVD_INT2F_FG_END:      /*                         */
                       VDHVVD_INT2F_BG_END,      /*                         */
                    pcrf);                       /*                         */
#endif                                           /*                         */

#ifndef  MONO                 /* any primary device except MONO             */

#ifdef V21YEE07
     /*            
     **  Fix removed because it requires MR1 kernel.  This way
     **  video drivers based on the DDK will run on both GA and MR1.
     */
  if (flBigSel)                                  /* is stack big?    73541  */
  {                                              /*                  73541  */
     flBigSel = FALSE;                           /*                  73541  */
     VDHEndUseVPMStack();                        /* restore stack    73541  */
  }                                              /*                  73541  */
#endif /*V21YEE07*/
  if (VDMData.flV86mode)
  {                                              /*                         */
    VDHSwitchToV86();                            /*                         */
  }                                              /*                         */
  VDHPopRegs(VDHREG_AX);
#endif                                           /*                         */
#ifdef SVGA
  VDHPostEventSem(VDMData.VdmSVGA.hevDelaySwitch);         /*          */
#endif
}

#ifdef   VGA                                     /*                         */

/***************************************************************************
 *
 * FUNCTION NAME = VDHRegisterInt2FProc
 *
 * DESCRIPTION   = INT 2F registration routine
 *
 *                  This routine is called by whichever another primary
 *                  virtual video device driver such as 8514 or XGA requires
 *                  completion of INT 2F notification.
 *
 * INPUT         = flType  =  type of notification required (see VVD.H)
 *                 pfn     -> VVD entry point to signal INT 2F completion
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID VDHENTRY VDHRegisterInt2FProc(FLAGS flType,PFNINT2FP pfn)/*            */
{                                                /*                         */

  /*
  ** FLAG: need to handle multiple device registerations                    
  */

  flNotifyType = flType;                         /* save notification type
                                                                            */
  pfnInt2FProc = pfn;                            /* save routine address
                                                                            */
}                                                /*                         */
#endif                                           /*                         */
#pragma  END_SWAP_CODE

