/*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 = VVINIT.C
 *
 * DESCRIPTIVE NAME = Virtual Video Device Driver Initialization
 *
 *
 * VERSION = V2.0
 *
 * DATE      11/10/88
 *
 * DESCRIPTION  This module contains the VVD's initialization code.
 *
 * FUNCTIONS    VDDInit()           VVD initialization
 *              vvEditVideoTables() Edit global tables for adapter if necessary
 *              vvFindMono()        Test if a Monochrome adapter is installed
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


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

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif

#pragma  BEGIN_SWAP_DATA

extern ULONG npgActive[];             /* moved from VVSTATE.C              */
extern ULONG flVVD;
extern PBOOL pflVDMBusy;              /* offset to WakeIdle flag           */
extern PSZ pszVVDName;
extern PBYTE pPhysVRAM;
extern PVDM pvdmPhysVRAM;
extern ULONG npgPhysVRAM;
extern ULONG npgPlane;
extern PLE apleAll[];
extern HMXSEM hmxWindowedEvent;
extern HEVSEM hevWindowedEvent;
extern HHOOK hhookEventTimer;

#ifdef   EGAVGA
/*!!These two belong in vvphys.c! */                            /*          */
extern HMXSEM hmxPhysLatch;
extern HMXSEM hmxPhysPageEvent;

extern PLE pleATCx;                                             /*          */
extern PLE pleSEQIndx;                                          /*          */
extern PLE pleSEQData;                                          /*          */
extern PLE pleCRTIndx;                                          /*          */
extern PLE pleCRTData;                                          /*          */
extern PLE pleGDCIndx;                                          /*          */
extern PLE pleGDCData;                                          /*          */
extern PLE pleATIVGAIndx;                                       /*          */
extern PLE pleATIVGAData;                                       /*          */
extern PLE pleVGADACMask;               /* 0x03c6 (R/W) */      /*          */
#endif

#ifdef   VGA
extern BYTE aregSEQInit[MAX_SEQREGS];
extern BYTE aregGDCInit[MAX_GDCREGS];                           /*          */
extern BYTE aregCRTInit[MAX_CRTREGS];                           /*          */
BOOL   flDualDisplayConf = FALSE;                               /*          */
#endif /* VGA */

#ifdef   SVGA
extern BYTE aregATIInit[ATI_TOTAL_INITREGS];
extern BOOL     flBgndExecSupported;                            /*          */
extern BOOL     flInt10Disabled;                                /*          */
extern BYTE aregCRTCBInit[TOTAL_TSENG_CRTCBREGS];               /*          */
extern PLE pleTsengCRTCBData;                                   /*          */
extern PLE pleTsengCRTCBIndex;                                  /*          */
extern PSADAPTERINFO psCurAdapterInfo;                          /*          */
extern SDACINFO sDacBT485Info;                                  /*          */
extern SDACINFO sDacHiColorInfo;                                /*          */
extern PSDACINFO psCurDacInfo;                                  /*          */
#endif

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

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

/* extern  SZ      szPropSyncOutput;                                        */

extern SZ szPropInt2F;
extern SZ szPropOnDemandAlloc;
#endif

#ifdef   VDDSTRICT
extern ULONG nbVDMData;
#endif
#pragma  END_SWAP_DATA

#ifdef   EGAVGA
   #pragma  BEGIN_GLOBAL_DATA
extern HEVSEM hevControllerEvent;
   #pragma  END_GLOBAL_DATA
#endif
#pragma  BEGIN_INIT_CODE

/***************************************************************************
 *
 * FUNCTION NAME = vvFindMono()
 *
 * DESCRIPTION   = Test if a Monochrome adapter is installed
 *
 *                 This routine checks if a Monochrome adapter/monitor is
 *                 installed It looks for the MONO's 6845 CRTC at I/O ports
 *                 0x3B4 and 0x3B5.  It attempts to read/write to these
 *                 ports and compares the values.
 *
 * INPUT         = None
 *
 * OUTPUT        = TRUE if MONO hardware exists, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvFindMono( VOID )                               /*          */
/*PVOID pLowMemAlias )                *//* Not needed! */       /*          */
{
  BYTE invalue;

  /* Do not use vvInput/vvOutput because                      *//*          */
  /* 1) we do not want mono ports adjusted to color           *//*          */
  /* 2) we (monocga) may not have a PLE for the GDCPOS1 port  *//*          */

  /*
  ** Select the cursor index register and read its value
  */
  OUTB( PORT_MONOCRTINDX,
        REG_CRTCURLOCLO );
  invalue = INB( PORT_MONOCRTDATA );

  /*
  ** Modify its value
  */
  invalue ^= 0xff;
  OUTB( PORT_MONOCRTDATA,
        invalue );

  /* Re-Index to clear the bus in case it floats              *//*          */
  /* And therefore saves the previous write.                  *//*          */

  OUTB( PORT_MONOCRTINDX,                                       /*          */
        REG_CRTCURLOCLO );                                      /*          */

  /*
  ** Read the value again;  if changed, assume that MONO is present
  */
  if( invalue == INB( PORT_MONOCRTDATA )
      /* Check for Mono monitor attached to a VGA/EGA         *//*          */
//    && !(pVDMBase( pLowMemAlias )->rb_bVInfo & BIOSVINFO_EGAMONO)
//    && !(pVDMBase( pLowMemAlias )->rb_bVFlags & BIOSVFLAGS_VGAMONO) )
      /* Just to make sure port exists,                       *//*          */
      /* Make sure not 0x00 or not 0xff either, so check      *//*          */
      /* for MISCOUT_ENABLERAM to have both off and on        *//*          */
      && ((INB( PORT_GDCPOS1 )                                  /*          */
           & (MISCOUT_ENABLERAM | MISCOUT_COLRPORTS))           /*          */
          != MISCOUT_ENABLERAM) )                               /*          */
    flVVD |= VVD_MONOPRESENT;

#ifndef MONO                                           /*            */
  else                                                 /*            */
    /*
    ** Fixup for maximum number of monochrome pages                 
    */
    npgActive[2] = 8;    // ((16*1024)/PAGESIZE)*2     /*            */
#endif                                                 /*            */

  /*
  ** Restore its value
  */

  invalue ^= 0xFF;
  OUTB( PORT_MONOCRTDATA,
        invalue );
}

#ifdef   EGAVGA

/***************************************************************************
 *
 * FUNCTION NAME = vvEditVideoTables()
 *
 * DESCRIPTION   = Edit global tables for adapter if necessary
 *
 *                 This routine performs adapter-specific VDD table editing,
 *                 if necessary.
 *
 * INPUT         = pLowMemAlias -> low memory
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvEditVideoTables(PVOID pLowMemAlias)
{
#ifdef   VGA
  register INT i;
  BYTE bSaveIndex;                                /*          *//*          */
#endif

  PBVDM pvdmROM;
  register PROMHDR pROMAlias;

  /*
  ** Pick likely starting point for Video ROM
  */

  pvdmROM = PFROMVADDR(SEGMENTOF16(pVDMBase(pLowMemAlias)->rb_avpIVT
     [BIOSINT_VIDEOGRAPH]),
                       0);
  pROMAlias = VDHAllocPages(pvdmROM,
                            PAGESFROMBYTES(0x10000),
                            VDHAP_SYSTEM|VDHAP_PHYSICAL);
  AssertNONZERO(pROMAlias);

  if (pROMAlias)
  {

#ifdef   TSENG
    if (DWORDOF(pROMAlias->romhdr_abFiller[0x73],
                0) == 0x6e657354)
    {
      pleATCx.ulBRegCount = TOTAL_TSENG_ATCREGS;                /*          */
      pleSEQData.ulBRegCount = TOTAL_TSENG_SEQREGS;             /*          */
      pleGDCData.ulBRegCount = TOTAL_TSENG_GDCREGS;             /*          */
      pleCRTData.ulBRegCount = TOTAL_TSENG_CRTREGS;             /*          */

      #ifdef   VDDDEBUG
      PRINTDEBUG("Patched for TSENG adapter\n");
      #endif
    }
#endif /* TSENG */
    VDHFreePages(pROMAlias);
  }

  /*  ** This is a very dirty section here: it doesn't know what the current hardware
  ** is and whether it is unlocked. It blindly writes/reads ports which may not
  ** exist. It can't be removed yet, because we have no way of replacing the
  ** functionallity yet. The function is trying to compensate for the
  ** fact that we don't always know how to prepare the state of the VDM 
  ** (hardware or shadow) in order to allow the BIOS int 10 to be successful at
  ** the creation time. This section is usefull only if we are running without a
  ** PMI file in an environment where a VDM is to be created at the time when
  ** controller is in an advanced state (example: non PMI (8514/vendor) display driver. 
  ** When a PMI file exists, vvInt10SetModePrepare function performs this functionality.
  ** That function reads the current state of the controller to get a basic shadow 
  ** and then performs PMI Cleanup on top to simulate the state at the init time.
  */
#ifdef   VGA

  bSaveIndex = vvInput( INVALID_HVDM,                           /*          */
                        &pleSEQIndx );                          /*          */
  for( i = 0;
       i < MAX_SEQREGS;
       i++ )
  {
    vvOutput( INVALID_HVDM,                                     /*          */
              &pleSEQIndx,                                      /*          */
              (BYTE) i );
    aregSEQInit [i] = vvInput( INVALID_HVDM,                    /*          */
                               &pleSEQData );                   /*          */
  }
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleSEQIndx,                                        /*          */
            bSaveIndex );                                       /*          */

  bSaveIndex = vvInput( INVALID_HVDM,                           /*          */
                        &pleGDCIndx );                          /*          */
  for( i = 0;
       i < MAX_GDCREGS;
       i++ )
  {                                                             /*          */
    vvOutput( INVALID_HVDM,                                     /*          */
              &pleGDCIndx,                                      /*          */
              (BYTE) i );                                       /*          */
    aregGDCInit [i] = vvInput( INVALID_HVDM,                    /*          */
                               &pleGDCData );                   /*          */
  }                                                             /*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleGDCIndx,                                        /*          */
            bSaveIndex );                                       /*          */

  bSaveIndex = vvInput( INVALID_HVDM,                           /*          */
                        &pleCRTIndx );                          /*          */
  for( i = 0;
       i < MAX_CRTREGS;
       i++ )
  {                                                             /*          */
    vvOutput( INVALID_HVDM,                                     /*          */
              &pleCRTIndx,                                      /*          */
              (BYTE) i );                                       /*          */
    aregCRTInit [i] = vvInput( INVALID_HVDM,                    /*          */
                               &pleCRTData );                   /*          */
  }                                                             /*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTIndx,                                        /*          */
            bSaveIndex );                                       /*          */

#endif /* VGA */

#ifdef   SVGA

  bSaveIndex = (BYTE) (vvInput( INVALID_HVDM,                   /*          */
                               &pleATIVGAIndx )                 /*          */
                       | 0x80);                                 /*          */
  for( i = ATI_START_EXTREGS;
       i < ATI_END_EXTREGS;
       i++ )
  {
    vvOutput( INVALID_HVDM,                                     /*          */
              &pleATIVGAIndx,                                   /*          */
              (BYTE) i );
    aregATIInit [i - ATI_START_EXTREGS] =
      vvInput( INVALID_HVDM,                                    /*          */
               &pleATIVGAData );                                /*          */
  }
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleATIVGAIndx,                                     /*          */
            bSaveIndex );                                       /*          */

  /* JWK01 start for tseng */

  bSaveIndex = (BYTE) (vvInput( INVALID_HVDM, &pleTsengCRTCBIndex ));
  for ( i = TSENG_CRTCB_START; i <= TSENG_CRTCB_END; i++ )
  {
    vvOutput( INVALID_HVDM,
              &pleTsengCRTCBIndex,
              (BYTE) i );
    aregCRTCBInit [i] =
      vvInput( INVALID_HVDM,
               &pleTsengCRTCBData );
  }
  vvOutput( INVALID_HVDM,
            &pleTsengCRTCBIndex,
            bSaveIndex );


  /* JWK01 end for tseng */

#endif /* SVGA */
}

#endif /* EGAVGA */

/*            start */
#ifdef   SVGA

/* This code is here only for the compatibility with early S3 *//*          */
/* drivers which did not have compete DAC identification in   *//*          */
/* the SVGADATA.PMI file.                                     *//*          */
/* DACs should now be detected/identified by SVGA.EXE         *//*          */
/* instead of during VSVGA.SYS init time!                     *//*          */
/* In other words, DO NOT ADD MORE DAC ID CODE IN VSVGA!      *//*          */

/*****************************************************************************
 *
 * FUNCTION NAME = vvDacIsBrooktree()                                       
 *
 * DESCRIPTION   = If Brooktree DAC identified, return TRUE.
 *                 This is specific for the BT485 RAMDAC used by S3
 *                 because in order to get to the DAC, specific
 *                 S3 registers must be manipulated.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 1
 * RETURN-ERROR  = 0
 *
 ****************************************************************************/

BOOL PRIVENTRY vvDacIsBrooktree( VOID )                         /*          */
{
  BYTE bIndx;                                                   /*          */
  BOOL bId;
  BYTE bTmp;

  bIndx = vvInput( INVALID_HVDM,                                /*          */
                   &pleCRTIndx );       /* get current index */ /*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTIndx,                                        /*          */
            0x39 );                     /* unlock S3 register *//*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTData,                                        /*          */
            0xa0 );                                             /*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTIndx,                                        /*          */
            0x55 );                     /* S3's key to DAC  */  /*          */
  bTmp = vvInput( INVALID_HVDM,                                 /*          */
                  &pleCRTData );                                /*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTData,                                        /*          */
            (BYTE) (bTmp & 0xfc) );     /* set RS[3:2] = 0,0  *//*          */
  psCurAdapterInfo->pfnSVGADacRS2Clear( INVALID_HVDM );         /*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleVGADACMask,                                     /*          */
            0xff);                      /* set mask reg = ff  */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTData,                /* set RS[3:2] = 1,0  *//*          */
            (BYTE) (bTmp & 0xfc | 0x02) );                      /*          */
  /*
  ** Read the ID
  */
  bId = (vvInput( INVALID_HVDM,                                 /*          */
                 &pleVGADACMask )       /* get ID from Status *//*          */
         != 0xff);                      /* A BT 485 RAMDAC!   *//*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTData,                                        /*          */
            bTmp );                     /* restore RS[3:2]    *//*          */
  vvOutput( INVALID_HVDM,                                       /*          */
            &pleCRTIndx,                                        /*          */
            bIndx );                    /* restore the index */ /*          */
  return( bId );                                                /*          */
}

/* This code is here only for the compatibility with early S3 *//*          */
/* drivers which did not have compete DAC identification in   *//*          */
/* the SVGADATA.PMI file.                                     *//*          */
/* DACs should now be detected/identified by SVGA.EXE         *//*          */
/* instead of during VSVGA.SYS init time!                     *//*          */
/* In other words, DO NOT ADD MORE DAC ID CODE IN VSVGA!      *//*          */

/*****************************************************************************
 *
 * FUNCTION NAME = vvDacGetType()                                           
 *
 * DESCRIPTION   = Identifies DAC for PMI without DACSTRING.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

VOID PRIVENTRY vvDacGetType( VOID )                             /*          */
{
  psCurDacInfo =                                                /*          */
    (vvDacIsBrooktree()                                         /*          */
     ? &sDacBT485Info                   /* it's Brooktree 485 *//*          */
     : &sDacHiColorInfo);                                       /*          */
}
#endif /* SVGA */
/*            end */
/***************************************************************************
 *
 * FUNCTION NAME = VDDInit()
 *
 * DESCRIPTION   = VVD initialization
 *
 *                 This routine is defined as the device driver entry point,
 *                 and is called during system initialization.
 *
 * INPUT         = None
 *
 * OUTPUT        = SUCCESS
 *                     TRUE
 *                 FAILURE
 *                     FALSE (ie, hardware missing, or reserved page conflict)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *                 verify existence of physical hardware
 *                 determine primariness/secondariness
 *                 locate and reserve physical VRAM pages
 *                 obtain global linear mapping to physical VRAM
 *                 define DosRequestVDD/VDHRequestVDD procedure
 *                 define screen-enable-during-pause procedure
 *
 ****************************************************************************/

BOOL EXPENTRY VDDInit(register PSZ pszInit)
{
#ifdef VGA
  PSZ   pInit = pszInit;                                /*           */
#endif
  register INT i;
  PVOID pLowMemAlias;
  register ULONG nKB;
  BOOL fSuccess = TRUE;
  VPBOUND vpbUpdateGrfx =
  {
    1,600,1
  }
  ;
  AssertTRUE(nbVDMData == sizeof(PERVDMDATA));

#ifdef   DCR1013

  while (pszInit = STRTOKEN(pszInit))

    if (STRCOMPARE(pszInit,
                   "/wingraph",
                   FALSE) == 0)
      flVVD |= VVD_GRFXALLOWED;
#endif

#ifdef VGA                                                      /*            */
  while (pInit = STRTOKEN(pInit))

    if (STRCOMPARE(pInit,
                   "/dual",
                   FALSE) == 0)
      flDualDisplayConf = TRUE;
#ifdef SVGA
    else if (STRCOMPARE(pInit,                                  /*            */
                   "/bgexec",
                   FALSE) == 0)
      flBgndExecSupported = TRUE;
    else if (STRCOMPARE(pInit,                                  /*            */
                   "/int10off",
                   FALSE) == 0)
      flInt10Disabled = TRUE;
#endif
#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 global semaphores
  */

#ifdef   EGAVGA

  if (!CreateEventSem(&hevControllerEvent))
    fSuccess = FALSE;

  if (!CreateMutexSem(&hmxPhysPageEvent))
    fSuccess = FALSE;

  if (!CreateMutexSem(&hmxPhysLatch))
    fSuccess = FALSE;
#endif

  if (!CreateEventSem(&hevWindowedEvent))
    fSuccess = FALSE;

  if (!CreateMutexSem(&hmxWindowedEvent))
    fSuccess = FALSE;

  /*
  ** Allocate global context timer hook
  */

  if (!(hhookEventTimer = VDHAllocHook(VDH_TIMER_HOOK,
                                       (PFNARM)VVEventTimer,
                                       0)))
    fSuccess = FALSE;

  /*
  ** Get access to low memory
  */

  pLowMemAlias = VDHAllocPages(LOWMEM_START,
                               LOWMEM_PAGES,
                               VDHAP_SYSTEM|VDHAP_PHYSICAL);

  if (!pLowMemAlias)
    fSuccess = FALSE;

  /*
  ** Begin equipment checks
  */

//vvFindMono(pLowMemAlias);                                     /*          */
  vvFindMono();                                                 /*          */

#ifdef   MONO

  if (!(flVVD&VVD_MONOPRESENT))
    fSuccess = FALSE;                            /* No MPA-Mono installed   */
#endif

#ifdef   EGAVGA

  if (!pVDMBase(pLowMemAlias)->rb_nVRows)
    fSuccess = FALSE;                            /* No EGA/VGA installed    */
#endif


  /*
  ** If we made it past the equipment checks
  */

  if (fSuccess)
  {

    /*
    ** Note that VVD_PRIMARY *would* be set whenever the equipment flags
    ** so indicate, but under OS/2, a mono monitor can never be primary
    */

#ifndef  MONO
    flVVD |= VVD_PRIMARY;
#endif

    /*
    ** Mark VRAM pages as reserved
    */

#ifdef   EGAVGA

    if (flVVD&VVD_MONOPRESENT)
    {
      fSuccess = VDHReservePages(pvdmPhysVRAM,
                                 PAGESFROMBYTES(MONOMEM_START-EGAVGAMEM_START)
         ) && VDHReservePages((PBVDM)(MONOMEM_START+MONOMEM_LEN),
                              npgPhysVRAM-PAGESFROMBYTES(MONOMEM_START+
                              MONOMEM_LEN-EGAVGAMEM_START));
    }

    else
#endif
         fSuccess = VDHReservePages(pvdmPhysVRAM,
                                    npgPhysVRAM);
  }

  /*
  ** If VRAM pages were successfully reserved
  */

  if (fSuccess)
  {

    /*
    ** Obtain global addressability to physical VRAM
    */

    pPhysVRAM = VDHAllocPages((PBVDM)VRAM_START,
                              PAGESFROMBYTES(VRAM_LEN),
                              VDHAP_SYSTEM|VDHAP_PHYSICAL);

    if (pPhysVRAM)
    {

      /*
      ** Install user event hooks
      */

      VDHInstallUserHook(VDM_CREATE,
                         (PUSERHOOK)VVCreate);
      VDHInstallUserHook(VDM_CREATE_DONE,
                         (PUSERHOOK)VVCreateDone);/*                        */
      VDHInstallUserHook(VDM_FOREGROUND,
                         (PUSERHOOK)VVSetFgnd);
      VDHInstallUserHook(VDM_BACKGROUND,
                         (PUSERHOOK)VVSetBgnd);
      VDHInstallUserHook(VDM_CODEPAGE_CHANGE,
                         (PUSERHOOK)VVChangeCodePage);
      VDHInstallUserHook(VDM_TITLE_CHANGE,
                         (PUSERHOOK)VVChangeTitle);
      VDHInstallUserHook(VDM_TERMINATE,
                         (PUSERHOOK)VVDestroy);

#ifdef   EGAVGA

      /*
      ** Determine the size of physical memory planes
      */

      nKB = (pVDMBase(pLowMemAlias)->rb_bVInfo&BIOSVINFO_MEMMASK);
      nKB = ((nKB >> ZEROBITS(BIOSVINFO_MEMMASK))+1)*(16*1024);

      /*
      ** Save # pages per plane
      */

      npgPlane = nKB/PAGESIZE;

      /*
      ** Make any necessary adapter-specific table edits
      */

      vvEditVideoTables(pLowMemAlias);

      /*
      ** Initialize the physical page usage table
      */

      vvUpdatePhysPageMap(NULL);
#endif

      /*
      ** Set VDD name to secondary name if secondary display
      */

      pszVVDName = VVD_NAME1;

      if (!(flVVD&VVD_PRIMARY))
        pszVVDName = VVD_NAME2;
      VDHRegisterVDD(pszVVDName,
                     VVSysReqProc,
                     VVDevReqProc);

#ifdef   CGA
      VDHRegisterScreenProc(VVForceDisplay);
#endif

#ifdef   PROPERTIES

      if (!VDHRegisterProperty(szPropInt10Emulate, /* property name         */
                               NULL,             /* no help file            */
                               0,                /* no help id              */
                               VDMP_BOOL,        /* type                    */
                               VDMP_ORD_OTHER,   /* no ordinal              */
                               0,                /* modifiable after
                                                    creation                */
                               (VOID *)TRUE,     /* default                 */
                               NULL,             /* validation info         */
                               VVSetInt10Emulation/* function               */
                                  ))
        fSuccess = FALSE;

      if (!VDHRegisterProperty(szPropRtrcEmulate, /* property name          */
                               NULL,             /* no help file            */
                               0,                /* no help id              */
                               VDMP_BOOL,        /* type                    */
                               VDMP_ORD_OTHER,   /* no ordinal              */
                               0,                /* modifiable after
                                                    creation                */

/*                  (VOID*)FALSE,                  default                  */

/*                             (VOID *)TRUE,     /* default ** Temp Change  */
                               (VOID*)FALSE,     /* default                 */
                               NULL,             /* validation info         */
                               VVSetRetraceEmulation/* function             */
                                  ))
        fSuccess = FALSE;

   #ifdef   EGA

      /*
      ** For the EGA, we have to eliminate one of the restriction
      ** strings;  we either move the mono string on top of the color
      ** string, or nullify the mono string.
      **
      ** We don't have to make any adjustments for the other drivers:
      ** the mono driver doesn't have PROPERTIES support, the CGA driver
      ** just contains the color string, and the VGA driver always
      ** contains both, because VGA can support both color and mono
      ** configurations.
      **
      ** FLAG: 20-Aug-90:    The last bit about VGA is true
      ** with color monitors, but what about mono monitors?
      */

      if (pVDMBase(pLowMemAlias)->rb_bVMode == BIOSVMODE_MONO80)
        memcpy(szPropCGARestrict,
               szPropMONORestrict,
               sizeof(PROP_NAME_MONORESTRICT));
      szPropMONORestrict[0] = 0;
   #endif

      if (!VDHRegisterProperty(szPropModeRestrict, /* property name         */
                               NULL,             /* no help file            */
                               0,                /* no help id              */
                               VDMP_ENUM,        /* type                    */
                               VDMP_ORD_OTHER,   /* no ordinal              */
                               VDMP_CREATE,      /* NOT modifiable after
                                                    creation                */
                               szPropNoRestrict, /* default                 */
                               szPropNoRestrict, /* validation info         */
                               NULL              /* no function             */
                                  ))
        fSuccess = FALSE;

      if (!VDHRegisterProperty(szPropUpdateWindow, /* property name         */
                               NULL,             /* no help file            */
                               0,                /* no help id              */
                               VDMP_INT,         /* type                    */
                               VDMP_ORD_OTHER,   /* no ordinal              */
                               0,                /* modifiable after
                                                    creation                */
                               (VOID *)(TICKS_DIRTY *TIMER_CHECK/100), /*
                                                    default                 */
                               SSToDS(&vpbUpdateGrfx), /* validation info   */
                               VVSetUpdateFrequency/* function              */
                                  ))
        fSuccess = FALSE;

/*   if (!VDHRegisterProperty(                                              */
/*           szPropSyncOutput,    property name                             */
/*           NULL,                no help file                              */
/*           0,                   no help id                                */
/*           VDMP_BOOL,           type                                      */
/*           VDMP_ORD_OTHER,      no ordinal                                */
/*           0,                   modifiable after creation                 */
/*           (VOID*)TRUE,         default                                   */
/*           NULL,                validation info                           */
/*           VVSetSyncOutput      function                                  */
/*        )                                                                 */
/*      )                                                                   */
/*       fSuccess = FALSE;                                                  */

      if (!VDHRegisterProperty(szPropInt2F,      /* property name           */
                               NULL,             /* no help file            */
                               0,                /* no help id              */
                               VDMP_BOOL,        /* type                    */
                               VDMP_ORD_OTHER,   /* no ordinal              */
                               0,                /* modifiable after
                                                    creation                */
                               (VOID *)FALSE,    /* default                 */
                               NULL,             /* validation info         */
                               VVSetInt2F        /* function                */
                                  ))
        fSuccess = FALSE;

      if (!VDHRegisterProperty(szPropOnDemandAlloc, /* property name        */
                               NULL,             /* no help file            */
                               0,                /* no help id              */
                               VDMP_BOOL,        /* type                    */
                               VDMP_ORD_OTHER,   /* no ordinal              */
                               0,                /* modifiable after
                                                    creation                */
                               (VOID *)TRUE,     /* default                 */
                               NULL,             /* validation info         */
                               VVSetOnDemandAlloc/* function                */
                                  ))
        fSuccess = FALSE;
                                                  /*            */
        VDHRegisterProperty(szPropIOTrap,         /* property name           */
                            NULL,                 /* no help file            */
                            0,                    /* no help id              */
                            VDMP_BOOL,            /* type                    */
                            VDMP_ORD_OTHER,       /* no ordinal              */
                            VDMP_CREATE,          /* not modifiable after    */
                                                  /* creation                */
                            (VOID *)TRUE,         /* default                 */
                            NULL,                 /* validation info         */
                            NULL                  /* no function             */
                            );
#endif                                           /* PROPERTIES              */
    }

    else
    {
      fSuccess = FALSE;

#ifdef   EGAVGA

      if (flVVD&VVD_MONOPRESENT)
      {
        VDHUnreservePages(pvdmPhysVRAM,
                          PAGESFROMBYTES(MONOMEM_START-EGAVGAMEM_START));
        VDHUnreservePages((PBVDM)(MONOMEM_START+MONOMEM_LEN),
                          npgPhysVRAM-PAGESFROMBYTES(MONOMEM_START+MONOMEM_LEN
                             -EGAVGAMEM_START));
      }

      else
#endif
           VDHUnreservePages(pvdmPhysVRAM,
                             npgPhysVRAM);
    }
  }
  VDHFreePages(pLowMemAlias);

  /*
  ** If installation failed, free all context hooks/semaphores
  */

  if (!fSuccess)
  {
    VDHFreeHook(hhookEventTimer);
    DestroyEventSem(hevWindowedEvent);
    DestroyMutexSem(hmxWindowedEvent);

#ifdef   EGAVGA
    DestroyMutexSem(hmxPhysPageEvent);
    DestroyEventSem(hevControllerEvent);
#endif
  }

#ifdef   SVGA
  vvDacGetType();                                               /*          */
#endif /* SVGA */

  /*
  ** Get the offset the WakeIdle Flag                                       
  */

  if (!pflVDMBusy)                                              /*          */
    pflVDMBusy = VDHGetBusyFlagPtr();                           /*          */
  return  fSuccess;
}

#pragma  END_INIT_CODE

