/*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 = VVXGA.C
 *
 * DESCRIPTIVE NAME = Virtual XGA/A Video Device Driver for the XGA/A
 *
 *
 * VERSION = V2.0
 *
 * DATE      12/13/91
 *
 * DESCRIPTION  This module contains the all XGA VDD's code and data.
 *
 *
 * FUNCTIONS
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define  IO8BIT                        /* CL386 Version 6.00.054 FLAG: */
#include <mvdm.h>
#include <vvd.h>
#include <vvxgap.h>
#include <propname.h>

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif
#define  INCL_DOSERRORS
#include <bseerr.h>
#pragma  BEGIN_SWAP_DATA

 /*
 **
 **                  GLOBAL DATA
 */

HVDD hvddVideo = NULL;                 /* handle to other VDDs registered
                                          under same name                   */
HVDD hvddDma   = NULL;                 /* handle to VDMA                    */
USHORT nNumConfig = 0;                 /* # XGA instances                   */
USHORT nNumVDM = 0;                    /* # active VDM sessions             */
PBYTE XGAPDAddr = NULL;                /* XGA Page Directory linear address */
ULONG XGAPDPhysAddr = 0L;              /* XGA Page Directory physical
                                          address                           */
HLOCK XGAPDHandle;                     /* XGA Page Directory lock handle    */
USHORT nConfigStart = XGA_INSTANCES;   /* 1st config index for XGAENV[]
                                          search                            */
USHORT nConfigEnd = 0;                 /* last config index for XGAENV[]
                                          search                            */
SHORT CurConfig = -1;                  /* index into XGAENV for supp XGA    */
SHORT InitXGAinVGA = -1;               /* index into XGAENV for XGA in VGA  */
BOOL glVDMXGA;                         /* global VDM flag (see global VDM_*
                                          constants)                        */
PVOID pRingBuffer = NULL;      /* Coprocessor save/restore buffer           */
ULONG pRingBufPhys = NULL;   /* save/restore buffer physical addr           */
HLOCK hRingBuffer = NULL;              /* 64K buffer lock handle            */

 /*
 ** Number of planes is 8 regardless of memory expansion
 */

USHORT nPlanes = 8;                    /* physical plane configuration      */
USHORT npgBufferMax;                   /* maximum # of VRAM pages found on  */

 /*
 ** the best configured XGA
 */

PBYTE p64kVRAM = NULL;                 /* 64K aperture linear address
                                                                            */
BYTE planar_setting;                   /* saved planar setting              */

 /*
 ** XGA structure
 **
 ** This structure defines fields for each instance of XGA.
 */

/*typedef struct xgaenv_s {         for each XGA instance                   */
/*  ULONG  OneMegAperture;          1M aperture                             */
/*  ULONG  VRAMAddr;                video memory base address               */
/*  PBYTE  pVRAMAddr;               Linear address to the XGA's VRAM        */
/*  PBYTE  VRAMPTAddr;              VRAM Page Table linear address          */
/*  HLOCK  VRAMPTHandle;            VRAM Page Table lock handle             */
/*  ULONG  ROMAddr;                 start of ROM address range (ROS + $K)   */
/*  ULONG  COPAddr;                 Coprocessor base address                */
/*  ULONG  pCOPAllocAddr;           Allocated addr to the Coprocessor's MMIO regs*/
/*  COP_S* pCOPAddr;                Linear addr to the Coprocessor's MMIO regs*/
/*  USHORT DupROMAddr;              indicates commonly shared ROM address   */
/*  USHORT IORegBase;               IO register base address                */
/*  CHAR   flVRAM_1Meg;             flag TRUE=1Mb, FALSE=0.5Mb              */
/*  BYTE   Auto_Config;             R/O Index Register                      */
/*  BYTE   Monitor_ID_DAC_Comp      R/O Index Register                      */
/*  BYTE   Mystery_Reg              R/O Index Register query by AFI         */
/*  BYTE   Display_Control1         MOD 90 BIOS workaround                  */
/*  BYTE   External_Clock_Select    MOD 90 BIOS workaround                  */
/*  USHORT Monitor_type;            monitor attached to this XGA            */
/*  struct VDHMapSource_s MapSource;    physical mem mapped regs            */
  /*  ULONG   vdhms_laddr;     linear address of source memory object       */
  /*  ULONG   vdhms_hobj;      memory object handle                         */
/*  struct VDHMapTarget_s MapTarget;    target linear addr in VDM           */
  /*  ULONG     vdhmt_laddr;     Target address in V86-space (0 <=          */
  /*                             vdhmt_laddr < 1M+64K)  to be mapped.       */
  /*  ULONG     vdhmt_cpg;       count of pages to map                      */
  /*  ULONG     vdhmt_hmap;      handle of mapping.  Must be zero on        */
  /*                             first call to VDHMapPages for region.      */
/* }XGAENV_S;                                                               */

XGAENV_S XGAENV[XGA_INSTANCES]={
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
   { 0L, 0L, (char *)0, (char *)0, 0L, 0L, 0L, 0L, 0, 0, FALSE, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L},
                                                                 };

 /*
 ** pagelist_s - structure to describe dis-contiguous physical ranges
 */

struct pagelist_s
{
  ULONG pl_paddr;                      /* base physical address of one
                                          range                             */
  ULONG pl_cb;                         /* bytes contiguously mapped from
                                          pl_paddr                          */
} ;

struct pagelist_s PGList;
ULONG NElements;

 /*
 ** XGA I/O Trap handler routines for 21x0 - 21x9
 */

IOH aiohBReg[] = {
        {VXGAReadOpMode,           VXGAWriteOpMode},
        {VXGAReadApertureCntl,     VXGAWriteApertureCntl},
        {VXGAReadReserved,         VXGAWriteReserved},
        {VXGAReadReserved,         VXGAWriteReserved},
        {VXGAReadIntEnable,        VXGAWriteIntEnable},
        {VXGAReadIntStatus,        VXGAWriteIntStatus},
        {VXGAReadVirtMemCntlr,     VXGAWriteVirtMemCntlr},
        {VXGAReadVirtMemIntStatus, VXGAWriteVirtMemIntStatus},
        {VXGAReadApertureIndex,    VXGAWriteApertureIndex},
        {VXGAReadMemAccess,        VXGAWriteMemAccess},
};

 /*
 ** XGA I/O Trap handler routines for 21xA
 */

IOH iohXGAirregIndex =
{
  VXGAReadIndex,      VXGAWriteIndex,     NULL,/* to be simulated by
                                          VXGAReadIndex                     */
  VXGAWriteIndexWord, NULL,
} ;

 /*
 ** XGA I/O Trap handler routines for 21xB - 21xF
 */

IOH iohXGAirregData =
{
  VXGAReadIndexDataByte,                  VXGAWriteIndexDataByte,
  VXGAReadIndexDataWord,                  VXGAWriteIndexDataWord,
  NULL,
} ;

PSYSFUN apfnSysReq[] =
{
  vXGASysQueryMode,   vXGASysQueryCursor, vXGASysQueryPalette,
  vXGASysCopyLVB,     vXGASysCopyBitmap
} ;

#ifdef   PROPERTIES
SZ szPropIOTrap = PROP_NAME_8514A_IOTRAP;
SZ szPropInt2F = PROP_NAME_INT2F;
#endif

#ifdef   VDDSTRICT
CHAR szAssertMsg[] = "VXGA assertion failure in %s, line %d\n";
#endif

#ifdef   VDDDEBUG
CHAR szModule[] = "VXGA: ";
#endif
#pragma  END_SWAP_DATA
#pragma  BEGIN_SWAP_INSTANCE

 /*
 **      MUST reflect changes to vdmdata_s structure in VVXGAP.H
 */

PERVDMDATA VDMData = {
               VDM_NOTDONE+VDM_OPMODEXGA,     /* BOOL     flVDMXGA              */
               -1,               /* USHORT       nSaveRestoreConfig             */
               0L,               /* TBLMAP_S*    Tblmap                         */
               1L,               /* ULONG        TblPages                       */
               0,                /* INT          TblEntriesPresent;             */
               0,                /* PBYTE        Palette_Buf                    */
               0,                /* PBYTE        pBuffer                        */
               -1,               /* SHORT        nXGAin132ColConfig             */
               -1,               /* SHORT        nXGAinVGAConfig                */
               0L,               /* PLONG        DOSPTLinAddr                   */
               0L,               /* HLOCK        hlockDOSPT;                    */
               0,                /* INT          nApertureEnabled               */
               0L,               /* dmaReqInfo packet on VDHOpenVDD             */
               VXGAInt4BHandler, /* dmaReqInfo packet on VDHOpenVDD             */
               0L,               /* VDHMAPTARGET ApertSource[0] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPTARGET ApertSource[1] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPTARGET ApertSource[2] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPTARGET ApertSource[3] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPTARGET ApertSource[4] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPTARGET ApertSource[5] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPTARGET ApertSource[6] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPTARGET ApertSource[7] - vdhms_laddr   */
               0L,               /*                               vdhms_hobj    */
               0L,               /* VDHMAPSOURCE ApertTarget[0] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */
               0L,               /* VDHMAPSOURCE ApertTarget[1] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */
               0L,               /* VDHMAPSOURCE ApertTarget[2] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */
               0L,               /* VDHMAPSOURCE ApertTarget[3] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */
               0L,               /* VDHMAPSOURCE ApertTarget[4] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */
               0L,               /* VDHMAPSOURCE ApertTarget[5] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */
               0L,               /* VDHMAPSOURCE ApertTarget[6] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */
               0L,               /* VDHMAPSOURCE ApertTarget[7] - vdhmt_laddr   */
              16L,               /* 16 x 4096 pages               vdhmt_cpg     */
               0L,               /*                               vdhmt_hmap    */

               /*
               ** Initial Index Register shadow for abregXGAIRData[]
               ** in vXGARegs[].  See vdmdata_s structure for detail.
               */

               0x00,             /* 00h - reserved                              */
               0x00,             /* 01h - reserved                              */
               0x00,             /* 02h - reserved                              */
               0x00,             /* 03h - reserved                              */
               0x01,             /* 04h - auto-configuration           (R/O)    */
               0x00,             /* 05h - reserved                              */
               0x00,             /* 06h - reserved                              */
               0x00,             /* 07h - reserved                              */
               0x00,             /* 08h - reserved                              */
               0x00,             /* 09h - reserved                              */
               0x00,             /* 0Ah - reserved                              */
               0x00,             /* 0Bh - reserved                              */
               0x10,             /* 0Ch - coprocessor save/restore data A       */
               0x00,             /* 0Dh - coprocessor save/restore data B       */
               0x00,             /* 0Eh - reserved                              */
               0x00,             /* 0Fh - reserved                              */
               0x5f,             /* 10h - horizontal total lo                   */
               0x00,             /* 11h - horizontal total ho                   */
               0x4f,             /* 12h - horizontal display end lo             */
               0x00,             /* 13h - horizontal display end hi             */
               0x50,             /* 14h - horizontal blanking start lo          */
               0x00,             /* 15h - horizontal blanking start hi          */
               0x82,             /* 16h - horizontal blanking end lo            */
               0x00,             /* 17h - horizontal blanking end hi            */
               0x54,             /* 18h - horizontal sync pulse start lo        */
               0x00,             /* 19h - horizontal sync pulse start hi        */
               0x9c,             /* 1Ah - horizontal sync pulse end lo (132 Col)*/
               0x00,             /* 1Bh - horizontal sync pulse end hi (132 Col)*/
               0x00,             /* 1Ch - horizontal sync position     (W/O)    */
               0x00,             /* 1Dh - reserved                              */
               0x00,             /* 1Eh - horizontal sync position     (W/O)    */
               0x00,             /* 1Fh - reserved                              */
               0x0b,             /* 20h - vertical total lo                     */
               0x02,             /* 21h - vertical total hi                     */
               0xdf,             /* 22h - vertical display end enable lo        */
               0x03,             /* 23h - vertical display end enable hi        */
               0xe7,             /* 24h - vertical blanking start lo            */
               0x01,             /* 25h - vertical blanking start hi            */
               0x04,             /* 26h - vertical blanking end lo              */
               0x00,             /* 27h - vertical blanking end hi              */
               0xea,             /* 28h - vertical sync pulse start lo          */
               0x06,             /* 29h - vertical sync pulse start hi          */
               0x0c,             /* 2Ah - vertical sync pulse end      (132 Col)*/
               0x00,             /* 2Bh - reserved                              */
               0xff,             /* 2Ch - vertical line compare lo              */
               0x03,             /* 2Dh - vertical line compare hi              */
               0x00,             /* 2Eh - reserved                              */
               0x00,             /* 2Fh - reserved                              */
               0x01,             /* 30h - sprite horizontal start lo            */
               0x00,             /* 31h - sprite horizontal start hi            */
               0x20,             /* 32h - sprite horizontal preset              */
               0x00,             /* 33h - sprite vertical start lo              */
               0x00,             /* 34h - sprite vertical start hi              */
               0x00,             /* 35h - sprite vertical preset                */
               0x00,             /* 36h - sprite control                        */
               0x00,             /* 37h - reserved                              */
               0xfc,             /* 38h - sprite color 0 red                    */
               0xfc,             /* 39h - sprite color 1 green                  */
               0xfc,             /* 3Ah - sprite color 1 blue                   */
               0xfc,             /* 3Bh - sprite color 1 red                    */
               0xfc,             /* 3Ch - sprite color 1 green                  */
               0xfc,             /* 3Dh - sprite color 1 blue                   */
               0x00,             /* 3Eh - reserved                              */
               0x00,             /* 3Fh - reserved                              */
               0x00,             /* 40h - display pixel map offset lo           */
               0x00,             /* 41h - display pixel map offset mi           */
               0x00,             /* 42h - display pixel map offset hi           */
               0x28,             /* 43h - display pixel map width lo            */
               0x00,             /* 44h - display pixel map width hi            */
               0x00,             /* 45h - reserved                              */
               0x00,             /* 46h - reserved                              */
               0x00,             /* 47h - reserved                              */
               0x00,             /* 48h - reserved                              */
               0x00,             /* 49h - reserved                              */
               0x00,             /* 4Ah - reserved                              */
               0x00,             /* 4Bh - reserved                              */
               0x00,             /* 4Ch - reserved                              */
               0x00,             /* 4Dh - reserved                              */
               0x00,             /* 4Eh - reserved                              */
               0x00,             /* 4Fh - reserved                              */
               0xd3,             /* 50h - display control 1            (132 Col)*/
               0x00,             /* 51h - display control 2                     */
               0x6a,             /* 52h - display id and comparator    (R/O)    */
               0x30, /*LOOK LOOK    53h - mystery register read by AFI (R/O)    */
               0x00,             /* 54h - clock frequency select       (132 Col)*/
               0x00,             /* 55h - border color                          */
               0x00,             /* 56h - reserved                              */
               0x00,             /* 57h - reserved                              */
               0x00,             /* 58h - reserved                              */
               0x00,             /* 59h - reserved                              */
               0x00,             /* 5Ah - reserved                              */
               0x00,             /* 5Bh - reserved                              */
               0x00,             /* 5Ch - reserved                              */
               0x00,             /* 5Dh - reserved                              */
               0x00,             /* 5Eh - reserved                              */
               0x00,             /* 5Fh - reserved                              */
               0x10,             /* 60h - sprite/palette index lo               */
               0x2f,             /* 61h - sprite index hi                       */

               /*
               ** The following resgisters are NOT used on SAVE/RESTORE
               */

               0x00,             /* 62h - sprite/palette index lo (prefetch)    */
               0x00,             /* 63h - sprite index hi (prefetch)            */


               0xff,             /* 64h - palette mask                          */
               0x94,             /* 65h - palette data                          */
               0x01,             /* 66h - palette sequence                      */
               0x94,             /* 67h - palette red prefetch                  */
               0x94,             /* 68h - palette green prefetch                */
               0x94,             /* 69h - palette blue prefetch                 */
               0x00,             /* 6Ah - sprite data                           */
               0xc0,             /* 6Bh - sprite prefetch                       */
               0x00,             /* 6Ch - reserved                              */
               0x00,             /* 6Dh - reserved                              */
               0x00,             /* 6Eh - reserved                              */
               0x00,             /* 6Fh - reserved                              */
               0x7f,             /* 70h - external clock select        (132 Col)*/

               /*
               ** End of Index Register shadow
               */

               /*
               ** Initial I/O Register shadow values for abregXGAIOReg[]
               ** in vXGARegs[].  See vdmdata_s structure for detail.
               */

               0x04,             /* 00h - operating mode                        */
               0x00,             /* 01h - aperture control                      */
               0x00,             /* 02h - reserved                              */
               0x00,             /* 03h - reserved                              */
               0x00,             /* 04h - interrupt enable                      */
               0x00,             /* 05h - interrupt status                      */
               0x05,             /* 06h - virtual memory control                */
               0x00,             /* 07h - virtual memory interrupt status       */
               0x20,             /* 08h - aperture index                        */
               0x00,             /* 09h - memory access                         */
               0x00,             /* 0Ah - index select                          */
               0x00,             /* 0Bh - index data                            */
             };


#pragma  END_SWAP_INSTANCE
#pragma  BEGIN_INIT_CODE

/***************************************************************************
 *
 * FUNCTION NAME = VDDInit()
 *
 * DESCRIPTION   = VXGA 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)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * PSEUDO-CODE
 *                 verify existence of physical hardware
 *                 install event hooks (creation)
 *                 install event hooks (termination)
 *                 install event hooks (background switching)
 *                 install event hooks (foreground switching)
 *                 install event hooks (page fault handling)
 *                 Install User hook for map/Unmap
 *                 Register for I/O trapping Advanced Property
 *                 Register as a co-primary Video VDD
 *
 ****************************************************************************/

BOOL EXPENTRY VDDInit(PSZ psz)
{
  register INT i;
  register INT j;

/* BOOL fSuccess = TRUE;                                                    */

   ULONG ROM_add_rec[16] = { 0xc0000, 0xc2000, 0xc4000, 0xc6000,
                             0xc8000, 0xca000, 0xcc000, 0xce000,
                             0xd0000, 0xd2000, 0xd4000, 0xd6000,
                             0xd8000, 0xda000, 0xdc000, 0xde000 };

   /*
   ** Monitor ID table
   */

   BYTE Monitor_Table[] = { 0x0,            /* 0000                      */
                            0x0,            /* 0001                      */
                            0x0,            /* 0010                      */
                            0x0,            /* 0011                      */
                            0x0,            /* 0100  5081                */
                            0x0,            /* 0101  Buffalo             */
                            0x0,            /* 0110                      */
                            0x0,            /* 0111  Boston              */
                            0x0,            /* 1000                      */
                            0x0B,           /* 1001  8604, 8507          */
                            0x09,           /* 1010  8514                */
                            0x0C,           /* 1011  8515 (Dallas)       */
                            0x0,            /* 1100                      */
                            0x03,           /* 1101  8503                */
                            0x04,           /* 1110  8513, 8512          */
                            0x0};           /* 1111  No monitor attached */

   /*
   ** Monitor preference table, ordered by Display Resolution/Quality
   ** This table is indexed using the Monitor ID subscript.
   */

   BYTE Mon_XlatTable[] = { 0x0,            /* Not Supported */
                            0x0,            /* Not Supported */
                            0x0,            /* Not Supported */
                            0x1,            /* 8503 */
                            0x2,            /* 8513, 8512 */
                            0x0,            /* Not Supported */
                            0x0,            /* Not Supported */
                            0x0,            /* Not Supported */
                            0x0,            /* Not Supported */
                            0x4,            /* 8514 */
                            0x0,            /* Not Supported */
                            0x3,            /* 8604, 8507 */
                            0x5,            /* 8515 (Dallas) */
                            0x0,            /* Not Supported */
                            0x0,            /* Not Supported */
                            0x0};           /* Not Supported */

   /*
   ** Operating Mode Register (Address 21x0) Display Mode set for each XGA
   */

   SHORT IORegDisplayMode[XGA_INSTANCES] = { -1, -1, -1, -1, -1, -1, -1, -1 };


  USHORT ipdata;                       /* *******************************   */
  UCHAR ip_byte;                       /* Temporary local storage vars      */
  USHORT index;                        /* *******************************   */
  USHORT xga_index = 0;
  USHORT cop_instance;
  UCHAR card_slot_setting;
  USHORT pos_id;
  SHORT previous_config = -1;
  USHORT prev_value;                   /* save original value               */
  USHORT machinetype;                  /* family type indicator             */

 /*
 ** begin XGA init code
 */
// INT3();
  /*
  ** Assume 1 Meg adapter configuration unless we found otherwise
  */

  npgBufferMax = PAGESFROMBYTES(MAX_VRES *MAX_HRES *nPlanes/8);
  DISABLE();
  planar_setting = INB(PORT_PLANAR);
  card_slot_setting = INB(PORT_SLOT);  /* read card slot setting            */

  machinetype = (USHORT)VDHQuerySysValue(CURRENT_VDM, VDHGSV_MACHINETYPE);

  for (i = PLANAR; i < MAX_SLOT; i++)
  {

    DISABLE();

    if (i == PLANAR)
    {
      OUTB(PORT_PLANAR,
           PORT_SETUP_MODE);           /* planar into setup mode            */
    }

    else
    {
      OUTB(PORT_SLOT,
           (UCHAR)i);                  /* card into setup mode              */
    }
    pos_id = inpw(PORT_POS_ID);

    /***                                                                  ***/
    /*   if the pos_id not found, then query family 1 types by              */
    /*   using 108-10f to enable pos registers                              */
    /***                                                                  ***/

    if ((i > PLANAR) &&                /* ignore planar config              */
        (machinetype != MACHINE_TYPE_PS2) && /* only for family 1           */
        ((pos_id > XGA_ID_UPPER) ||    /* didn't find XGA                   */
         (pos_id < XGA_ID_LOWER)))     /*                                   */
    {

      /* next instruction does not compile properly so switch               */
      /* to assembler                                                       */
      /* prev_value = INB(PORT_POS_ID+i);     save original value           */
       _asm
       {
          mov     edx,i
          add     dx,0100h
          in      ax,dx
          mov     prev_value,ax
       }

       OUTB(PORT_POS_ID+i,(UCHAR)i);   /* enable family 1 pos reg           */
       pos_id = inpw(PORT_POS_ID);     /* get hardware ID                   */
    }

    if (pos_id <= XGA_ID_UPPER && pos_id >= XGA_ID_LOWER)
    {                                  /* XGA on card                       */
      nNumConfig++;
      xga_index = (((USHORT)INB(POS_BASE_ADDRESS+2)&0x0e) >> 1);

      /*
      ** determine the 1st and last configuration index value to
      ** facilitate XGAENV[] search
      */

      if (xga_index < nConfigStart)
      {
        nConfigStart = xga_index;
      }

      if (xga_index > nConfigEnd)
      {
        nConfigEnd = xga_index;
      }

      /*
      ** determine IO Register base address
      */

      XGAENV[xga_index].IORegBase = (((USHORT)INB(POS_BASE_ADDRESS+2)&0x0e) <<
         3)+0x2100;

      /*
      ** get the Auto_Conifiguration, Display ID and DAC Comparartor,
      ** Display Control 1, External Clock Select,          
      ** AND THE MYSTERY REGISTER USED BY THE AFI FOR THE PURPOSE OF
      ** SETTING UP THE INITIAL SHADOW VALUE FOR EACH XGA
      */

      OUTB(XGAENV[xga_index].IORegBase+AXGA_INDEX_SELECT,
           AINDX_AUTOCONFIG);
      XGAENV[xga_index].Auto_Config = INB(XGAENV[xga_index].IORegBase+
         AXGA_INDEX_DATA_B);
      OUTB(XGAENV[xga_index].IORegBase+AXGA_INDEX_SELECT, /*                */
           AINDX_DISPCONTROL1);        /*                                   */
      XGAENV[xga_index].Display_Control1 = /*                               */
         INB(XGAENV[xga_index].IORegBase+AXGA_INDEX_DATA_B);/*              */
      OUTB(XGAENV[xga_index].IORegBase+AXGA_INDEX_SELECT,
           AINDX_DISPIDCOMPARATOR);
      XGAENV[xga_index].Monitor_ID_DAC_Comp = INB(XGAENV[xga_index].IORegBase+
         AXGA_INDEX_DATA_B);
      XGAENV[xga_index].Monitor_type = Monitor_Table[XGAENV[xga_index].
         Monitor_ID_DAC_Comp&0x0f];

      OUTB(XGAENV[xga_index].IORegBase+AXGA_INDEX_SELECT,
           AINDX_RESERVED5b);                                  /*           */
      XGAENV[xga_index].Misc_Control1 =
         INB(XGAENV[xga_index].IORegBase+AXGA_INDEX_DATA_B);   /*           */

      OUTB(XGAENV[xga_index].IORegBase+AXGA_INDEX_SELECT,
           AINDX_MYSTERYREG);

      /*
      ** allow AFI to load on back level XGA adapters
      */

      if ((ipdata = INB(XGAENV[xga_index].IORegBase+AXGA_INDEX_DATA_B)) < 0x30
         )
        ipdata = 0x30;
      XGAENV[xga_index].Mystery_Reg = ipdata;
      OUTB(XGAENV[xga_index].IORegBase+AXGA_INDEX_SELECT, /*                */
           AINDX_EXTCLOCKSELECT);      /*                                   */
      XGAENV[xga_index].External_Clock_Select = /*                          */
         INB(XGAENV[xga_index].IORegBase+AXGA_INDEX_DATA_B);/*              */

      /*
      ** record the bootup XGA in VGA mode if one found
      */

/*    if (INB(XGAENV[xga_index].IORegBase)&0x01)                             */
/*      InitXGAinVGA = xga_index;                                            */

      IORegDisplayMode[xga_index] = (SHORT) (INB(XGAENV[xga_index].IORegBase)); /*           */
      if (IORegDisplayMode[xga_index] & 0x0001)                                 /*           */
        InitXGAinVGA = xga_index;                                               /*           */

      ENABLE();

      /*
      ** we must use the 64K aperture to determine VRAM size
      ** since the scheme must work on an SX system and the
      ** 1 Meg aperture may not always be there.
      */

      XGAENV[xga_index].OneMegAperture = /*                                 */
         ((ULONG)(INB(POS_BASE_ADDRESS+5)&0x0f) << 20);/*                   */

      if (vXGA64KcheckVRAM(XGAENV[xga_index].IORegBase))
      {                                /*                                   */

        if (i == PLANAR)
        {                              /*                                   */
          PRINTDEBUG("Found XGA Adapter on planar with 1 Mb\n");
        }

        else
        {                              /*                                   */
          PRINTDEBUGa("Found XGA Adapter on slot %d with 1 Mb\n", i-7);
        }
        XGAENV[xga_index].flVRAM_1Meg = TRUE;/*                             
                                                                            */
      }

      else
      {                                /*                                   */

        if (i == PLANAR)
        {                              /*                                   */
          PRINTDEBUG("Found XGA Adapter on planar with 0.5 Mb\n");
        }

        else
        {                              /*                                   */
          PRINTDEBUGa("Found XGA Adapter on slot %d with 0.5 Mb\n", i-7);
        }
      }

      /*
      ** calculate VRAM (4 meg aperture) Address
      */

      XGAENV[xga_index].VRAMAddr = ((ULONG)((char)INB(POS_BASE_ADDRESS+4)&0xfe
         )) << 8;
      XGAENV[xga_index].VRAMAddr |= ((ULONG)((USHORT)INB(POS_BASE_ADDRESS+2)
         &0x0e)) << 5;
      XGAENV[xga_index].VRAMAddr = XGAENV[xga_index].VRAMAddr << 16;

      /*
      ** get addressability to the XGA's VRAM
      */

      if (!(XGAENV[xga_index].pVRAMAddr = VDHAllocPages((PBVDM)XGAENV
         [xga_index].VRAMAddr,
                                                        npgBufferMax, /* 1
                                          Meg                               */
                                                        VDHAP_SYSTEM|
                                                        VDHAP_PHYSICAL)))
      {
        return  FALSE;
      }

      index = (INB(POS_BASE_ADDRESS+2) >> 4)&0xf;
      cop_instance = (INB(POS_BASE_ADDRESS+2) >> 1)&0x07;
      XGAENV[xga_index].ROMAddr = ROM_add_rec[index]+4096;
      XGAENV[xga_index].COPAddr = ROM_add_rec[index]+0x1c00+(128*cop_instance)
         ;

      /*
      ** Identify any duplicate ROM areas among XGAs and use the same
      ** pointer to address the linear address value
      */

      for (j = 0; j < XGA_INSTANCES; j++)/* chk prev valus                  */
      {

        if (j != xga_index)
        {

          if (XGAENV[j].IORegBase)     /* valid xga                         */
          {

            if (XGAENV[xga_index].ROMAddr == XGAENV[j].ROMAddr)
            {
              XGAENV[xga_index].DupROMAddr = 1;/* indic dup ROM            @*/
              XGAENV[xga_index].pCOPAllocAddr = XGAENV[j].pCOPAllocAddr;
              break;                   /* no need to look further           */
            }                          /* end if ROMAddr test               */
          }                            /* end if valid XGAENV               */
        }                              /* end j != xga_index                */
      }                                /* end for XGA_INSTANCES             */

      if (!XGAENV[xga_index].DupROMAddr)
      {
        if (!((PVOID)XGAENV[xga_index].pCOPAllocAddr =
                     VDHAllocPages((PVOID)XGAENV[xga_index].ROMAddr,
                                   (ULONG)PAGESFROMBYTES(4*1024),
                                   VDHAP_SYSTEM | VDHAP_PHYSICAL)))
        {
          /*
          ** Free previously obtained memory
          */

          for (j = 0; j < XGA_INSTANCES; j++)
          {

            if ((XGAENV[j].pCOPAllocAddr) && (!XGAENV[j].DupROMAddr))
              VDHFreePages((PBYTE)XGAENV[j].pCOPAllocAddr);
          }
          return  FALSE;
        }
      }

/*       XGAENV[xga_index].pCOPAddr += (cop_instance * 128 + 1024 * 3);     */
         /*
         ** assembler workaround for the above 'C' code
         */

         _asm
         {
            movzx  eax,cop_instance
            imul   eax,eax,128
            add    eax,3072
            movzx  esi,xga_index
            imul   esi,esi,TYPE XGAENV
            add    eax,dword ptr XGAENV[esi].pCOPAllocAddr
            mov    dword ptr XGAENV[esi].pCOPAddr,eax
         }

    }


    if (i == PLANAR)
      OUTB(PORT_PLANAR,
           planar_setting);            /* restore planar setting            */

    if (machinetype != MACHINE_TYPE_PS2)    /* value was changed            */
    {                                  /*                                   */
      OUTB(PORT_POS_ID+i,prev_value);  /* restore orig value                */
    }                                  /* end family1 test                  */

  }                                    /* end for i=planar; i<max_slot      */

  OUTB(PORT_SLOT,
       card_slot_setting);             /* restore card slot setting         */


  if (!nNumConfig)                     /* still no go so....                */
    return  FALSE;                     /* fail if no XGA found              */


  if (nNumConfig == 1)
  {

    /*
    ** if XGA found, initialize CurConfig
    */

    for (i = nConfigStart; i <= nConfigEnd; i++)
    {

      if (XGAENV[i].IORegBase)
      {
        CurConfig = (SHORT)((XGAENV[i].IORegBase&0x00ff) >> 4);
      }
    }
  }

  else
  {

    /*
    ** if XGA's found, initialize CurConfig
    */

    if (nNumConfig > 1)
    {

      /*
      ** based on monitor type (bypass power-up
      */

      for (i = nConfigStart; i <= nConfigEnd; i++)
      {

        if ((XGAENV[i].IORegBase) && (i != InitXGAinVGA))
        {                              /* skip power-up                     */

          if (previous_config != -1)
          {

            if (Mon_XlatTable[XGAENV[i].Monitor_type] > Mon_XlatTable[XGAENV
               [previous_config].Monitor_type])
            {
              CurConfig = (SHORT)((XGAENV[i].IORegBase&0x00ff) >> 4);
              previous_config = i;
            }
          }

          else
          {
            if (IORegDisplayMode[i] >= 1)            /* At least in VGA Mode             */
            {                                                               /*           */
              CurConfig = (SHORT)((XGAENV[i].IORegBase&0x00ff) >> 4);
              previous_config = i;       /* setup initially                  */
            }                                                               /*           */
          }
        }
      }
      /*
      ** Multiple XGA's found, ONLY one Display Monitor setup - does NOT set
      ** CurConfig above - Default CurConfig to InitXGAinVGA
      */
      if ((CurConfig == -1) && (XGAENV[InitXGAinVGA].IORegBase))
        CurConfig = (SHORT)((XGAENV[InitXGAinVGA].IORegBase&0x00ff) >> 4);
    }
  }
  ENABLE();

  /*
  ** Install user event hooks
  */

  VDHInstallUserHook(VDM_CREATE,
                     (PUSERHOOK)VXGACreate);
  VDHInstallUserHook(VDM_VDD_CREATE_DONE,
                     (PUSERHOOK)VXGACreateDone);/*                          */
  VDHInstallUserHook(VDM_FOREGROUND,
                     (PUSERHOOK)VXGASetFgnd);
  VDHInstallUserHook(VDM_BACKGROUND,
                     (PUSERHOOK)VXGASetBgnd);
  VDHInstallUserHook(VDM_TERMINATE,
                     (PUSERHOOK)VXGADestroy);
  VDHInstallUserHook(VDM_MEMORY_MAPPED_IN,
                     (PUSERHOOK)VXGAMapHndlr);
  VDHInstallUserHook(VDM_MEMORY_UN_MAPPED,
                     (PUSERHOOK)VXGAUnMapHndlr);

  /*
  ** Reserve the memory mapped register areas in physical & linear memory
  */

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {

    if (XGAENV[i].IORegBase)
    {
      XGAENV[i].MapTarget.vdhmt_cpg = 1L;/* map 4K area                     */

      if (!XGAENV[i].DupROMAddr)       /* not a duplicate ROM addr          */
      {
        VDHReservePages((PVOID)(XGAENV[i].ROMAddr-4096),
                        1L);
        VDHReservePages((PVOID)XGAENV[i].ROMAddr,
                        1L);           /* to map later                      */
      }
    }
  }

#ifdef   PROPERTIES

  VDHRegisterProperty(szPropIOTrap, /* property name                    */
                           NULL,       /* no help file                      */
                           0,          /* no help id                        */
                           VDMP_BOOL,  /* type                              */
                           VDMP_ORD_OTHER, /* no ordinal                    */

      #ifdef OLD_PROPERTIES
                           0,          /* modifiable after creation         */

   #else
                           VDMP_CREATE, /* not modifiable after creation    */
   #endif
                           (VOID *)TRUE, /* default                         */
                           NULL,       /* validation info                   */

   #ifdef   OLD_PROPERTIES
                           VXGASetIOTrapping/* function                     */

   #else
       NULL                            /* no function                       */
   #endif
       );
//            return  FALSE;
#endif

  /*
  ** Register as a co-primary Video VDD
  */

  VDHRegisterVDD(VVD_NAME1,
                 VXGASysReqProc,
                 VXGADevReqProc);


  PRINTDEBUG("+------------------------------------------------------------------------+\n");
  PRINTDEBUG("| RAM|Base|VRAMAddr|pVRAMAddr|  1MegAp| ROMAddr| COPAddr|pCOPAddr|Monitor|\n");
  PRINTDEBUG("+------------------------------------------------------------------------+\n");


  for (i = 0; i < XGA_INSTANCES; i++)
  {

    if (XGAENV[i].IORegBase)
    {
      PRINTDEBUGa("|%01x ",   i );
      PRINTDEBUGc("%01x |",   (int) XGAENV[i].flVRAM_1Meg );
      PRINTDEBUGc("%04x|",    (int) XGAENV[i].IORegBase );
      PRINTDEBUGc("%08x| ",   (long)XGAENV[i].VRAMAddr );
      PRINTDEBUGc("%08x|",    (long)XGAENV[i].pVRAMAddr );
      PRINTDEBUGc("%08x|",    (long)XGAENV[i].OneMegAperture );
      PRINTDEBUGc("%08x|",    (long)XGAENV[i].ROMAddr );
      PRINTDEBUGc("%08x|",    (long)XGAENV[i].COPAddr );
      PRINTDEBUGc("%08x|   ", (long)XGAENV[i].pCOPAddr );
      PRINTDEBUGc("%04x|\n",  (int) XGAENV[i].Monitor_type );
    }
  }


  PRINTDEBUG("+------------------------------------------------------------------------+\n\n");

  PRINTDEBUGa("Total XGA(s): %d\n",nNumConfig);
  PRINTDEBUGa("Curconfig=%d\n",CurConfig);
  PRINTDEBUGa("InitXGAinVGA=%d\n",InitXGAinVGA);

  /*
  ** Adjust VRAM page size if the BEST configuration found
  ** is only 1/2 Meg
  */

  if (!XGAENV[CurConfig].flVRAM_1Meg)
  {
    npgBufferMax = npgBufferMax/2;
  }
  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGA64KcheckVRAM
 *
 * DESCRIPTION   = Check VRAM size
 *
 * INPUT         = ioPort
 *
 * OUTPUT        = TRUE      1 Meg VRAM
 *                 FALSE   < 1 Meg VRAM
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGA64KcheckVRAM(USHORT ioPort)/*                            */
{                                      /*                                   */
  BOOL OneMeg = TRUE;                  /* assume 1 Meg VRAM                 */
  BYTE PaletteMask;                    /* shadow data                       */
  BYTE VideoMode;                      /*                                   */
  BYTE VRAMaperture;                   /*                                   */
  BYTE ApertureIndex;                  /*                                   
                                                                            */


  if (!p64kVRAM)
  {                                    /*                                   */

    if (!(p64kVRAM = VDHAllocPages((PBVDM)VGA_VRAM_START, /*                */
                                   PAGESFROMBYTES(VGA_VRAM_LEN), /*
                                                                            */
                                   VDHAP_SYSTEM|VDHAP_PHYSICAL)))/*
                                                                            */
      return  OneMeg;                  /*                                   */
  }                                    /*                                   */

  /*
  ** save all relevant register content before using A0000
  ** aperture to check VRAM size
  */

  VideoMode = INB(ioPort+AXGA_OPERATING_MODE);/*                            */
  VRAMaperture = INB(ioPort+AXGA_APERTURE_CONTROL);/*                       */
  ApertureIndex = INB(ioPort+AXGA_APERTURE_INDEX);/*                        */
  OUTB(ioPort+AXGA_INDEX_SELECT,
       AINDX_PALETTEMASK);             /*                                   */
  PaletteMask = INB(ioPort+AXGA_INDEX_DATA_B);/*                            
                                                                            */
  OUTB(ioPort+AXGA_INTERRUPT_ENABLE,
       0x00);                          /* disable interrupt                 */
  OUTB(ioPort+AXGA_INDEX_DATA_B,
       0x00);                          /* blank screen                      */
  OUTB(ioPort+AXGA_OPERATING_MODE,
       0x04);                          /* set ext. mode                     */
  OUTB(ioPort+AXGA_APERTURE_CONTROL,
       0x01);                          /* set A0000 apert.                  */
  OUTB(ioPort+AXGA_APERTURE_INDEX,
       0x0C);                          /* offset 768K                       
                                                                            */

  if (!vXGACheckVRAM(p64kVRAM))        /*                                   */
    OneMeg = FALSE;                    /*                                   
                                                                            */

  /*
  ** restore saved registers
  */
                                                                        /*          */

  OUTB(ioPort+AXGA_APERTURE_INDEX,
       ApertureIndex);                 /*                                   */
  OUTB(ioPort+AXGA_APERTURE_CONTROL,
       VRAMaperture);                  /*                                   */
  OUTB(ioPort+AXGA_OPERATING_MODE,
       VideoMode);                     /*                                   */
  OUTB(ioPort+AXGA_INDEX_DATA_B,
       PaletteMask);                   /*                                   
                                                                            */
  return  OneMeg;                      /*                                   */
}

#pragma  END_INIT_CODE
#pragma  BEGIN_SWAP_CODE

/***************************************************************************
 *
 * FUNCTION NAME = VXGACreate()
 *
 * 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 VXGASetFgnd grows the buffers, effectively
 *                 nothing happens, since they were already grown here; if
 *                 the VDM is being started in the background, then when
 *                 VXGASetBgnd 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 (ie, not enough memory)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL EXPENTRY VXGACreate(HVDM hvdm)
{
  register INT count;
  register INT i;

  PRINTDEBUG("*****  I am in CREATE \n");

/*  INT3();                                                                 */
  /*
  **                Allocate all per-VDM semaphores
  */

  /*
  ** Allocate MUX semaphore to notify PMShell of mode changes
  */

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

  /*
  ** Allocate MUX semaphore to serialize access to LIM table
  */

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

  /*
  ** Allocate EVENT semaphore to serialize I/O access to XGA
  */

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

  /*
  ** Allocate EVENT semaphore to serialize LIM memory processing
  */

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

  /*
  ** Allocate EVENT semaphore to serialize LIM memory processing
  */

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

  /*
  ** Allocate context hook handle
  */

  if (!(VDMData.hhookVDMFGContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                                 (PFNARM)VXGAVDMFGContext,
                                                 0)))
    return  FALSE;

  /*
  ** Allocate context hook handle
  */

  if (!(VDMData.hhookVDMBGContext = VDHAllocHook(VDH_CONTEXT_HOOK,
                                                 (PFNARM)VXGAVDMBGContext,
                                                 0)))
    return  FALSE;

  /*
  ** Allocate INT 10 context hook handle
  */

  if (!(VDMData.hhookInt10Context = VDHAllocHook(VDH_CONTEXT_HOOK,
                                                 (PFNARM)VXGAInt10Context,
                                                 0)))
    return  FALSE;

  /*
  ** Allocate INT 10 return hook handle
  */

  if (!(VDMData.hhookInt10Ret = VDHAllocHook(VDH_RETURN_HOOK,
                                             (PFNARM)VXGAInt10Return,
                                             0)))
    return  FALSE;

  /*
  ** Initialize shadow register buffers
  */

  VXGAInitRegs();

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

  VDMData.hvdmXGA = hvdm;
  VDMData.sgIDXGA = VDHQuerySysValue(hvdm,
                                     VDHLSV_SESSIONID);

  /*
  ** Query Advanced Properties
  */

#ifdef   PROPERTIES

  /*
  ** Obtain I/O trap property settings
  */

  if (VDHQueryProperty(szPropIOTrap))
#endif
       VDMData.flVDMXGA |= VDM_IOTRAPPED;

#ifdef   PROPERTIES

  /*
  ** Obtain INT 2F property settings
  */

  if (VDHQueryProperty(szPropInt2F))
    VDMData.flVDMXGA |= VDM_INT2F;
#endif

  /*
  ** Set device ownership
  */

  VDMData.flVDMXGA |= VDM_DEVOWNER;

  /*
  ** Allocate table for mapping LIM memory pages
  */

  if (VDMData.flVDMXGA&VDM_NOTDONE)    /* VDMDATA not set up yet            */
  {

    if (!vXGAInitMap(hvdm))            /* initialize setup for mappin       */
      return  FALSE;
  }

  /*
  ** Allocate buffer storage for VDM (LVB, Palette, Sprite, Co-pro State)
  */

  if (!vXGAGrowBuffer(hvdm))           /* get LVB, etc.                     */
    return  FALSE;

  /*
  ** Allocate storage for first VDM created                 *
  */

  if (!nNumVDM++)                      /* this is the first VDM             */
  {

    /*
    ** Allocate & Lock 4K Page Directory
    */

    if (!(XGAPDAddr = VDHAllocPages(NULL,
                                    1L,
                                    VDHAP_SYSTEM)))
      return  FALSE;

    /*
    ** Lock down Page Directory
    */

    if (!(XGAPDHandle = VDHLockMem(XGAPDAddr,
                                   4096,
                                   VDHLM_16M,                   /*          */
                                   &PGList,
                                   &NElements)))
      return  FALSE;

    XGAPDPhysAddr = PGList.pl_paddr;   /* save Pg Directory Physical Addr   */

    /*
    ** Initialize VRAM Page Table for each XGA instance
    */

    for (count = nConfigStart; count <= nConfigEnd; count++)
    {

      if (XGAENV[count].IORegBase)
      {
        vXGAInitPaging(&XGAENV[count]);/* init VRAM pg tbl                  */

        if (!XGAENV[count].VRAMPTAddr) /* allocate error                    */
          return  FALSE;
      }
    }
  }

  /*
  **        Install page fault hook for memory mapped registers
  */

  /*
  ** NOTE:  XGA ROM area is not reserved and mapped by the VBIOS VDD. we
  **        will break up the ROM area into 2 separate 4K-pages to be
  **        treated individually.  Initially both pages will be marked
  **        valid and the 2nd. page of ROM containing the memory mapped
  **        IO registers will be marked invalid, causing page faults to
  **        occur.
  **
  **        Since ROMAddr is the address of the 2nd. page of ROM, we need
  **        to adjust this value to reference the first ROM page.
  */

  for (count = nConfigStart; count <= nConfigEnd; count++)
  {

    if ((XGAENV[count].IORegBase) &&   /* make sure valid                   */
       (!XGAENV[count].DupROMAddr))    /* and not duplicate@                */
    {

      /*
      ** map the first page of ROM as valid physical area
      */

      XGAENV[count].MapSource.vdhms_laddr = XGAENV[count].
         MapTarget.vdhmt_laddr = (XGAENV[count].ROMAddr)-4096;
      XGAENV[count].MapTarget.vdhmt_hmap = 0L;/* initialize handle          */

      if (!VDHMapPages(&XGAENV[count].MapSource,
                       &XGAENV[count].MapTarget,
                       VDHMT_PHYSICAL))/* make page present                 */
        return  FALSE;                 /* exit if error                     */

      /*
      ** map the memory mapped register area as physically valid
      */

      XGAENV[count].MapSource.vdhms_laddr = XGAENV[count].
         MapTarget.vdhmt_laddr = XGAENV[count].ROMAddr;
      XGAENV[count].MapTarget.vdhmt_hmap = 0L;/* initialize handle          */
      VDHMapPages(&XGAENV[count].MapSource,
                  &XGAENV[count].MapTarget,
                  VDHMT_PHYSICAL);     /* make page present                 */

      /*
      ** map the memory mapped register area as invalid
      */

      VDHMapPages(&XGAENV[count].MapSource,
                  &XGAENV[count].MapTarget,
                  VDHMT_INVALID);      /* to enable pg faulting to occur    */

      if (!VDHInstallFaultHook(hvdm,
                               (PVOID)XGAENV[count].ROMAddr,
                               1L,
                               VXGAPgFaultHndlr,
                               VDHIFH_ADDR))
      {

        for (i = nConfigStart; i <= count; i++)
        {

          if ((XGAENV[i].IORegBase) && /* make sure valid                   */
             (!XGAENV[i].DupROMAddr))  /* and not duplicate@                */
            VDHRemoveFaultHook(hvdm,
                               (PVOID)XGAENV[count].ROMAddr,
                               1L,
                               VXGAPgFaultHndlr);/* remove prev hooks       */
        }
        return  FALSE;                 /* fail creation                     */
      }
    }
  }

  /*
  ** Indicate fault hooks were installed for removal by destroy
  */

  VDMData.flVDMXGA |= VDM_HOOKED;
  vXGALockIO(hvdm);                    /* claim the IOOWNED bit             */
  vXGASetIOHooks();                    /* install all I/O handlers          */

  /*
  ** Get VGA VDD handle, so that we can post video events to it
  */

  if (!hvddVideo)
  {                                    /*                                   */
    hvddVideo = VDHOpenVDD(VVD_NAME1);

    /*
    ** register INT 2F notifications
    */

    VDHRegisterInt2FProc((VDHVVD_NOTIFY_ON_OFF|/*                           */
       VDHVVD_NOTIFY_START|            /*                                   */
       VDHVVD_NOTIFY_END),             /*                                   */
                         VXGAInt2FHandler);/*                               */

    /*
    ** Tell VVGA we are here now                                            
    */

    VDHRequestVDD(hvddVideo,                                    //          
                  hvdm,                                         //          
                  VVDDEVREQ_XGAPRESENT,                         //          
                  (PVOID)TRUE,                                  //          
                  NULL);                                        //          
  }                                    /*                                   */

  /*
  ** Establish communication with virtual DMA driver                        
  ** and pass entry point to receive Int4B notifications                    
  */

  if (!hvddDma)                                                 //          
  {                                                             //          
    hvddDma = VDHOpenVDD(VDMA_NAME);                            //          

    if (hvddDma)                                                //          

      if (!VDHRequestVDD(hvddDma,                               //          
                         hvdm,                                  //          
                         VDMA_REGISTER_VXGA,                    //          
                         &VDMData.dmaReqInfo,                   //          
                         NULL))                                 //          
        hvddDma = NULL;                                         //          
  }                                                             //          

  return  TRUE;                        /* all done -- time to boogie        */
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAInitRegs()
 *
 * DESCRIPTION   = VDM shadow register initialization
 *
 *                 This subroutine is called each time a new VDM is created
 *                 for the purpose of initializing the shadow register
 *                 buffer for each XGA.
 *
 *                 By doing so, we will be able to achieve a bit more
 *                 virtualizing by not blocking a VDM when it attempts to
 *                 query the content of an I/O Reigster.
 *
 *INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY VXGAInitRegs()
{
  register INT i;
  register USHORT  ioPort;                              /*           */

  /*
  ** Setup shadow data for each valid XGA in VGA mode
  ** and also initialize the R/O register values
  */

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {

    if (XGAENV[i].IORegBase)
    {                                  /* valid XGA configuration           */
      VDMData.vXGARegs[i] = VDMData.vXGARegs[0];
      VDMData.vXGARegs[i].abregXGAIRData[AINDX_AUTOCONFIG] = XGAENV[i].
         Auto_Config;
      VDMData.vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1] = /*
                                                                            */
         XGAENV[i].Display_Control1;   /*                                   */
      VDMData.vXGARegs[i].abregXGAIRData[AINDX_DISPIDCOMPARATOR] = XGAENV[i].
         Monitor_ID_DAC_Comp;
      VDMData.vXGARegs[i].abregXGAIRData[AINDX_MYSTERYREG] = XGAENV[i].
         Mystery_Reg;
      VDMData.vXGARegs[i].abregXGAIRData[AINDX_EXTCLOCKSELECT] = /*
                                                                            */
         XGAENV[i].External_Clock_Select;

      VDMData.vXGARegs[i].abregXGAIRData[AINDX_RESERVED5b] =
         XGAENV[i].Misc_Control1;                              /*           */
    }
  }

  if (InitXGAinVGA)                    /*                                   */

  /* Begin           */
  {
    /*
    **  If coming from 132 Column Mode, then reset the XGA Registers
    **  (Clock Frequency Select, External Clock Select, Vertical Pulse
    **  Pulse End, and Operating Mode Registers) and corresponding
    **  Shadow Register Values to VGA Mode.
    */
    ioPort = XGAENV[InitXGAinVGA].IORegBase;      /* Get XGA I/O Base Addr.  */
    if (INB(ioPort) == 0x03) {                    /* If 132 Column Mode.     */
       OUTW(ioPort+INDEX_SELECT,                  /* Set Clock Frequency     */
            (0x04 << 8) | AINDX_CLOCKFREQSELECT); /*  for VGA Mode.          */
       VDMData.vXGARegs[InitXGAinVGA].
               abregXGAIRData[AINDX_CLOCKFREQSELECT] = 0x04;
       OUTW(ioPort+INDEX_SELECT,                  /* Set External Clock      */
            (0x00 << 8) | AINDX_EXTCLOCKSELECT);  /*  for VGA Mode.          */
       VDMData.vXGARegs[InitXGAinVGA].
               abregXGAIRData[AINDX_EXTCLOCKSELECT] = 0x00;
       OUTW(ioPort+INDEX_SELECT,                  /* Set Vert Sync Pulse     */
            (0x20 << 8) | AINDX_VERTSYNCPULSEEND);/*  End for VGA Mode.      */
       VDMData.vXGARegs[InitXGAinVGA].
               abregXGAIRData[AINDX_VERTSYNCPULSEEND] = 0x20;
       OUTB(ioPort, 0x01);                        /* Set Oper Reg to VGA Mode*/
    }
    VDMData.vXGARegs[InitXGAinVGA].abregXGAIOReg[0] = 1;/*                  */
  }
  /* End             */
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGACreateDone()
 *
 * DESCRIPTION   = VDM creation completed notification
 *
 *                 This registered subroutine is called when all VDDs in the
 *                 system have completed their creation routines.
 *
 *                 At this time, the XGA VDD will review the 640K area to
 *                 include those areas that were not mapped by the other VDDs
 *                 to ensure locking of the 640K DOS region when an XGA
 *                 applciation is started.
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = SUCCESS
 *                     TRUE (new VDM accepted)
 *                 FAILURE
 *                     FALSE (ie, not enough memory)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID EXPENTRY VXGACreateDone(HVDM hvdm)
{
  TBLMAP_S *Tblptr;
  TBLMAP_S *Tblptr2;
  TBLMAP_S TblptrTemp;
  ULONG Tempaddr = 0;
  ULONG p;
  INT i;
  INT j;
  register PVDMDATA pvd = pVDMData(hvdm);

  PRINTDEBUG("*****  I am in vXGACreateDone \n");

  /*
  ** Add all 640K to the map table if there were no entries mapped
  ** during create time
  */

  if (!pvd->TblEntriesPresent)         /* no entries in table               */
  {
    VXGAMapHndlr(0,
                 0,
                 160,
                 VDHMT_PHYSICAL);      /* all 640K to be mapped             */
    return ;                           /* git out of here                   */
  }

  /*
  ** Sort the entries in the table to determine what's missing in the
  ** 640K DOS region.  Sort in ascending order, using a BUBBLE sort.
  */

  Tblptr = pvd->TblMap;                /* set to start of map table         */
  Tblptr2 = pvd->TblMap;               /* set to start of map table         */

  for (i = 0; i < pvd->TblEntriesPresent-1; i++)/* for all entries          */
  {

    for (j = i+1; j < pvd->TblEntriesPresent; j++)/* for those lower        */
    {
      Tblptr2++;

      if (Tblptr->MapAddr > Tblptr2->MapAddr)
      {
        TblptrTemp = *Tblptr2;
        *Tblptr2 = *Tblptr;
        *Tblptr = TblptrTemp;
      }
    }
    Tblptr++;
    Tblptr2 = Tblptr;
  }

  /*
  ** Verify whether any region under 640K was mapped
  */

  Tblptr = pvd->TblMap;                /* set to start of map table         */

  if ((ULONG)Tblptr->MapAddr >= 0xa0000)/* nothing under 640K mapped        */
  {
    VXGAMapHndlr(0,
                 0,
                 160,
                 VDHMT_PHYSICAL);      /* map all 640K                      */
    return ;                           /* git out of here                   */
  }

  /*
  ** Now scan through rest of table to add addresses below 640K that
  ** were left out
  */

  j = pvd->TblEntriesPresent;          /* obtain #entries in table          */

  for (i = 0; i < j; i++)              /* for current #entries in table     */
  {
    p = PAGESFROMBYTES((ULONG)Tblptr->MapAddr-Tempaddr);/* calc #pgs        */

    if (p)                             /* something to map                  */
      VXGAMapHndlr(0,
                   Tempaddr,
                   p,
                   VDHMT_PHYSICAL);    /* add addr to table                 */
    (PBYTE)Tempaddr = (Tblptr->MapAddr+(Tblptr->MapPages *4096));
    Tblptr++;                          /* next mapped entry                 */

    if ((ULONG)Tblptr->MapAddr >= 0xa0000)/*                     @INTBL>640K*/
      break;                           /* exit loop                         */
  }

  /*
  ** Add whatever is necessary to get all 640K
  */

  if (Tempaddr < 0xa0000)              /* still need to add more entries    */
  {
    p = PAGESFROMBYTES(0xa0000-Tempaddr);/* calculate #pages                */
    VXGAMapHndlr(0,
                 Tempaddr,
                 p,
                 VDHMT_PHYSICAL);      /* last of 640K area                 */
  }
  pvd->flVDMXGA |= VDM_640KMAPPED;     /*                                   */
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGASetFgnd()
 *
 * DESCRIPTION   = VDM foreground notification routine
 *
 *                 This routine is registered at VDD init time through
 *                 VDHInstallUserHook.  It is called each time a VDM is
 *                 switched to foreground.  The main responsibility of this
 *                 routine is to determine whether to let the VDM handle its
 *                 own RESTORE or allow the VDD do it.  Any XGA interrupts
 *                 pending at this point will be asserted.
 *
 * INPUT         = hvdm -> new foreground VDM handle
 *
 * OUTPUT        =
 *                 None
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL EXPENTRY VXGASetFgnd(register HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  XGAENV_S *pXGAENV = &XGAENV[CurConfig];
  register INT i;

/*  INT3();                                                                 */
  /*
  ** If we own the device and the VDM is not foreground
  */

  if (pvd->flVDMXGA&VDM_DEVOWNER && !vdhBTS(&pvd->flVDMXGA,
                                            LOG2(VDM_FGND)))
  {
    if (pvd->flVDMXGA&VDM_GOINGDOWN) {  /* 80034 - retn if VDM being killed */
       return TRUE;                     /* 80034 */
    }                                   /* 80034 */

    /*
    ** Indicate restore in progress
    */

    glVDMXGA |= VDM_RESTORE;

    /*
    ** serialize access to the video state
    */

    RequestMutexSem(pvd->hmxXGAState); /*                                   */
    PRINTDEBUGa("***** Foreground  device owner, VDM data %x\n",
               pVDMData(hvdm));

    /*
    ** Restore the 1st 132 column configuration
    */

    vXGASaveRestore132(hvdm);

    /*
    ** if the XGA I/O registers were altered
    */

    if (pvd->flVDMXGA&VDM_IOINIT)
    {

      /*
      ** Indicate which XGA to really restore
      */

      if (pvd->nSaveRestoreConfig != -1)
      {                                /* memory mapped regs touched        */
        pXGAENV = &XGAENV[pvd->nSaveRestoreConfig];
      }

      /*
      ** if I/O trapping enabled
      */

      if (pvd->flVDMXGA&VDM_IOTRAPPED)
      {

      /*
      ** Turn the screen off while we're updating things
      */

        vXGAVideoEnable(hvdm,
                        pXGAENV,
                        FALSE);

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

        if (vXGATransferBuffer(hvdm,
                               pXGAENV,
                               TRUE))
        {
          return (FALSE);
        }

        /*
        ** Update sprite, palette, and coprocessor state
        */

        vXGAVideoState(hvdm,
                       pXGAENV);

        /*
        ** unsuspend the coprocessor
        */
/*           pXGAENV->pCOPAddr->CopCntrl &= 0x00;                           */

      }

      /*
      ** restore I/O registers
      */

      vXGASaveRestoreIOReg(hvdm,
                           pXGAENV);
    }

    /*
    ** allow pre INT 2F notification to change I/O access
    */

    if (!(pvd->flVDMXGA&VDM_INT2F))
    {                                  /*                                   */

      /*
      ** Allow the VDM to party direct on I/O registers
      ** and the entire VDM memory space now
      */

      if (!vdhBTS(&pvd->flVDMXGA,
                  LOG2(VDM_FG_CONTEXTHOOK)))
        VDHArmContextHook(pvd->hhookVDMFGContext,
                          hvdm);
    }

       /*
       ** assert all pending interrupts
       */
/*     for (i=1; i <= (pvd->nNumPending); i++ )                             */
/*     {                                                                    */
/*        vXGAIntHandler();                                                 */
/*     }                                                                    */
    /*
    ** release the IOOWNED bit, and thaw VDM if frozen
    */

    vXGAUnlockIO(hvdm);

    /*
    ** if VDM previously blocked in the background...
    */

    if (vdhBTR(&pvd->flVDMXGA,
               LOG2(VDM_BLOCKED)))
    {

      /*
      ** convey to the Shield that the VDM is no longer suspended
      */

      vXGAUpdateShieldState(hvdm);
    }
    ReleaseMutexSem(pvd->hmxXGAState); /*                                   */
  }
  PRINTDEBUGa("***** Foreground  not device owner, VDM data %x\n",
             pVDMData(hvdm));
  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGALockVDM()
 *
 * DESCRIPTION   = VDM lock/unlock routine
 *
 *                 This routine is called to lock/unlock the VDM's entire
 *                 DOS region and any 'mapped-in' extended memory.  The
 *                 entire DOS region is contained within the map table and
 *                 will be automatically locked/unlocked when the entries in
 *                 the map table are locked/unlocked.
 *
 * INPUT         = hvdm -> VDM handle
 *                 lock == TRUE  (lock down VDM's 640K region)
 *                         FALSE (unlock VDM's 640K region)
 *
 * OUTPUT        = No Error  (0)
 *                 Error     (1)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGALockVDM(register HVDM hvdm,BOOL lock)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  TBLMAP_S *Tblptr = pvd->TblMap;     /* temp variable to track tbl entries */
  register INT i;
  register INT count = (pvd->TblEntries);
  PBYTE TempAddr;

  AssertNONZERO(Tblptr);

  /*
  ** if locking
  */

  if (lock)
  {
    PRINTDEBUG("***** lock memory\n");

    /*
    ** wait for mapping semaphore
    */

    RequestMutexSem(pvd->hmxXGAMapSem);

    /*
    ** lock "mapped-in" extended memory
    */

    while (count)
    {

      if ((Tblptr->MapAddr) && !(Tblptr->MapHandle))
      {
        TempAddr = Tblptr->MapAddr;

        if ((ULONG)TempAddr == -1L)    /* need to lock address 0            */
          TempAddr = 0;

        if (!(Tblptr->MapHandle = VDHLockMem(TempAddr,
                                             (Tblptr->MapPages *4096),
                                             VDHLM_16M,         /*          */
                                             (struct pagelist_s *)-1,
                                             (ULONG *)-1)))
        {
          PRINTDEBUGa("*****  Lock LIM Mem %08x ", TempAddr );
          PRINTDEBUGc("Fail- %x\n", VDHGetError());
        }
      }
      count--;
      Tblptr++;
      AssertNONZERO(Tblptr);
    }
    ReleaseMutexSem(pvd->hmxXGAMapSem);

    /*
    ** indicate entire vdm memory locked down
    */

    pvd->flVDMXGA |= VDM_LOCKED;

    /*
    ** if unlocking
    */

  }

  else
  {
    PRINTDEBUG("***** unlock memory\n");

    /*
    ** wait for mapping semaphore
    */

    RequestMutexSem(pvd->hmxXGAMapSem);

    /*
    ** unlock "mapped-in" extended memory
    */

    while (count)
    {

      if ((Tblptr->MapAddr) && (Tblptr->MapHandle))
      {
        VDHUnlockMem(Tblptr->MapHandle);
        Tblptr->MapHandle = 0;
      }
      count--;
      Tblptr++;
      AssertNONZERO(Tblptr);
    }
    ReleaseMutexSem(pvd->hmxXGAMapSem);

    /*
    ** unlock 640K DOS page table
    */

    if (pvd->hlockDOSPT)
    {
      VDHUnlockMem(pvd->hlockDOSPT);
      pvd->hlockDOSPT = 0;
    }

    /*
    ** indicate entire vdm memory unlocked
    */

    pvd->flVDMXGA &= ~VDM_LOCKED;
  }
  return 0;
}

#pragma  optimize      ("",off)        /*                                   */

/***************************************************************************
 *
 * FUNCTION NAME = vXGAInitHog()
 *
 * DESCRIPTION   = Setup the Coprocessor Memory I/O Registers for
 *                 data transfer using hardware Bitblt.
 *
 *                 Setup the Coprocessor Memory I/O Registers for
 *                 data transfer using hardware Bitblt.
 *
 *                 Pixel Operations Register (Offset 7Ch) definition:
 *
 *                   Bits 31-30 = Background Source
 *                        29-28 = Foreground Source
 *                        27-24 = Step function
 *                        23-20 = Source Pixel Map
 *                        19-16 = Destination Pixel Map
 *                        15-12 = Pattern Pixel Map
 *                        11-08 = Reserved
 *                        07-06 = Mask Pixel Map
 *                        05-04 = Drawing Mode
 *                           03 = Reserved
 *                        02-00 = Direction Octant
 *
 *                   Note:  Bitblt operations are initiated by writing
 *                          the Most Significant Byte (bits 24-31) at
 *                          offset 7Fh of the Pixel Operation register.
 *
 * INPUT         = hvdm -> VDM
 *                 p -> pixel map B
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAInitHog(HVDM hvdm,ULONG pMapB,XGAENV_S *pXGAENV)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  COP_S *pHog = pXGAENV->pCOPAddr;     /* coprocessor MMIO regs             */
  USHORT ioPort = pXGAENV->IORegBase;  /* I/O Base Register address         */

  /*
  ** disable Address Decode
  */

  OUTB((ioPort+0x06),
       (INB(ioPort+0x06)&0xfe));       /*                                   */

  /*
  ** clear Coprocessor Control Register
  */

  pHog->CopCntrl = 0x00;

  /*
  ** setup Pixel Map A
  */

  pHog->PixMapIndex = 0x01;

    /*
    ** Pixel Map A (VRAM) Base Address
    */

  pHog->PixMapBase = pXGAENV->VRAMAddr;

  /*
  ** Map A Dimensions (1024 x 1024 x 8 or 1024 x 1024 x 4)
  */

  pHog->PixMapWidth = 0x03FF;          /*                                   */
  pHog->PixMapHeight = 0x03FF;         /*                                   */
  pHog->PixMapFormat = 0x03;           /* pack the pixel(s) in 8 bits
                                                                            */

  /*
  ** setup Pixel Map B
  */

  pHog->PixMapIndex = 0x02;

  /*
  ** Pixel Map B (Stage Buffer) Base Address
  */

  pHog->PixMapBase = pMapB;

  /*
  ** Map B Dimensions (1024 x 32 x 8 or 1024 x 32 x 4)
  */

  pHog->PixMapWidth = 0x03FF;
  pHog->PixMapHeight = 0x001F;         /*                                   */
  pHog->PixMapFormat = 0x03;           /* pack the pixel(s) in 8 bits
                                                                            */

  /*
  ** setup Foreground and Background Mix
  */

  pHog->FgndMix = 0x03;                /* source                            */
  pHog->BgndMix = 0x03;                /* source                            */

  /*
  ** setup Destination Color Compare
  */

  pHog->DestColorCompCond = 0x04;      /* enable update                     */

  /*
  ** enable all bits per pixel subject to update
  */

  pHog->PixBitMask = -1;

  /*
  ** carry chain mask
  */

  pHog->CarryChainMask = 0x7F;

  /*
  ** foreground color
  */

  pHog->FgndColor = 0x00;

  /*
  ** background color
  */

  pHog->BgndColor = 0x00;

  /*
  ** width of draw (1024)
  */

  pHog->OpDimWidth = 0x03FF;

  /*
  ** heigth of draw
  */

  pHog->OpDimHeigth = 0x001F;          /*                                   */

  /*
  ** mask map origin x offset
  */

  pHog->MaskMapOriginX = 0x00;

  /*
  ** mask map origin y offset
  */

  pHog->MaskMapOriginY = 0x00;

  /*
  ** source x address
  */

  pHog->SourceMapX = 0x00;

  /*
  ** source y address
  */

  pHog->SourceMapY = 0x00;

  /*
  ** pattern x address
  */

  pHog->PatternMapX = 0x00;

  /*
  ** pattern y address
  */

  pHog->PatternMapY = 0x00;

  /*
  ** destination x address
  */

  pHog->DestMapX = 0x00;

  /*
  ** destination y address
  */

  pHog->DestMapY = 0x00;

  /*
  ** mask map disabled, draw all pixels, top left origin
  */

  pHog->PixOpLo = 0x9000;              /* pattern generated from source     */
}

#pragma  optimize      ("",on)         /*                                   */

/***************************************************************************
 *
 * FUNCTION NAME = vXGAWaitForCoProReady()
 *
 * DESCRIPTION   = Wait for coprocessor ready
 *
 *                 Waits until co-processor is in ready state
 *
 * INPUT         = pHog
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAWaitForCoProReady(register COP_S *pHog)
{

/*  register int count;                                                     */

  for (; ; )
  {                                    /*                                   */

    if (!(pHog->CopCntrl&0x80))
      break;

/*     count++;                                                             */

  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAVideoState()
 *
 * DESCRIPTION   = Save/Restore video state
 *
 *                 Save/Restore sprite, palette and coprocessor state.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAVideoState(HVDM hvdm,XGAENV_S *pXGAENV)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register INT i;
  PBYTE pSprite = pvd->Sprite_Buf,     /* sprite buffer pointer             */

     pPalette = pvd->Palette_Buf,      /* palette buffer pointer            */
     pState = pvd->State_Buf;          /* state buffer pointer              */

  COP_S *pHog = pXGAENV->pCOPAddr;     /* coprocessor MMIO regs             */

  AssertNONZERO(pSprite);
  AssertNONZERO(pPalette);
  AssertNONZERO(pState);

  /*
  ** disable sprite refresh
  */

  OUTW(pXGAENV->IORegBase+INDEX_SELECT,
       0x0036);

  /*
  ** if VDM going background
  */

  if (!(pvd->flVDMXGA&VDM_FGND))
  {

  /*
  ** save 64x64 sprite image - 2 bits per pixel (1024 bytes)
  */

    OUTW(pXGAENV->IORegBase+INDEX_SELECT,
         0x0061);                      /* sprite index HI                   */
    OUTW(pXGAENV->IORegBase+INDEX_SELECT,
         0x0062);                      /* sprite index LO                   */
    OUTB(pXGAENV->IORegBase+INDEX_SELECT,
         0x6A);                        /* sprite data index                 */

  /*
  ** save 1024 bytes of sprite data in groups of 4
  */

       _asm
       {
           mov    cx,((64*64*2)/8)/4         ;1024 bytes of sprite data
           mov    ebx,pXGAENV                ;setup pHog pointer
           mov    dx,word ptr [ebx].IORegBase;get Base IO Reg port
           add    dx,0Ch                     ;setup for 21xC for DWORD read
           mov    ebx,pSprite                ;
       ReadSprite:
           in     eax,dx                     ;read 16 pixels at a time
           mov    dword ptr [ebx],eax        ;save data in pSprite buffer
           add    ebx,4                      ;next DWORD
           dec    cx                         ;
           jnz    ReadSprite                 ;
       }

    /*
    ** save the 256 palette locations
    */

    vXGAGetPalette(hvdm);


     _asm
     {
         mov    ebx,pHog                   ;setup XGA memory mapped I/O addr
//            mov    byte ptr [ebx].CopCntrl,0Ah;   (already set)             ;          
         sub    cx,cx                      ;
         mov    cl,byte ptr [ebx].StateLenA;read coprocessor state length A
                                           ;
         mov    ebx,pXGAENV                ;
         mov    dx,word ptr [ebx].IORegBase;get the IO Reg Base address
         add    dx,INDEX_SELECT            ;setup for 21xA
         mov    al,0Ch                     ;
         out    dx,al                      ;select state length A register
                                           ;
         add    dx,0Ch-INDEX_SELECT        ;use 21xC for I/O
         mov    ebx,pState                 ;setup pState pointer
     ReadStateA:                           ;
         in     eax,dx                     ;read coprocessor state (DWORD)
         mov    dword ptr [ebx],eax        ;save the state in pState
         add    ebx,4                      ;next pState location
         dec    cx                         ;
         jnz    ReadStateA                 ;
         mov    pState,ebx                 ;save current pState location
                                           ;
         mov    ebx,pHog                   ;setup pHog pointer
         mov    cl,byte ptr [ebx].StateLenB;read coprocessor state length B
                                           ;
         mov    ebx,pXGAENV                ;
         mov    dx,word ptr [ebx].IORegBase;IO Reg Base address
         add    dx,INDEX_SELECT            ;setup for 21xA
         mov    al,0Dh                     ;
         out    dx,al                      ;select state length B register
                                           ;
         add    dx,0Ch-INDEX_SELECT        ;use 21xC for I/O
         mov    ebx,pState                 ;setup pState pointer
     ReadStateB:                           ;
         in     eax,dx                     ;read coprocessor state (DWORD)
         mov    dword ptr [ebx],eax        ;save the state in pState
         add    ebx,4                      ;next pState location
         dec    cx                         ;
         jnz    ReadStateB                 ;
     }

  }

  else
  {

    /*
    ** VDM is going foreground
    */
    /*
    ** wait for coprocessor request to complete.
    ** Make sure VRAM restore is all done.
    */

    vXGAWaitForCoProReady(pHog);                               /*           */

    i = INB(pXGAENV->IORegBase);       /* save adapter mode                 */

    /*
    ** set adapter to XGA mode
    */

    OUTB(pXGAENV->IORegBase,
         0x04);                        /*                                   */

    /*
    ** restore the 1024 byte sprite
    */

    OUTW(pXGAENV->IORegBase+INDEX_SELECT, 0x0061); /*                       */
    OUTW(pXGAENV->IORegBase+INDEX_SELECT, 0x0060); /*                       */
    OUTB(pXGAENV->IORegBase+INDEX_SELECT, 0x6A);

    /*
    ** restore 1024 bytes of sprite data in groups of 4
    */

       _asm
       {
           mov    cx,((64*64*2)/8)/4         ;1024 bytes of sprite data
           mov    ebx,pXGAENV                ;setup pHog pointer
           mov    dx,word ptr [ebx].IORegBase;get Base IO Reg port
           add    dx,0Ch                     ;setup for 21xC for DWORD write
           mov    ebx,pSprite                ;
       WriteSprite:                          ;
           mov    eax,dword ptr [ebx]        ;get 16 pixels from pSprite buffer
           out    dx,eax                     ;write 16 pixels at a time
           add    ebx,4                      ;next DWORD
           dec    cx                         ;
           jnz    WriteSprite                ;
       }

    /*
    ** restore the 256 palette locations
    */

    OUTW(pXGAENV->IORegBase+INDEX_SELECT,
         0x0060);

    /*
    ** R,B,G,x order
    */

    OUTW(pXGAENV->IORegBase+INDEX_SELECT,
         0x0466);
    OUTB(pXGAENV->IORegBase+INDEX_SELECT,
         0x0065);


       _asm
       {
           mov    ebx,pXGAENV                  ;setup pHog pointer
           mov    dx,word ptr [ebx].IORegBase  ;get Base IO port address
           add    dx,0Bh                       ;setup 21xB for DWORD write

           mov    cx,256                       ;sets of R,B,G,x palette values
           mov    ebx,pPalette                 ;setup pointer to pPalette buffer
      WritePalette:
           mov    eax,dword ptr [ebx]          ;get R,B,G,x valu from pPalette buff
           out    dx,eax                       ;write DWORD value to palette loc
           add    ebx,4                        ;next pPalette DWORD location
           dec    cx                           ;
           jnz    WritePalette                 ;
       }

    /*
    ** reset adapter to its previous mode **
    */

    OUTB(pXGAENV->IORegBase, i);         /*                                   */


     _asm
     {
         mov    ebx,pHog                   ;setup XGA memory mapped I/O addr
         mov    byte ptr [ebx].CopCntrl,08h;                               ;@V2.0  TPL16
         sub    cx,cx                      ;
         mov    cl,byte ptr [ebx].StateLenA;read coprocessor state length A
                                           ;
         mov    ebx,pXGAENV                ;
         mov    dx,word ptr [ebx].IORegBase;get the IO Reg Base address
         add    dx,INDEX_SELECT            ;setup for 21xA
         mov    al,0Ch                     ;
         out    dx,al                      ;select state length A register
                                           ;
         add    dx,0Ch-INDEX_SELECT        ;use 21xC for I/O
         mov    ebx,pState                 ;setup pState pointer
     WriteStateA:                          ;
         mov    eax, dword ptr [ebx]       ;get coprocessor state from pState
         out    dx,eax                     ;restore coprocessor state (DWORD)
         add    ebx,4                      ;next pState location
         dec    cx                         ;
         jnz    WriteStateA                ;
         mov    pState,ebx                 ;save current pState location
                                           ;
         mov    ebx,pHog                   ;setup pHog pointer
         mov    cl,byte ptr [ebx].StateLenB;read coprocessor state length B
                                           ;
         mov    ebx,pXGAENV                ;
         mov    dx,word ptr [ebx].IORegBase;IO Reg Base address
         add    dx,INDEX_SELECT            ;setup for 21xA
         mov    al,0Dh                     ;
         out    dx,al                      ;select state length B register
                                           ;
         add    dx,0Ch-INDEX_SELECT        ;use 21xC for I/O
         mov    ebx,pState                 ;setup pState pointer
     WriteStateB:                          ;
         mov    eax,dword ptr [ebx]        ;get coprocessor state from pState
         out    dx,eax                     ;Write coprocessor state (DWORD)
         add    ebx,4                      ;next pState location
         dec    cx                         ;
         jnz    WriteStateB                ;
     }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGATransferBuffer()
 *
 * DESCRIPTION   = Save/Restore video RAM
 *
 *                 Determine whether to use the coprocessor or the
 *                 system processor to save/restore the VRAM.  All
 *                 save requests, except for the initial VDM save,
 *                 will utilize the Dirty bit of the VRAM Page
 *                 Table to help reduce the amount of video data
 *                 transfered to/from the adapter.
 *
 *                 Note:  On a SAVE, the current VDM video state can
 *                        be obtained from the per VDM data area.
 *                        On a RESTORE, the I/O registers should have
 *                        been setup with the previous values prior
 *                        to entry into this routine.
 *
 *                        The private Page Directory and the VDM's
 *                        Page Table must remain locked down for
 *                        the duration of save/restore operations
 *                        just in case Coprocessor is used.
 *
 *                 Pixel Operations Register (Offset 7Ch) definition:
 *
 *                   Bits 31-30 = Background Source
 *                        29-28 = Foreground Source
 *                        27-24 = Step function
 *                        23-20 = Source Pixel Map
 *                        19-16 = Destination Pixel Map
 *                        15-12 = Pattern Pixel Map
 *                        07-06 = Mask Pixel Map
 *                        05-04 = Drawing Mode
 *                           03 = Reserved
 *                        02-00 = Direction Octant
 *
 *                   Note:  Bitblt operations are initiated by writing
 *                          the Most Significant Byte (bits 24-31) at
 *                          offset 7Fh of this register.
 *
 * INPUT         = hvdm   -> VDM
 *                 fWrite == TRUE (RESTORE)
 *                           FALSE (SAVE)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGATransferBuffer(HVDM hvdm,XGAENV_S *pXGAENV,BOOL fWrite)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  PVOID pRingBufLin;                   /* linear address to 64K buffer      */
  ULONG pBuffPhys;                     /* local copy of pRingBufPhys        */
  PBYTE pLVB,                          /* pointer to LVB                    */

     pApp;                             /* system memory apperture linear
                                          address                           */

  register INT i,count;                /* number of 32K/64K tranfers        */
  USHORT ioPort;                       /* I/O Base Register address         */
  BYTE DspCntl;                        /* Display Control 1                 */
  COP_S *pHog = pXGAENV->pCOPAddr;     /* coprocessor MMIO regs             */

  /*
  ** allocate the 64K stage buffer as required
  */

  if (!pRingBuffer && !hRingBuffer)
  {

  /*
  ** lock down buffer as required
  */

    if (pRingBuffer = VDHAllocPages(NULL,
                                    (ULONG)16,
                                    VDHAP_SYSTEM))/*                        */

      if (hRingBuffer = VDHLockMem(pRingBuffer, /*                          */
                                   (ULONG)(64*1024), /*                     */
                                   VDHLM_CONTIGUOUS|VDHLM_16M,  /*           31*/
                                   &PGList, /*                              */
                                   &NElements))/*                           */
        pRingBufPhys = PGList.pl_paddr;/*                                   */
  }                                    /*                                   */

  /*
  ** can we use Coprocessor to do save/restore?
  */

  if (hRingBuffer)                     /*                                   */
  {

    /*
    ** point to begining of ring buffer
    */

    pRingBufLin = pRingBuffer;         /*                                   */
    pBuffPhys = pRingBufPhys;          /* ring buffer physical address
                                                                            */
    AssertNONZERO(pRingBufPhys);

    /*
    ** point to begining of LVB
    */

    pLVB = pvd->pBuffer;
    AssertNONZERO(pLVB);

    /*
    ** terminate the coprocessor
    */

    pHog->CopCntrl = 0x20;
    vXGAWaitForCoProReady(pHog);

    /*
    ** initialize Coprocessor for save/restore
    */

    vXGAInitHog(hvdm,
                pRingBufPhys,
                pXGAENV);

    /*
    ** initialize count
    */

    if (pXGAENV->flVRAM_1Meg)
    {
      count = 32;
    }

    else
    {
      count = 16;
    }

    if (fWrite)                        /* ** VRAM restore **                */
    {

      /*
      ** copy 32K data from LVB to ring buffer
      */

      vdhMoveMem(pLVB,
                 pRingBufLin,
                 1,
                 1,
                 0x8000,
                 FALSE);               /*                                   */
      pLVB += 32768;

      /*
      ** initiate Coprocessor request to xfer 32k of data
      ** (1024 x 32) from ring buffer to VRAM
      */

      pHog->PixOpHi = 0xA821;          /* PxBlt from Pixel Map B to A       */

      /*
      ** for rest of the entire 1024 x 1024 LVB
      */

      for (i = 1; i < count; i++)
      {

        /*
        ** fixup pointer into ring buffer
        */

        if (pRingBufLin == pRingBuffer)/*                                   */
        {

          /*
          ** index 32K into ring buffer
          */

          (ULONG)pRingBufLin += 32768;
          pBuffPhys += 32768;          /*                                   */
        }

        else
        {

          /*
          ** point to begining of ring buffer
          */

          pRingBufLin = pRingBuffer;   /*                                   */
          pBuffPhys = pRingBufPhys;    /*                                   */
        }

        /*
        ** copy 32K data from LVB to ring buffer
        */

        vdhMoveMem(pLVB,
                   pRingBufLin,
                   1,
                   1,
                   0x8000,
                   FALSE);             /*                                   */
        pLVB += 32768;
        vXGAWaitForCoProReady(pHog);

        /*
        ** Select Map B **
        */

        pHog->PixMapIndex = 0x02;      /*                                   */

        /*
        ** change Map B Base Address...
        */

        pHog->PixMapBase = pBuffPhys;  /*                                   */

        /*
        ** Update source (Ring Buffer) X,Y offset...
        */

        pHog->SourceMapX = 0x00;       /*                                   */
        pHog->SourceMapY = 0x00;       /*                                   */

        /*
        ** and destination (VRAM) X,Y offset fixup
        */

        pHog->DestMapX = 0;
        pHog->DestMapY = (0x0020*i);

        /*
        ** initiate Coprocessor request to xfer 32k of data
        ** (1024 x 32) from ring buffer to VRAM
        */

        pHog->PixOpHi = 0xA821;        /* PxBlt from Pixel Map B to A       */
      }
    }

    else
    {

      /*
      ** save VRAM
      */

      /*
      ** initiate Coprocessor request to xfer 32k of data
      ** (1024 x 32) from VRAM to ring buffer
      */

      pHog->PixOpHi = 0xA812;          /* PxBlt from Pixel Map A to B       */

      if (pRingBufLin == pRingBuffer)  /*                                   */
      {

        /*
        ** index 32K into ring buffer
        */

        (ULONG)pRingBufLin += 32768;
        pBuffPhys += 32768;            /*                                   */
      }

      else
      {

        /*
        ** point to begining of ring buffer
        */

        pRingBufLin = pRingBuffer;     /*                                   */
        pBuffPhys = pRingBufPhys;      /*                                   */
      }

      /*
      ** for the rest of the entire 1024 x 1024 LVB
      */

      for (i = 1; i < count; i++)
      {
        vXGAWaitForCoProReady(pHog);

        /*
        ** Select Map B
        */

        pHog->PixMapIndex = 0x02;      /*                                   */

        /*
        ** Change Destination Base Address...
        */

        pHog->PixMapBase = pBuffPhys;  /*                                   */

        /*
        ** Update source (VRAM) X,Y offset...
        */

        pHog->SourceMapX = 0x00;
        pHog->SourceMapY = (0x0020*i);

        /*
        ** and destination (Ring Buffer) X,Y offset
        */

        pHog->DestMapX = 0x00;
        pHog->DestMapY = 0x00;

        /*
        ** initiate Coprocessor request to
        ** xfer data from VRAM to ring buffer
        */

        pHog->PixOpHi = 0xA812;        /* PxBlt from Pixel Map A to B       */

        if (pRingBufLin == pRingBuffer)/*                                   */
        {

          /*
          ** point to lower 32K of ring buffer
          */

          (ULONG)pRingBufLin += 32768;
          pBuffPhys += 32768;          /*                                   */
        }

        else
        {

          /*
          ** point to upper 32K of ring buffer
          */

          pRingBufLin = pRingBuffer;   /*                                   */
          pBuffPhys = pRingBufPhys;    /*                                   */
        }

        /*
        ** copy 32K data from ring buffer to LVB
        */

        vdhMoveMem(pRingBufLin,
                   pLVB,
                   1,
                   1,
                   0x8000,
                   FALSE);             /*                                   */
        pLVB += 32768;
      }

    /*
    ** wait for coprocessor request to complete.
    ** Make sure VRAM save is all done.
    */

      vXGAWaitForCoProReady(pHog);                             /*           */

      /*
      ** now copy last 32K chunk from ring buffer to the LVB
      */

      if (pRingBufLin == pRingBuffer)  /*                                   */
        (ULONG)pRingBufLin += 32768;   /*                                   */

      else                             /*                                   */
        pRingBufLin = pRingBuffer;     /*                                   */

      /*
      ** copy 32K data from ring buffer to LVB
      */

      vdhMoveMem(pRingBufLin,
                 pLVB,
                 1,
                 1,
                 0x8000,
                 FALSE);               /*                                   */
    }
  }

  else
  {

    /*
    ** Save/Restore through direct VRAM access
    */

    PRINTDEBUGa("*****  AllocPages/LockMem Fail- %x\n", VDHGetError());

/*     INT3();                                                              */
    /*
    ** use the 64k aperture VRAM pointer for save/restore
    */

    if (p64kVRAM)
    {                                  /*                                   */

      if (fWrite)                      /* restore request?                  */
      {                                /*                                   */
        i = pvd->nSaveRestoreConfig;   /*                                   */

        /*
        ** save the Display Control 1 register
        */

        DspCntl =                      /*                                   */
           pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1];/*
                                                                            */

        /*
        ** keep the display disable
        */

        pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1] &= 0xfc;
        pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1] |= 0x01;
      }                                /*                                   
                                                                            */
      ioPort = pXGAENV->IORegBase;     /*                                   
                                                                            */

      /*
      ** disable XGA interrupts, change to extended
      ** graphics mode, setup aperture at A0000h,
      ** setup aperture index to the 1st 64K
      */

      OUTB(ioPort+AXGA_INTERRUPT_ENABLE, 0x00); /*                          */
      OUTB(ioPort+AXGA_OPERATING_MODE, 0x04);   /*                          */
      OUTB(ioPort+AXGA_APERTURE_CONTROL, 0x01); /*                          */

      /*
      ** setup loop terminator for either 1/2 Meg or 1 Meg
      */

      count = (1024*512)/65536;        /* 1/2 Meg in 64K chunks             */

      if (pXGAENV->flVRAM_1Meg)        /* 1 Meg card?                       */
        count *= 2;                    /* make adjustment                   */

      if (fWrite)                      /* restore request?                  */
      {
        pLVB = pvd->pBuffer;           /* source = LVB                      */

        /*
        ** restore all the registers 1st
        */

        vXGASaveRestoreIOReg(hvdm,
                             pXGAENV);
        OUTB(ioPort+AXGA_APERTURE_CONTROL,
             0x01);                    /*                                   */

        /*
        ** copy 64K chunks
        */

        for (i = 0; i < count; i++)
        {
          OUTB(ioPort+AXGA_APERTURE_INDEX, i); /*                           */
          pApp = p64kVRAM;             /* destination = 64K aperture
                                                                            */
          vdhMoveMem(pLVB,
                     pApp,
                     1,
                     1,
                     65536,
                     FALSE);           /*                                   */
          pLVB += 65536;               /* next 64K chunk                    */
        }
        pvd->vXGARegs[pvd->nSaveRestoreConfig]./*                           */
           abregXGAIRData[AINDX_DISPCONTROL1] = DspCntl;
      }

      else
      {

        /*
        ** save VRAM
        */

        pApp = pvd->pBuffer;           /* destination = LVB                 */

        /*
        ** copy 64K chunks
        */

        for (i = 0; i < count; i++)
        {
          OUTB(ioPort+AXGA_APERTURE_INDEX, i); /*                           */
          pLVB = p64kVRAM;          /* destination = 64K aperture           */
          vdhMoveMem(pLVB,
                     pApp,
                     1,
                     1,
                     65536,
                     FALSE);           /*                                   */
          pApp += 65536;               /* next 64K chunk                    */
        }
      }
    }

    else
    {
      return  TRUE;                    /* error return                      */
    }
  }
  return  FALSE;                       /* normal return                     */
}

#pragma  optimize      ("",off)        /*                                   */

/***************************************************************************
 *
 * FUNCTION NAME = vXGACheckVRAM()
 *
 * DESCRIPTION   = Check for VRAM memory usage
 *
 *                 Determine whether the bank of VRAM memory is currently
 *                 being used by the VGA
 *
 * INPUT         = pVRAM -> VRAM memory pointer
 *
 * OUTPUT        = TRUE  = VRAM memory is being used
 *                 FALSE = VRAM memory is NOT being used
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGACheckVRAM(PBYTE pVRAM)
{
  BYTE Byte1;                          /*                                   */
  BYTE Byte2;                          /*                                   */

  /*
  ** read, write, verify aperture availability
  */

  Byte1 = *(pVRAM);                    /* save the 1st byte                 */
  Byte2 = *(pVRAM+16);                 /* save the 2nd byte                 */
  *(pVRAM) = 0x12;                     /* write 1st signature               */
  *(pVRAM+16) = 0x34;                  /*                                   */

  if ((*(pVRAM) == 0x12) &&            /* signature found?                  */
     (*(pVRAM+16) == 0x34))            /*                                   */
  {
    *(pVRAM) = Byte1;                  /* restore original values
                                                                            */
    *(pVRAM+16) = Byte2;               /*                                   */
    return  TRUE;                      /* indicate VRAM is in used          */
  }
  return  FALSE;                       /* indicate VRAM is available        */
}

#pragma  optimize      ("",on)         /*                                   */

/***************************************************************************
 *
 * FUNCTION NAME = vXGAVideoEnable()
 *
 * DESCRIPTION   = Enable or Disable video refresh
 *
 *                 Turn the display ON/OFF.
 *
 * INPUT         = hvdm -> VDM
 *                 enable == TRUE  (ON)
 *                           FALSE (OFF)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAVideoEnable(HVDM hvdm,XGAENV_S *pXGAENV,BOOL enable)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register UCHAR dspctrl;

  /*
  ** read display control 1 register, mask out the don't care bits
  ** and preset for video disable
  */

  OUTB(pXGAENV->IORegBase+INDEX_SELECT,
       0x50);
  dspctrl = ((INB(pXGAENV->IORegBase+INDEX_DATA)&0xfc)|0x01);

  /*
  ** if enable specified
  */

  if (enable)
  {
    dspctrl |= 0x02;
  }
  OUTB(pXGAENV->IORegBase+INDEX_DATA,
       dspctrl);
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAPDFixUp()
 *
 * DESCRIPTION   = VDM page directory fix-up routine
 *
 *                 This routine is called to update the current page
 *                 directory for the current task.
 *
 * INPUT         = hvdm -> VDM handle
 *
 * OUTPUT        = No Error  (0)
 *                 Error     (1)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGAPDFixUp(HVDM hvdm,XGAENV_S *pXGAENV)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  ULONG PDOffset;                      /* offset into page directory        */
  ULONG DOSPDEntry;                    /* value of DOS page directory entry
                                          physical addresses of...          */
  ULONG SysPDPhysAddr;                 /* system page directory             */
  ULONG DOSPTPhysAddr;                 /* DOS page table linear addresses
                                          of...                             */
  PLONG SysPDLinAddr;                  /* system page directory             */
  ULONG DOSEntryLinAddr;               /* DOS entry in system page
                                          directory                         */
  register INT i;
  TBLMAP_S *Tblptr = pvd->TblMap;      /* pointer to table map              */
  register INT count = (pvd->TblEntries);
  USHORT ioPort;                       /* XGA I/O port address              */

  AssertNONZERO(Tblptr);

  if (pvd->flVDMXGA&VDM_FGND)
  {                               /* is the VDM still foreground?           */

    /*
    ** get system page directory base address
    */

    _asm

    {
       push eax
       mov  eax, cr3                     ;Get address of system page directory
       mov  SysPDPhysAddr, eax
       pop  eax
    }

    /*
    ** get linear address of system page directory
    */

    if (!(SysPDLinAddr = (VDHAllocPages((PVOID)(SysPDPhysAddr),
                                        (ULONG)1,
                                        VDHAP_PHYSICAL+VDHAP_SYSTEM))))
    {
      PRINTDEBUGa("*****  AllocPages Fail- %x\n", VDHGetError());

/*  INT3();                                                                 */

      return 1;
    }

    else
    {

      /*
      ** get offset into page directory for VDM entry
      ** right adjust bits 22 - 31 * 4 = (>> 20 bits)
      */

      PDOffset = ((ULONG)hvdm >> 20);  /* preserve bits 22 - 31 (10 bits)   */
      DOSEntryLinAddr = (ULONG)SysPDLinAddr+PDOffset;

      /*
      ** get physical address of VDM page table
      */

      DOSPDEntry = *((PLONG)DOSEntryLinAddr);
      DOSPTPhysAddr = (DOSPDEntry&0xFFFFF000);

      /*
      ** get linear address of VDM page table
      */

      if (!pvd->DOSPTLinAddr)          /* none obtained yet                 */
        pvd->DOSPTLinAddr = (VDHAllocPages((PVOID)(DOSPTPhysAddr),
                                           (ULONG)1,
                                           VDHAP_PHYSICAL+VDHAP_SYSTEM));

      if (!pvd->DOSPTLinAddr)          /* error occurred                    */
      {

/*          INT3();                                                         */

        VDHFreePages(SysPDLinAddr);
        return 1;
      }

      else
      {

        /*
        ** lock down VDM page table
        */

        if (!pvd->hlockDOSPT)          /* DOS page table not locked down
                                                                            */
        {                              /*                                   */

          if (!(pvd->hlockDOSPT = VDHLockMem((PVOID)(pvd->DOSPTLinAddr),
                                             (ULONG)(4096),
                                             VDHLM_16M,         /*          */
                                             (struct pagelist_s *)-1,
                                             (ULONG *)-1)))
          {
            PRINTDEBUGa("*****  LockMem Fail- %x\n", VDHGetError());

/*             INT3();                                                      */

            VDHFreePages(SysPDLinAddr);
            VDHFreePages(pvd->DOSPTLinAddr);
            pvd->DOSPTLinAddr = 0;
            return 1;
          }
        }
      }
    }

    /*
    ** copy VDM page directory entry to extra page directory
    */

    *(PLONG)XGAPDAddr = *((PLONG)((ULONG)XGAPDAddr+PDOffset)) = DOSPDEntry;

    /*
    ** wait for mapping semaphore
    */

    RequestMutexSem(pvd->hmxXGAMapSem);

    /*
    ** copy extended memory page directory entries to extra page directory
    */

    while (count)
    {

      if ((Tblptr->MapAddr) && (Tblptr->MapHandle))
      {

        /*
        ** get page directory entry
        ** ignore individual entries in the map table with addresses <640K
        ** remember a -1 entry indicates address 0
        */

        if (((ULONG)Tblptr->MapAddr >= 0xa0000) && ((ULONG)Tblptr->MapAddr !=
           -1))
        {
          PDOffset = ((ULONG)Tblptr->MapAddr >> 20);
          AssertTRUE(PDOffset <= 4096);
          *(PLONG)(XGAPDAddr+PDOffset) = *(PLONG)((ULONG)SysPDLinAddr+PDOffset
             );
        }
      }
      count--;
      Tblptr++;
    }
    ReleaseMutexSem(pvd->hmxXGAMapSem);

    /*
    ** set extra page directory base address for each XGA instance
    */

    for (i = nConfigStart; i <= nConfigEnd; i++)
    {
      ioPort = XGAENV[i].IORegBase;

      if (ioPort)
      {

        /*
        ** make sure the Virtual Memory Control Register is reset to
        ** Supervisor Mode 1st before the Page Directory Base Address
        ** is changed
        */

        OUTB(ioPort+AXGA_VIRTUAL_MEMORY_CONTROLLER,
             0x00);
        XGAENV[i].pCOPAddr->PageDirBaseAddr = XGAPDPhysAddr;

        /*
        ** now put the XGA into virtual memory mode
        */

        OUTB(ioPort+AXGA_VIRTUAL_MEMORY_CONTROLLER,
             0x05);

        /*
        ** wait for the Coprocessor to complete the operation and
        ** than clear any pending VM Interrupts
        */

        vXGAWaitForCoProReady(XGAENV[i].pCOPAddr);
        OUTB(ioPort+AXGA_VIRTUAL_MEMORY_INT_STATUS,
             INB(ioPort+AXGA_VIRTUAL_MEMORY_INT_STATUS));
      }
    }

    /*
    ** don't need this hanging around anymore
    */

    VDHFreePages(SysPDLinAddr);
  }                                    /*                                   */
  return 0;
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGASaveRestore132()
 *
 * DESCRIPTION   = Save/Restore XGA 132 Column registers
 *
 *                 This routine must be called before a complete SAVE
 *                 or RESTORE is done to insure 132 column specific
 *                 registers are Saved/Restored.
 *
 *                 132 Column Text Mode Registers:
 *                   Operating Mode Reg. (21x0)
 *                   Index Register      (21xA)
 *                   Horiz. Sync End Lo  (1A)
 *                   Horiz. Sync End Hi  (1B)
 *                   Vertical Sync End   (2A)
 *                   Display Control 1   (50)
 *                   Clock Frequency     (54)
 *                   External Clock      (70)
 *
 * INPUT         = hvdm -> VDM handle
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGASaveRestore132(HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register SHORT i;
  register USHORT ioPort;

  i = pvd->nXGAin132ColConfig;         /* get current 132 col config index
                                          setup by vXGAHogSuspend           */

  /*
  ** if there is a XGA in 132 column mode to be Saved/Restored
  */

  if (i != -1)                         /* 132 column mode exists            */
  {
    ioPort = XGAENV[i].IORegBase;      /* get XGA I/O Base address          */

    /*
    ** If VDM going background, do the SAVE
    */

    if (!(pvd->flVDMXGA&VDM_FGND))
    {
      PRINTDEBUG("Background SAVE - 132 column mode  \n");

/*     ** save Operating Mode Register **                                   */
/*   pvd->vXGARegs[i].abregXGAIOReg[0] = INB(ioPort);                       */

      /*
      ** save Read/Write Index Select Register
      */

      pvd->vXGARegs[i].abregXGAIOReg[INDEX_SELECT] = INB(ioPort+INDEX_SELECT);

/*          PRINTDEBUGa("*****  I/O Reg - %x", 0x0A )';                           */
/*          PRINTDEBUGc(" = %x\n", pvd->vXGARegs[i].abregXGAIOReg[INDEX_SELECT]); */
      /*
      ** save all 132 column mode specific Index Registers
      */

      OUTB(ioPort+INDEX_SELECT,
           AINDX_HORZSYNCPULSEENDLO);
      pvd->vXGARegs[i].abregXGAIRData[AINDX_HORZSYNCPULSEENDLO] = INB(ioPort+
         INDEX_DATA);
      OUTB(ioPort+INDEX_SELECT,
           AINDX_HORZSYNCPULSEENDHI);
      pvd->vXGARegs[i].abregXGAIRData[AINDX_HORZSYNCPULSEENDHI] = INB(ioPort+
         INDEX_DATA);
      OUTB(ioPort+INDEX_SELECT,
           AINDX_VERTSYNCPULSEEND);
      pvd->vXGARegs[i].abregXGAIRData[AINDX_VERTSYNCPULSEEND] = INB(ioPort+
         INDEX_DATA);
      OUTB(ioPort+INDEX_SELECT,
           AINDX_DISPCONTROL1);
      pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1] = INB(ioPort+
         INDEX_DATA);
      OUTB(ioPort+INDEX_SELECT,
           AINDX_CLOCKFREQSELECT);
      pvd->vXGARegs[i].abregXGAIRData[AINDX_CLOCKFREQSELECT] = INB(ioPort+
         INDEX_DATA);
      OUTB(ioPort+INDEX_SELECT,
           AINDX_EXTCLOCKSELECT);
      pvd->vXGARegs[i].abregXGAIRData[AINDX_EXTCLOCKSELECT] = INB(ioPort+
         INDEX_DATA);
    }

    else
    {

      /*
      ** VDM is going foreground, do the RESTORE
      */

      PRINTDEBUG("Foreground RESTORE - 132 column mode  \n");

      /*
      ** restore Operating Mode Register
      */

      OUTB(ioPort,
           pvd->vXGARegs[i].abregXGAIOReg[0]);

/*          PRINTDEBUGa("*****  I/O Reg - %x", i );                    */
/*          PRINTDEBUGc(" = %x\n", pvd->vXGARegs[i].abregXGAIOReg[0]); */
      /*
      ** restore all 132 column mode specific Index Registers
      */

      OUTW(ioPort+INDEX_SELECT,
           (pvd->vXGARegs[i].abregXGAIRData[AINDX_HORZSYNCPULSEENDLO] << 8)|
              AINDX_HORZSYNCPULSEENDLO);
      OUTW(ioPort+INDEX_SELECT,
           (pvd->vXGARegs[i].abregXGAIRData[AINDX_HORZSYNCPULSEENDHI] << 8)|
              AINDX_HORZSYNCPULSEENDHI);
      OUTW(ioPort+INDEX_SELECT,
           (pvd->vXGARegs[i].abregXGAIRData[AINDX_VERTSYNCPULSEEND] << 8)|
              AINDX_VERTSYNCPULSEEND);

      if (pVDMBase(hvdm)->rb_nVRows == 42)
      {

        /*
        ** 132 x 43
        */

        if ((pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1]&0x0C3) !=
           0x83)
          pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1] = 0x83;
      }

      else
      {

        /*
        ** 132 x 25 or 132 x 50
        */

        if ((pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1]&0x0C3) !=
           0x43)
          pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1] = 0x43;
      }
      OUTW(ioPort+INDEX_SELECT,
           (pvd->vXGARegs[i].abregXGAIRData[AINDX_DISPCONTROL1] << 8)|
              AINDX_DISPCONTROL1);
      OUTW(ioPort+INDEX_SELECT,
           (pvd->vXGARegs[i].abregXGAIRData[AINDX_CLOCKFREQSELECT] << 8)|
              AINDX_CLOCKFREQSELECT);
      OUTW(ioPort+INDEX_SELECT,
           (pvd->vXGARegs[i].abregXGAIRData[AINDX_EXTCLOCKSELECT] << 8)|
              AINDX_EXTCLOCKSELECT);

      /*
      ** restore Read/Write Index Select Register
      */

      OUTB(ioPort+INDEX_SELECT,
           pvd->vXGARegs[i].abregXGAIOReg[INDEX_SELECT]);
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGASaveRestoreIOReg()
 *
 * DESCRIPTION   = Save/Restore XGA I/O registers
 *
 *                 This routine must be called before a complete SAVE is done
 *                 and must be called before vxgaTransferBuffer routine is
 *                 called.  The amount of information saved/restored is based
 *                 on the current video mode set.
 *
 *
 *                 If XGA is setup in:
 *
 *                 Extended Graphics Modes - All I/O Registers and Index
 *                 VGA                     - None
 *
 * INPUT         = hvdm -> VDM handle
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGASaveRestoreIOReg(HVDM hvdm,XGAENV_S *pXGAENV)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register INT i;
  USHORT ioPort;

/*  INT3();                                                                 */

  ioPort = pXGAENV->IORegBase;         /* get I/O register Base             */

  /*
  ** If VDM going background, do the SAVE
  */

  if (!(pvd->flVDMXGA&VDM_FGND))
  {

    /*
    ** if XGA is in NATIVE mode
    */

    if ((INB(ioPort)&0x04) == 0x04)
    {

      /*
      ** Save all I/O Registers that we don't shadow
      */

      for (i = AXGA_INTERRUPT_ENABLE; i < AXGA_INDEX_DATA_B; i++)
      {
        pvd->vXGARegs[pvd->nSaveRestoreConfig].abregXGAIOReg[i] = INB(ioPort+
           (USHORT)i);
      }

      /*
      ** Save all readable Index Registers
      */

      for (i = AINDX_HORZTOTALLO; i < IRINDX_INDXTOTAL; i++)
      {

        switch (i)
        {

          /*
          ** ignore shadow values for write only registers
          */

          case  AINDX_HORZSYNCPOSITION1 :
            break;

          /*
          ** ignore shadow values for write only registers
          */

          case  AINDX_HORZSYNCPOSITION2 :
            break;

          /*
          ** ignore values for sprite/palette registers
          */

          case  AINDX_SPRITEPALETTEIDXLOPREF :/*                            */
            break;                     /*                                   */
          case  AINDX_SPRITEIDXHIPREFETCH :/*                               */
            break;                     /*                                   */

          /*
          ** save all Readable Index Registers
          */

          default  :
            OUTB(ioPort+INDEX_SELECT,
                 i);
            pvd->vXGARegs[pvd->nSaveRestoreConfig].abregXGAIRData[i] = INB
               (ioPort+INDEX_DATA);
            break;
        }
      }
    }
  }

  else
  {

    /*
    ** VDM is going foreground, do the RESTORE
    */

    /*
    ** if XGA is in NATIVE mode
    */

    if ((pvd->vXGARegs[pvd->nSaveRestoreConfig].abregXGAIOReg[0]&0x04) == 0x04
       )
    {

      /*
      ** restore all Writable Index Registers
      */

      for (i = AINDX_HORZTOTALLO; i < IRINDX_INDXTOTAL; i++)
      {

        switch (i)
        {                              /*                                   */

          /*
          ** ignore values for sprite/palette registers
          */

          case  AINDX_SPRITEPALETTEIDXLOPREF :/*                            */
            break;                     /*                                   */
          case  AINDX_SPRITEIDXHIPREFETCH :/*                               */
            break;                     /*                                   */
          default  :                   /*                                   */
            OUTW(ioPort+INDEX_SELECT,
                 (pvd->vXGARegs[pvd->nSaveRestoreConfig].abregXGAIRData[i] <<
                    8)|i);
            break;                     /*                                   */
        }
      }

      /*
      ** restore all I/O Registers up to 21xA
      */

      for (i = 0; i < AXGA_INDEX_DATA_B; i++)
      {
        OUTB(ioPort+(USHORT)i,
             pvd->vXGARegs[pvd->nSaveRestoreConfig].abregXGAIOReg[i]);
      }

      /*
      ** set the virtual memory control register to user mode               
      ** if Int4B was received                                              
      */
      if (pvd->flVDMXGA & VDM_INT4B)                            /*          */
        OUTB(ioPort+AXGA_VIRTUAL_MEMORY_CONTROLLER,0x04);       /*          */
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAUpdateShieldState()
 *
 * DESCRIPTION   = Redetermine current video state
 *
 *                 This routine will only be called whenever there is a
 *                 change to the video state which PMShell needs to show
 *                 while the VDM is being windowed.
 *
 * INPUT         = hvdm -> VDM handle
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAUpdateShieldState(HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register INT i;
  SHORT WindowConfig = CurConfig;
  SHORT ClockFreq;

  /*
  ** serialize access to the video state
  ** RequestMutexSem(pvd->hmxXGAState);
  */

  /*
  ** Indicate which XGA to really save
  */

  if (pvd->nSaveRestoreConfig != -1)
  {                                    /* memory mapped register touched?   */
    WindowConfig = pvd->nSaveRestoreConfig;
  }

  /*
  ** if XGA in extended graphics mode
  */

  if ((pvd->vXGARegs[WindowConfig].abregXGAIOReg[0]&0x04) == 0x04)
  {

    /*
    ** refresh the video state structure...
    */

    pvd->npgBufferReq = npgBufferMax;
    pvd->vvmXGA.vvm_ulAdapter = ADAPTER_XGA;
    pvd->vvmXGA.vvm_ulFormat = FORMAT_BITMAP;
    pvd->vvmXGA.vvm_ulDDFormat = 0;
    pvd->vvmXGA.vvm_flMode = 0;
    pvd->vvmXGA.vvm_nRows = 480;
    pvd->vvmXGA.vvm_nCols = 640;
    pvd->vvmXGA.vvm_nPlanes = 1;
    pvd->vvmXGA.vvm_nBitCount = 1;                             /*            */
    pvd->vvmXGA.vvm_ulCellWidth = 1;
    pvd->vvmXGA.vvm_ulCellHeight = 1;
    pvd->vvmXGA.vvm_fSuspended = SUSPEND_NONE;

    if (pvd->flVDMXGA&VDM_BLOCKED)
      pvd->vvmXGA.vvm_fSuspended = SUSPEND_UNSUPPORTED_MODE;

    /*
    ** determine resolution and pixel size
    */
    if (pvd->nSaveRestoreConfig != -1) {                       /*            */
      pvd->vvmXGA.vvm_nBitCount =
                  (1 << (pvd->vXGARegs[WindowConfig].
                         abregXGAIRData[AINDX_DISPCONTROL2] & 0x07));
      pvd->vvmXGA.vvm_nCols = (pvd->vXGARegs[WindowConfig].
                               abregXGAIRData[AINDX_HORZDISPENDLO] + 1) * 8;
      pvd->vvmXGA.vvm_nRows = (pvd->vXGARegs[WindowConfig].
                               abregXGAIRData[AINDX_VERTDISPENDHI] * 256) +
                              pvd->vXGARegs[WindowConfig].
                              abregXGAIRData[AINDX_VERTDISPENDLO] + 1;
    }
    /*
    ** Refresh mode data for Shield
    */

    vXGAAddEvent(hvdm,
                 VVDEVENT_MODE,
                 &pvd->vvmXGA,
                 0);
  }

  else
  {
    pvd->flVDMXGA &= ~VDM_IOINIT;

    if (pvd->flVDMXGA&VDM_BLOCKED)

      /*
      ** tell the shield that we're suspended
      */

      vXGAAddEvent(hvdm,
                   VVDEVENT_MODE,
                   NULL,
                   0);
  }

 /*
 ** ReleaseMutexSem(pvd->hmxXGAState);
 */

}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAVDMFGContext()
 *
 * DESCRIPTION   = Foreground VDM context routine
 *
 *
 * INPUT         = p    == undefined
 *                 pcrf -> VDM register frame (NULL if called from VDD)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAVDMFGContext(PVOID p,PCRF pcrf)
{
  XGAENV_S *pXGAENV = &XGAENV[CurConfig];
  BOOL fTrap;
  INT i,j,xga_mode;
  USHORT ioPort;

  PRINTDEBUG("FG VDM Context hook\n");

/*  INT3();                                                                 */

  if (pcrf)                            /*                                   */
    VDMData.flVDMXGA &= ~VDM_FG_CONTEXTHOOK;

/*    ** if I/O trapping enabled **                                         */
/*  if (VDMData.flVDMXGA & VDM_IOTRAPPED)                                   */
/*  {                                                                       */
  /*
  ** Check session state in case hook was postponed so long that
  ** we are once again foreground (which can happen with pop-ups)
  */

  if (VDMData.flVDMXGA&VDM_FGND)
  {                                    /*                                   */

    /*
    ** serialize access to the video state
    */

    RequestMutexSem(VDMData.hmxXGAState);/*                                 */

    /*
    ** Indicate which XGA to really restore
    */

    if (VDMData.nSaveRestoreConfig != -1)/* memory mapped regs touched      */
      pXGAENV = &XGAENV[VDMData.nSaveRestoreConfig];

    /*
    ** if XGA is still in NATIVE mode
    */

    if (VDMData.flVDMXGA&VDM_IOINIT)
    {

      /*
      ** post map handler if waiting for memory
      */

      if (VDMData.flVDMXGA&VDM_GETLIMMEM)
      {
        VDHPostEventSem(VDMData.hevXGALIMMem);
        ResetEventSem(VDMData.hevXGAFGevent);/* set up event to wait...     */
        VDHWaitEventSem(VDMData.hevXGAFGevent,
                        MAX_VDM_WAIT); /* til map done                      */
      }

      /*
      ** once awaken, probably still didn't get the memory
      */

      if (VDMData.flVDMXGA&VDM_GETLIMMEM)/* if still no memory              */
        return ;                 /* go away; map handler already did popup  */
    }

/*  }                                                                       */
    /*
    ** Allow the VDM to party direct on the memory mapped I/O regs
    */

    if (VDMData.flVDMXGA&VDM_MMIOINIT)         /*mem mapped io regs used    */
    {

      if (!(VDMData.flVDMXGA & VDM_INT4B))     /*no Int4B support           */
      {

      /*
      ** lock down the VDM's entire memory space
      */

        if (vXGALockVDM(VDMData.hvdmXGA,
                        TRUE))
        {
          vXGALockVDM(VDMData.hvdmXGA,
                      FALSE);
          vXGAAddEvent(VDMData.hvdmXGA,
                       VVDEVENT_SWITCHERROR,
                       NULL,
                       0);
          return ;
        }

        else
        {

          /*
          ** fix up the extra page directory
          */

          if (vXGAPDFixUp(VDMData.hvdmXGA,
                          pXGAENV))
          {
            vXGALockVDM(VDMData.hvdmXGA,
                        FALSE);
            vXGAAddEvent(VDMData.hvdmXGA,
                         VVDEVENT_SWITCHERROR,
                         NULL,
                         0);
            return ;
          }
        }
      }                                   /* end no Int4B support           */

      pXGAENV->pCOPAddr->CopCntrl &= 0x00;/* unsuspend the coprocessor      */

      for (i = nConfigStart; i <= nConfigEnd; i++)
      {

        if ((XGAENV[i].IORegBase) &&   /* valid XGA instance                */
           (!XGAENV[i].DupROMAddr))    /* and not duplicate@                */
        {
          PRINTDEBUGa("*****  VDHMapPages physical %x\n", VDMData.hvdmXGA);

          XGAENV[i].MapTarget.vdhmt_hmap = 0L;/* initialize handle          */
          VDHMapPages(&XGAENV[i].MapSource,
                      &XGAENV[i].MapTarget,
                      VDHMT_PHYSICAL); /* make page present                 */
          VDMData.mmr_hmap[i] = XGAENV[i].MapTarget.vdhmt_hmap;/*
                                                                            */
        }
      }
    }
    xga_mode = FALSE;                /* assume all XGA are setup as VGA XGA */

    for (i = nConfigStart; i <= nConfigEnd; i++)
    {
      ioPort = XGAENV[i].IORegBase;

      if (ioPort)                      /* valid XGA instance                */
      {

        /*
        ** look for configuration with XGA mode set
        */

        if (VDMData.vXGARegs[i].abregXGAIOReg[0]&4)
          xga_mode = TRUE;             /* repaint necessary                 */

        /*
        ** Enable trapping for I/O Registers 21x0 - 21x9
        */

        for (j = 0; j < AXGA_INDEX_SELECT; j++)
        {
          VDHSetIOHookState(CURRENT_VDM,
                            ioPort++,
                            1,
                            &aiohBReg[j],
                            TRUE);
        }

        /*
        ** Enable trapping for Index Registers 21xA
        */

        VDHSetIOHookState(CURRENT_VDM,
                          XGAENV[i].IORegBase+0x0a,
                          1,
                          &iohXGAirregIndex,
                          TRUE);

        /*
        ** Enable trapping for Index Registers 21xB - 21xF
        */

        for (j = AXGA_INDEX_DATA_B; j < AXGA_TOTAL; j++)
        {
          VDHSetIOHookState(CURRENT_VDM,
                            XGAENV[i].IORegBase+j,
                            1,
                            &iohXGAirregData,
                            TRUE);
        }
      }
    }

    /*
    ** tell VVGA to setup for appropriate repaint flag
    */

    if (hvddVideo)
    {
      VDHRequestVDD(hvddVideo,
                    CURRENT_VDM,
                    VVDDEVREQ_REPAINT,
                    (PVOID)xga_mode,
                    NULL);
    }
    ReleaseMutexSem(VDMData.hmxXGAState);/*                                 */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAVDMBGContext()
 *
 * DESCRIPTION   = Background VDM context routine
 *
 *                 This is a context hook to perform I/O trap disabling in
 *                 the foreground VDM's context.
 *
 * INPUT         = p    == undefined
 *                 pcrf -> VDM register frame (NULL if called from VDD)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAVDMBGContext(PVOID p,PCRF pcrf)
{
  register XGAENV_S *pXGAENV;
  INT i,j;
  USHORT ioPort;

  PRINTDEBUG("BG VDM Context hook\n");

  if (pcrf)                            /*                                   */
    VDMData.flVDMXGA &= ~VDM_BG_CONTEXTHOOK;

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

  if (!(VDMData.flVDMXGA&VDM_FGND))
  {                                    /*                                   */

    /*
    ** serialize access to the video state
    */

    RequestMutexSem(VDMData.hmxXGAState);/*                                 */

    /*
    ** if VDM memory has been locked down
    */

    if (VDMData.flVDMXGA&VDM_LOCKED)
    {

    /*
    ** unlock VDM memory
    */

      vXGALockVDM(VDMData.hvdmXGA,
                  FALSE);
    }

    /*
    ** Prevent background VDM from using the XGA Coprocessor
    ** Only the second page of ROM containing the memory mapped registers
    ** will be marked invalid.  We are not interested in the first ROM pg.
    */

    for (i=nConfigStart; i<=nConfigEnd; i++)
    {
      ioPort = XGAENV[i].IORegBase;
      if (ioPort)
      {

        /*
        ** no dups allowed
        */

        if (!XGAENV[i].DupROMAddr)
        {

          /*
          ** make each ROM page invalid
          */

          PRINTDEBUGa("*****  VDHMapPages invalid %x \n", VDMData.hvdmXGA);

          XGAENV[i].MapTarget.vdhmt_hmap = VDMData.mmr_hmap[i];/*               */
          VDHMapPages(&XGAENV[i].MapSource,
                      &XGAENV[i].MapTarget,
                      VDHMT_INVALID);      /* this able page faulting to occur  */
        }

        /*
        ** if the VDM is access VRAM through the 64K Aperture
        ** freeze it on the way out
        */

        if (VDMData.ApertSource[i].vdhms_laddr)
        {
          VDMData.flVDMXGA |= VDM_FROZEN;  /* about to be frozen                */
        }

        /*
        ** Trap all background I/O Register access from 21x0 - 21x9
        */

        for (j = 0; j < AXGA_INDEX_SELECT; j++)
        {
          VDHSetIOHookState(CURRENT_VDM,
                            ioPort++,
                            1,
                            &aiohBReg[j],
                            TRUE);
        }

        /*
        ** Trap all background Index Register access at 21xA
        */

        VDHSetIOHookState(CURRENT_VDM,
                          XGAENV[i].IORegBase+0x0a,
                          1,
                          &iohXGAirregIndex,
                          TRUE);

        /*
        ** Trap all background Index Register access at 21xA
        */

        for (j = AXGA_INDEX_DATA_B; j < AXGA_TOTAL; j++)
        {
          VDHSetIOHookState(CURRENT_VDM,
                            XGAENV[i].IORegBase+j,
                            1,
                            &iohXGAirregData,
                            TRUE);
        }
      }
    }

    /*
    ** prevent the VDM from accessing the 64K Aperture
    ** by freezing it in the background
    */

    if ((VDMData.flVDMXGA& VDM_IOTRAPPED)  /*                                   */
        && !(VDMData.flVDMXGA&VDM_FG_CONTEXTHOOK) )
    {                                      /*                                   */

      if (!(VDMData.flVDMXGA&VDM_INT2F))
      {                                    /*                                   */

        if (VDMData.flVDMXGA&VDM_FROZEN)
        {
          VDMData.flVDMXGA |= VDM_BLOCKED; /* block VDM                         */
          vXGAAddEvent(VDMData.hvdmXGA,
                       VVDEVENT_MODE,
                       NULL,
                       0);                 /*                                   */
          VDHFreezeVDM(0);                 /* freeze that puppy                 */
        }
      }
    }

    ReleaseMutexSem(VDMData.hmxXGAState);  /*                                   */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAAddEvent()
 *
 * DESCRIPTION   = VDM video event installer
 *
 *                 This routine adds a video event to the "event queue"
 *
 * INPUT         = hvdm   -> VDM
 *                 iEvent == event ordinal
 *                 pEvent -> event data (varies from one event to another)
 *                 flAdd  == Event flags (eg, POSTEVENT_FLUSH)
 *                   vXGAAddEvent(hvdm, VVDEVENT_MODE, &pvd->vvmXGA, 0);
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAAddEvent(HVDM hvdm,INT iEvent,register PVOID pEvent,FLAGS
                             flAdd)
{
  VVPOST vvp;


  if (hvddVideo)
  {
    vvp.vvp_iEvent = iEvent;
    vvp.vvp_pEvent = pEvent;
    vvp.vvp_flEvent = flAdd|POSTEVENT_ADD;
    VDHRequestVDD(hvddVideo,
                  hvdm,
                  VVDDEVREQ_POSTEVENT,
                  SSToDS(&vvp),
                  NULL);
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAUnlockIO()
 *
 * DESCRIPTION   = VDM unlock I/O routine
 *
 *                 Allows VDM I/O to proceed.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = I/O may proceed
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  /*
  ** Release the IOOWNED bit
  */

  pvd->flVDMXGA &= ~VDM_IOOWNED;

  if (pvd->flVDMXGA&VDM_FROZEN)
  {
    VDHThawVDM(hvdm);
    pvd->flVDMXGA &= ~VDM_FROZEN;
  }

  if (pvd->flVDMXGA&VDM_IOWAKEME)
    PostEventSem(pvd->hevXGAWakeUp);
}

/***************************************************************************
 *                                                                                  
 * FUNCTION NAME = VXGAINT2FHANDLER()                                               
 *                                                                                  
 * DESCRIPTION   = INT 2FH HANDLER                                                  
 *                                                                                  
 * INPUT         = HVDM  == VDM HANDLE                                              
 *                 T     == NOTIFICATION TYPE                                       
 *                 PCRF  -> VDM REGISTER FRAME                                      
 *                                                                                  
 * OUTPUT        = NONE                                                             
 *                                                                                  
 * RETURN-NORMAL =                                                                  
 * RETURN-ERROR  =                                                                  
 *                                                                                  
 **************************************************************************/

VOID EXPENTRY VXGAInt2FHandler(HVDM hvdm,ULONG t,PCRF pcrf)/*               */
{                                      /*                                   */
  register PVDMDATA pvd = pVDMData(hvdm);/*                                 
                                                                            */


  switch (t)
  {                                    /*                                   */
    case  VDHVVD_INT2F_OFF :           /* at OS/2 task time                 */
      pvd->flVDMXGA &= ~VDM_INT2F;     /*                                   */
      break;                           /*                                   */
    case  VDHVVD_INT2F_ON :            /* at OS/2 task time                 */
      pvd->flVDMXGA |= VDM_INT2F;      /*                                   */
      break;                           /*                                   */
    case  VDHVVD_INT2F_FG_START :      /* at VDM task time                  */

      /*
      ** grant I/O access 1st on foreground notification
      */

      if (!vdhBTS(&pvd->flVDMXGA,
                  LOG2(VDM_FG_CONTEXTHOOK)))/*                              */
        VXGAVDMFGContext(NULL,
                         pcrf);        /*                                   */
      break;                           /*                                   */
    case  VDHVVD_INT2F_BG_END :        /*                                   */

      /*
      ** Indicate successful return from Int 2F notification
      */

      pvd->flVDMXGA &= ~VDM_FGND;      /* need to force it                  */
      VXGAVDMBGContext(NULL,
                       pcrf);          /*                                   */
      pvd->flVDMXGA |= VDM_INT2FWAKEME;/*                                   */
      PostEventSem(pvd->hevXGAWakeUp); /*                                   */
      break;                           /*                                   */
  }                                    /*                                   */
}                                      /*                                   */

/***************************************************************************
 *
 * FUNCTION NAME = VXGASetBgnd()
 *
 * DESCRIPTION   = VDM background notification routine
 *
 *                 This routine is registered at VDD init time through
 *                 VDHInstallUserHook.  It is called each time a VDM is
 *                 switched to background.  The main responsibility of this
 *                 routine is to determine whether to let the VDM handle its
 *                 own SAVE or allow the VDD do it through INT 2F
 *                 notification.  Any XGA interrupts pending at this point
 *                 will be asserted when the current VDM is switched back to
 *                 foreground.  The level of virtualization for this
 *                 hardware is very limited, so all background I/O will be
 *                 blocked.  The video signal will be left OFF after a SAVE
 *                 is done to avoid unnecessary screen flicker.
 *
 * INPUT         = hvdm -> new background VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID EXPENTRY VXGASetBgnd(register HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  XGAENV_S *pXGAENV = &XGAENV[CurConfig];

/*  USHORT            frozen  = 0;                                            */
/*  INT3();                                                                 */
  /*
  ** See what mode the VGA-defined XGA is running at
  */

  if (InitXGAinVGA != -1)              /*                                   */
  {                                    /*                                   */

    if (INB(0x2100+(InitXGAinVGA << 4)) == 04)/* XGA in XGA mode            */
      pvd->flVDMXGA |= VDM_PMXGA;      /* make a note of it                 */

    else                               /* not in XGA mode                   */
      pvd->flVDMXGA &= ~VDM_PMXGA;     /* reset indicator                   */
  }                                    /*                                   */

  /*
  ** If we own the device and the VDM is foreground
  */

  if (pvd->flVDMXGA&VDM_DEVOWNER && pvd->flVDMXGA&VDM_FGND)/*               */
  {

    /*
    ** serialize access to the video state
    */

    RequestMutexSem(pvd->hmxXGAState); /*                                   */

    /*
    ** suspend all XGA's
    */

    vXGAHogSuspend(hvdm);

    /*
    ** keep the VDM from changing the VRAM when 1 or more
    ** 64K Aperture are enabled
    */
/* if (pvd->nApertureEnabled)                                               */
/* {                                                                        */

    VDHFreezeVDM(hvdm);                /*                                   */

/*    frozen =1;                 ** indicate VDM frozen      **                      */
/* }                                                                        */
    /*
    ** Indicate which XGA to really save
    */

    if (pvd->nSaveRestoreConfig != -1)
    {                                  /* memory mapped regs touched        */
      pXGAENV = &XGAENV[pvd->nSaveRestoreConfig];
    }

    else
    {
      pvd->nSaveRestoreConfig = CurConfig;
    }

    /*
    ** Indicate save in progress
    */

    glVDMXGA &= ~VDM_RESTORE;
    PRINTDEBUGa("*****  Background device owner, VDM data %x\n", pVDMData(hvdm));

    /*
    ** Wait for INT 2F initiated by the sharing VVD to complete
    */

    if (pvd->flVDMXGA&VDM_INT2F)
    {

      if (pvd->flVDMXGA&VDM_IOINIT)
      {                                /*                                   */
        while (VDHIsVDMFrozen(hvdm))   /* do until not frozen               */
          VDHThawVDM(hvdm);            /* allow VDM to run                  */

        ReleaseMutexSem(pvd->hmxXGAState);/*                                */

        /*
        ** Wait for VVGA's Int 2F to complete
        */

        pvd->flVDMXGA &= ~VDM_INT2FWAKEME;
        ResetEventSem(pvd->hevXGAWakeUp);
        VDHWaitEventSem(pvd->hevXGAWakeUp,
                        MAX_VDM_WAIT);
        VDHFreezeVDM(hvdm);            /* put back to sleep                 */

        /*
        ** serialize access to the video state
        */

        RequestMutexSem(pvd->hmxXGAState);/*                                */
      }                                /*                                   */
    }
    pvd->flVDMXGA &= ~VDM_FGND;        /*                                   */

    /*
    ** Save the 1st 132 column mode configuration
    */

    vXGASaveRestore132(hvdm);

    /*
    ** if XGA I/O registers were altered
    */

    if (pvd->flVDMXGA&VDM_IOINIT)
    {

      /*
      ** save I/O registers
      */

      vXGASaveRestoreIOReg(hvdm,
                           pXGAENV);

      /*
      ** if I/O trapping enabled
      */

      if (pvd->flVDMXGA&VDM_IOTRAPPED)
      {

        /*
        ** Redetermine the current screen dimensions
        ** (and we may even decide to reset VDM_IOINIT)
        */

        vXGAUpdateShieldState(hvdm);

        /*
        ** if XGA is still in 'NATIVE' mode
        */

        if (pvd->flVDMXGA&VDM_IOINIT)
        {

          /*
          ** Turn the screen off while we're updating things
          */

          vXGAVideoEnable(hvdm,
                          pXGAENV,
                          FALSE);

          /*
          ** save sprite, pallette, coprocessor and state
          */

          vXGAVideoState(hvdm,
                         pXGAENV);

          /*
          ** Customize size of memory buffer for this VDM
          */

          if ((pvd->npgBuffer == 256) && !(pXGAENV->flVRAM_1Meg))
          {
            pvd->npgBufferReq = (pvd->npgBuffer >> 2);/* get 1/2            */
          }

          else                         /* buffer too small for this XGA     */
          {

            if ((pvd->npgBuffer == 128) && (pXGAENV->flVRAM_1Meg))
            {
              pvd->npgBufferReq = (pvd->npgBuffer << 2);/* double           */

              if (!vXGAGrowBuffer(hvdm))
              {
                vXGAAddEvent(hvdm,
                             VVDEVENT_SWITCHERROR,
                             NULL,
                             0);
                return ;               /* can't save properly               */
              }
            }
          }

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

          vXGATransferBuffer(hvdm,
                             pXGAENV,
                             FALSE);
        }
      }
    }

    /*
    ** restore VGA configuration
    */

    vXGAEnableVGA(hvdm);               /*                                   */

    /*
    ** terminate coprocessor operations
    */

    vXGAHogTerminate();

    /*
    ** Claim the IOOWNED bit
    */

    vXGALockIO(hvdm);

    /*
    ** the INT 2F Handler should have done this
    */

    if (!(pvd->flVDMXGA&VDM_INT2F))
    {                                  /*                                   */

      /*
      ** arm background context hook
      */

      if (!vdhBTS(&pvd->flVDMXGA,
                  LOG2(VDM_BG_CONTEXTHOOK)))
        VDHArmContextHook(pvd->hhookVDMBGContext,
                          hvdm);
    }                                  /*                                   */

/* if (pvd->nApertureEnabled)                                               */
       VDHThawVDM(hvdm);

       ReleaseMutexSem(pvd->hmxXGAState);                               /*           */


  }
  PRINTDEBUGa("***** Background  not device owner, VDM data %x\n",
             pVDMData(hvdm));
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAEnableVGA()
 *
 * DESCRIPTION   = Return 'BOOTUP' adapter back to VGA
 *
 *                 This routine is responsible for reenabling the
 *                 VGA on the planar or restore the 'BOOTUP' XGA
 *                 configuration back to VGA mode.
 *
 *                 WARNING:  On a PS/2, both VGA and XGA can be found
 *                           by reading the POS registers.  If XGA is
 *                           to be supported on non-ABIOS machines,
 *                           we must update all POS query routines
 *                           to insure proper adapter identification.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAEnableVGA(HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register XGAENV_S *pXGAENV = &XGAENV[nConfigStart];
  INT i;
  USHORT ioPort;                       /* Operation Mode Register address   */
  BYTE ioData;                         /* Operation Mode data               */
  USHORT FoundVGA = FALSE;             /* InitXGAinVGA isn't found          */

  /*
  ** search through all XGA configurations to disable VGA or
  ** 132 Column Mode Address Decode
  */

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {
    ioPort = pXGAENV->IORegBase;

    /*
    ** valid XGA configuration setup
    */

    if (ioPort)
    {
      ioData = INB(ioPort);

      if ((ioData&0x05) == 0x01)
      {                                /* VGA or 132 Column Mode enabled?   */

        if (i != InitXGAinVGA)
        {

          /*
          ** disable Address Decode
          */

          OUTB(ioPort,
               ioData&0xfe);
        }

        else
        {

          if (ioData == 0x01)          /* already in VGA mode?              */
            FoundVGA = TRUE;           /* InitXGAinVGA found                */
        }
      }
    }
    pXGAENV++;
  }

  /*
  ** exit if the initial XGA already setup in VGA mode
  */

  if (!FoundVGA)
  {

    /*
    ** if there is one XGA initially booted up in VGA mode then reset
    ** that configuration back to VGA mode.  This will allow the next
    ** VDM to be started on the bootup XGA.
    */

    if (InitXGAinVGA != -1)
    {
      ioPort = XGAENV[InitXGAinVGA].IORegBase;/* get VGA I/O Base addr      */
      OUTB(ioPort+0x01,
           0x00);                      /* reset Aperture control            */
      OUTB(ioPort+0x04,
           0x00);                      /* disable Interrupt                 */
      OUTB(ioPort+0x05,
           0xFF);                      /* clear all interrupts              */
      OUTW(ioPort+INDEX_SELECT,
           0xFF64);                    /* enable all palettes               */
      OUTW(ioPort+INDEX_SELECT,
           0x1550);                    /* prepare CRTC for reset            */
      OUTW(ioPort+INDEX_SELECT,
           0x1450);                    /* reset CRTC                        */
      OUTW(ioPort+INDEX_SELECT,
           0x0051);                    /* setup default scale factor        */
      OUTW(ioPort+INDEX_SELECT,
           0x0454);                    /* select VGA clock                  */
      OUTW(ioPort+INDEX_SELECT,
           0x0070);                    /* setup external clock              */
      OUTW(ioPort+INDEX_SELECT,
           0x202A);                    /* disable VSync interrupts          */
      OUTB(ioPort,
           0x01);                      /* enable VGA mode                   */
      OUTB(0x3C3,
           0x01);                      /* enable VGA hardware               */
    }

    else
    {

          /*
          ** no "boot" XGA found in VGA, VGA must be on planar
                                                                            */

      OUTB(PORT_PLANAR,
           planar_setting);            /* restore planar setting            */
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAHogTerminate()
 *
 * DESCRIPTION   = Terminate Coprocessor operation on all XGAs
 *
 *                 Before VxgaSetBgnd is complete, all Coprocessor operations
 *                 must be terminated in case other processes may want to use
 *                 them.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAHogTerminate()
{
  INT i;
  register COP_S *pHog;
  register XGAENV_S *pXGAENV = &XGAENV[nConfigStart];

  /*
  ** for all XGA configurations
  */

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {

    if (pXGAENV->IORegBase)
    {

      /*
      ** terminate the current coprocessor task
      */

      pHog = pXGAENV->pCOPAddr;
      pHog->CopCntrl = 0x20;
    }
    pXGAENV++;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAHogSuspend()
 *
 * DESCRIPTION   = Suspend Coprocessor operation on all XGAs
 *
 *                 This routine suspends all XGAs, records how many of them
 *                 complete with interrupt pending and records whether there
 *                 is an XGA with 132 column mode enabled.  The VxgaSetFgnd
 *                 routine will then use this value to assert the necessary
 *                 'soft' interrupt(s) for the VDM to processs at task time
 *                 (see VxgaFgndContext).
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAHogSuspend(HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register XGAENV_S *pXGAENV = &XGAENV[nConfigStart];
  COP_S *pHog;                         /* coprocessor MMIO registers        */
  INT i;
  USHORT ioPort;                       /* Operating Mode Register address   */
  UCHAR ioData;                        /* Operating Mode Register content   */

  pvd->nXGAinVGAConfig = -1;           /* assume no VGA setup               */
  pvd->nXGAin132ColConfig = -1;        /* assume no 132 column setup        */

  /*
  ** for all XGA configurations
  */

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {
    ioPort = pXGAENV->IORegBase;       /* get Op Mode Register address      */

    if (ioPort)
    {                                  /* valid port address?               */

      /*
      ** suspend the coprocessor
      */

      pHog = pXGAENV->pCOPAddr;        /* get linear Coprocessor address    */

      pHog->CopCntrl =  0x08;          /* set SOp bit                       */


      /*
      **  wait for confirmation                                            
      */

      for (;;)                                                /*            */
      {                                                       /*            */
        if (pHog->CopCntrl & 0x10)     /* check OpS bit */    /*            */
        break;                                                /*            */
      }                                                       /*            */


      /*
      ** disable decoding for all XGAs currently in VGA mode
      ** don't disable the bootup XGA found in VGA mode
      */

      ioData = INB(ioPort);            /* read the Op Mode Register         */

      if (((ioData&0x03) == 0x03) ||   /* look for 132 column mode setup    */
         (pvd->vXGARegs[i].abregXGAIOReg[0] == 0x11))/*                     */
      {

        if (i != InitXGAinVGA)
        {
          OUTB(ioPort,
               0x02);                  /* disable decoding                  */
        }

        if (pvd->nXGAin132ColConfig == -1)
        {
          pvd->nXGAin132ColConfig = i; /* save 1st one found                */
        }
      }

      else
      {

        if (ioData&0x01)               /* look for VGA setup                */
        {

          if (i != InitXGAinVGA)
          {
            OUTB(ioPort,
                 0x00);                /* disable decoding                  */
          }

          if (pvd->nXGAinVGAConfig == -1)
          {
            pvd->nXGAinVGAConfig = i;  /* save 1st one found                */
          }
        }
      }
    }
    pXGAENV++;                         /* next XGA environment              */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAFree()
 *
 * DESCRIPTION   = Free memory
 *
 *                 This registered subroutine is called to deallocate pages
 *                 that were obtained at initialization time.  This
 *                 includes:
 *                            VRAM Page Tables    (unlocked & freed)
 *                            XGA  Page Directory (unlocked & freed)
 * INPUT         = hvdm -> VDM
 *                 counter of #XGA VRAM instances to free
 * OUTPUT        =
 *                 None
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAFree()
{
  INT i;

  PRINTDEBUG("*****  I am in vXGAFree \n");

  /*
  ** unlock VRAM Page Table(s)
  */

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {

    if (XGAENV[i].VRAMPTHandle)        /* validate its existence first      */
    {
      VDHUnlockMem(XGAENV[i].VRAMPTHandle);
      VDHFreePages(XGAENV[i].VRAMPTAddr);
    }
  }

  /*
  ** Free previously allocated LVB and Page Directory if failure
  */

  if (XGAPDHandle)
    VDHUnlockMem(XGAPDHandle);

  if (XGAPDAddr)
    VDHFreePages(XGAPDAddr);
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAAllocTbl()
 *
 * DESCRIPTION   = Allocate LIM Mapping table
 *
 *                 Allocates an initial size table of 1 page containing
 *                 entries corresponding to mapping requests.  Re-allocates
 *                 the table by 1 page increments if necessary, copies the
 *                 contents from the previous table and updates the #
 *                 entries for the new table.
 *
 * INPUT         = hvdm -> VDM
 *                 counter of #XGA VRAM instances to free
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

PBYTE PRIVENTRY vXGAAllocTbl(HVDM hvdm)
{
  PVOID p;
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** Allocate table
  */

  if ((p = VDHAllocPages(NULL,
                         pvd->TblPages,
                         VDHAP_SYSTEM)) == NULL)
    return  p;                         /* out-of-memory error processing    */

/* memset (p, '\0', pvd->TblPages*4096); ** initialize to 00000000.....**          */

    _asm                                                                 /*            */
    {                                                                    /*            */
        mov   ecx, pvd                                                   ;;@V2.0YEE13
        mov   ecx, dword ptr [ecx].TblPages ;get # pages                   @V2.0YEE13
        shl   ecx, 10                       ;get # doublewords (*4K/4)     @V2.0YEE13
        mov   edi, p                        ;start of table                @V2.0YEE13
        mov   eax, 0                        ;value to initialize           @V2.0YEE13
        repe  stosd                         ;do it                         @V2.0YEE13
    }                                                                    /*            */


  if (pvd->TblMap)                     /* table already exists              */
  {

/* memcpy(p, pvd->TblMap, pvd->TblEntries*TBLENTRYSIZE); **copy old tbl**          */

    vdhMoveMem(pvd->TblMap,
               p,
               1,
               1,
               pvd->TblEntries *TBLENTRYSIZE,
               FALSE);                 /*                                   */
    VDHFreePages(pvd->TblMap);         /* free old table                    */
  }
  pvd->TblMap = p;                     /* set up new table address          */
  pvd->TblEntries = pvd->TblPages *4096/TBLENTRYSIZE;/* calc #entries       */
  pvd->TblPages++;                     /* update #pages for next time       */
  return  p;                           /* set good return code              */
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGADestroy()
 *
 * DESCRIPTION   = VDM termination notification
 *
 *                 This registered subroutine is called each time an
 *                 existing VDM is destroyed (see VDHInstallUserHook for
 *                 complete semantics).  Either by a user killing the VDM
 *                 session or some disastrous error occurred during create.
 *
 * INPUT         = hvdm -> dying VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID EXPENTRY VXGADestroy(HVDM hvdm)
{
  INT count;

  PRINTDEBUG("*****  I am in vXGADestroy \n");

/*  INT3();                                                                 */

  VDMData.flVDMXGA &= ~VDM_INT2F;      /* ignore Int 2F notification        */
  VDMData.flVDMXGA |= VDM_GOINGDOWN;   /* ignore map/unmap notificati       */

  /*
  ** Flip to background if not already, and free buffer
  */

  VXGASetBgnd(0);

  /*
  ** Shrink memory buffer & palette/sprite/co-pro buffer down now
  */

  VDMData.npgBufferReq = 0;
  vXGAShrinkBuffer(0);

  /*
  ** Reset to VGA mode only if originally running in VGA mode
  */

  if (!(VDMData.flVDMXGA&VDM_PMXGA))   /* initially VGA mode                */
    vXGAEnableVGA(0);                  /* transition to VGA mode            */

/*       **       Send Int 10 notification to switch to mode 3          *****/
/*  VDHArmContextHook(VDMData.hhookInt10Context, VDMData.hvdmXGA);          */
  /*
  ** release VDM memory if still locked down
  */

  if (VDMData.flVDMXGA&VDM_LOCKED)
    vXGALockVDM(VDMData.hvdmXGA,
                FALSE);

  /*
  ** free DOS 640K linear to physical address mapping
  */

  if (VDMData.DOSPTLinAddr)            /* only if it exists                 */
    VDHFreePages(VDMData.DOSPTLinAddr);

  if (VDMData.TblMap)                  /* validate existence first          */
    VDHFreePages(VDMData.TblMap);      /* release map table                 */

  if (nNumVDM == 1)
  {                                    /* last VDM terminating              */
    vXGAFree();                        /* free VRAM page tables, page
                                          directory                         */

    /*
    ** unlock 64K ring buffer
    */

    if (hRingBuffer)
    {                                  /*                                   */
      VDHUnlockMem(hRingBuffer);       /*                                   */
      hRingBuffer = NULL;              /*                                   */
    }

    /*
    ** free 64K ring buffer
    */

    if (pRingBuffer)
    {                                  /*                                   */
      VDHFreePages(pRingBuffer);       /*                                   */
      pRingBuffer = NULL;              /*                                   */
    }                                  /*                                   */
  }
  nNumVDM--;                           /* decrement VDM count               */

  /*
  ** Remove fault hooks for memory mapped register areas
  */

  if (VDMData.flVDMXGA&VDM_HOOKED)     /* verify prev fault hooks           */
  {

    for (count = nConfigStart; count <= nConfigEnd; count++)
    {

      if ((XGAENV[count].IORegBase) && /* make sure valid                   */
         (!XGAENV[count].DupROMAddr))  /* and not duplicate@                */
        VDHRemoveFaultHook(hvdm,
                           (PVOID)XGAENV[count].ROMAddr,
                           1L,
                           VXGAPgFaultHndlr);
    }
  }

  /*
  ** Deallocate all per-VDM semaphores
  */

  DestroyMutexSem(VDMData.hmxXGAState);
  DestroyMutexSem(VDMData.hmxXGAMapSem);
  DestroyEventSem(VDMData.hevXGAWakeUp);
  DestroyEventSem(VDMData.hevXGALIMMem);
  DestroyEventSem(VDMData.hevXGAFGevent);
}

#ifdef   OLD_PROPERTIES

 /*
 ** NOTE:  This property has been changed to a create-time only
 ** property, because it does not seem worth the effort at this
 ** time to write the necessary routines to re-enable trapping
 ** for all the ports on the fly...
 */

/***************************************************************************
 *
 * FUNCTION NAME = VXGASetIOTrapping
 *
 * DESCRIPTION   = Set per-VDM I/O trapping flag
 *
 *                 This routine is called when the user alters an existing
 *                 VDM's I/O trapping "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 VXGASetIOTrapping(ULONG op,HVDM hvdm,ULONG cb,PSZ psz)
{
  AssertTRUE(op == VDHPROP_SET);
  SETBIT(pVDMData(hvdm)->flVDMXGA,
         VDM_IOTRAPPED,
         (BOOL)psz);
  return 0;
}

#endif

/***************************************************************************
 *
 * FUNCTION NAME = vXGASetIOHooks()Install/remove I/O hooks
 *
 * DESCRIPTION   = Set per-VDM I/O trapping flag
 *
 *                 This routine installs all the appropriate I/O handlers
 *                 for the current VDM.
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGASetIOHooks()
{
  FLAGS fl;
  register INT i,j;
  register USHORT ioPort;

  PRINTDEBUG("In vXGASetIOHooks()...\n");

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {
    ioPort = XGAENV[i].IORegBase;      /* get current I/O Register Base     */

    if (ioPort)
    {

      /*
      ** install I/O Register Trap Handlers for 21x0 - 21x9
      */

      for (j = 0; j < AXGA_INDEX_SELECT; j++)
      {
        AssertRC(VDHInstallIOHook(CURRENT_VDM,
                                  ioPort++,
                                  1,
                                  &aiohBReg[j],
                                  0));
      }

      /*
      ** install Index Register Trap Handlers for 21xA
      */

      AssertRC(VDHInstallIOHook(CURRENT_VDM,
                                XGAENV[i].IORegBase+0x0a,
                                1,
                                &iohXGAirregIndex,
                                VDHIIH_NO_SIMULATE));

      /*
      ** install Index Register Trap Handlers for 21xB - 21xF
      */

      for (j = AXGA_INDEX_DATA_B; j < AXGA_TOTAL; j++)
      {
        AssertRC(VDHInstallIOHook(CURRENT_VDM,
                                  XGAENV[i].IORegBase+j,
                                  1,
                                  &iohXGAirregData,
                                  VDHIIH_NO_SIMULATE));
      }
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAInitPaging()
 *
 * DESCRIPTION   = Allocate and Initialize VRAM Page Table
 *
 *                    31       22 21      12 11        0
 *                    ----------------------------------
 *         ---------- |  DIR     |  PAGE    |  OFFSET  |      LINEAR ADDRESS
 *         |          ----------------------------------
 *         |                       |                |
 *         |                       |                |
 *         |   Page Directory      |  Page Table    |      Page Frame
 *         |    ----------         |  ----------    |      ----------
 *         |    |        |         |  |        |    |      |        |
 *         |    |        |         |  |--------|    |      |PHYSICAL|
 *         |    |        |         -->| ENTRY  |--- |      |ADDRESS |
 *         |    |--------|            |--------|  | |      |        |
 *         ---> | ENTRY  |------      |        |  | ------>|        |
 *              |--------|     |      |        |  |        |        |
 *              |        |     |      |        |  |        |        |
 *         ---> ----------     -----> ----------  -------> ----------
 *         |
 *         |
 *      -------
 *      | CR3 |
 *      -------
 *
 * INPUT         = XGAENV
 *
 * OUTPUT        = SUCCESS
 *                     TRUE
 *                 FAILURE
 *                     FALSE (not enough memory)
 *
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAInitPaging(XGAENV_S *XGAENV)
{
  ULONG *PDEntry;
  ULONG *TempPTAddr;
  ULONG TempAddr;
  INT i;

  /*
  ** Allocate a 4K VRAM page table
  */

  if (!(XGAENV->VRAMPTAddr = VDHAllocPages(NULL,
                                           1,
                                           VDHAP_SYSTEM)))
    return ;                           /* exit if no memory available       */

  /*
  ** Lock VRAM page table
  */

  if (!(XGAENV->VRAMPTHandle = VDHLockMem(XGAENV->VRAMPTAddr,
                                          4096,
                                          VDHLM_16M,            /*          */
                                          &PGList,
                                          &NElements)))
  {
    VDHFreePages(XGAENV->VRAMPTAddr);  /* free VRAM Page Table              */
    XGAENV->VRAMPTAddr = 0;            /* indicate failure                  */
    return ;                           /* exit if no memory available       */
  }

  /*
  ** Save XGA VRAM Page Table in Page Directory
  */

  (PBYTE)PDEntry = ((XGAENV->VRAMAddr >> 20)+XGAPDAddr);/* PD entry        @*/
  *PDEntry = PGList.pl_paddr|7;        /* save 4M VRAM Pg Tbl entry in Dir  */

  if (XGAENV->OneMegAperture)
  {                                    /*                                   */
    (PBYTE)PDEntry = ((XGAENV->OneMegAperture >> 20)+XGAPDAddr);/* PD ntry  */
    *PDEntry = PGList.pl_paddr|7;      /* save 1M aperture Pg Tbl entry in
                                          Dir                               */
  }                                    /*                                   */

  /*
  ** Save XGA VRAM page in Page Table
  */

  (PBYTE)TempPTAddr = XGAENV->VRAMPTAddr;/* save start of page table        */
  TempAddr = XGAENV->VRAMAddr|7;       /* save start of VRAM address set
                                          U/S, R/W, and P bits              */

  for (i = 0; i < NVRAMPAGES; i++)
  {
    *TempPTAddr = TempAddr;
    TempPTAddr++;                      /* point to next PTEntry Addr        */
    TempAddr += 4096;                  /* next 4k VRAM page                 */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAGrowBuffer()
 *
 * DESCRIPTION   = Grow specified VDM's virtual buffer
 *
 *                 This routine's purpose is to grow the virtual buffer to
 *                 the maximum possible size needed.
 *
 *                 Along with this, the following buffers are also allocated:
 *
 *                    -  768  bytes of Palette data
 *                    -  1024 bytes of Sprite data
 *                    -  1024 bytes of Co-processor State data
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = SUCCESS
 *                     TRUE
 *                 FAILURE
 *                     FALSE (not enough memory)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGAGrowBuffer(HVDM hvdm)
{
  PVOID p;
  PBYTE temp;
  BOOL fSuccess = FALSE;               /* initialize to false               */
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** If I/O trapping is disabled, assume the app will restore itself
  */

  if (!(pvd->flVDMXGA&VDM_IOTRAPPED))
    return  TRUE;                      /* I/O trapping doesn't need an LVB  */


  if (!pvd->pBuffer)                   /* no buffer allocated yet           */
  {

    if (p = VDHAllocPages(NULL,
                          npgBufferMax,
                          VDHAP_SYSTEM))/* get max                          */
    {

      /*
      ** Now get a 4K-page for palette, sprite, & copro state
      */

      if ((!pvd->Palette_Buf) && (temp = VDHAllocPages(NULL,
                                                       1,
                                                       VDHAP_SYSTEM)))
      {
        pvd->Palette_Buf = temp;       /* set palette buffer                */
        pvd->Sprite_Buf = temp+1024;   /* adjust to sprite buffer           */
        pvd->State_Buf = temp+1024+1024;/* adjust to state buffer           */
      }

      else                             /* no buffer obtained                */
      {
        VDHFreePages(p);               /* release LVB                       */
        p = NULL;                      /* indicate no buffer obtained       */
      }
    }
  }

  else                                 /* may need to grow existing buffer  */
  {

    if (pvd->npgBuffer >= npgBufferMax)/* current buff size maxed out       */
      fSuccess++;                      /* indicate ok                       */

    else                               /* grow this buffer                  */
      p = VDHReallocPages(pvd->pBuffer,
                          npgBufferMax,
                          NULL);       /* max siz                           */
  }

  if (!fSuccess && p)                  /* buffer was successfully allocated */
  {
    pvd->pBuffer = p;                  /* update new address                */
    pvd->npgBuffer = npgBufferMax;     /* update new size                   */
    fSuccess++;                        /* all's ok                          */
  }
  return  fSuccess;                    /* go away                           */
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAShrinkBuffer()
 *
 * DESCRIPTION   = Shrink specified VDM's virtual buffer
 *
 *                 This routine's purpose is to shrink the virtual buffer to
 *                 a minimum possible size.  The palette buffer and sprite
 *                 buffer is also deallocated.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAShrinkBuffer(HVDM hvdm)
{
  PVOID p;
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** If new size is zero
  */

  if (!pvd->npgBufferReq && pvd->pBuffer)
  {
    VDHFreePages(pvd->pBuffer);        /* free the entire LVB plane buffer  */
    pvd->pBuffer = NULL;               /* set null address                  */
    pvd->npgBuffer = 0;                /* zero out buffer size              */

    /*
    ** Free 4K-page allocated for palette, sprite & co-proc state
    */

    VDHFreePages(pvd->Palette_Buf);    /* free palette/sprite/state buffs   */
    pvd->Palette_Buf = NULL;           /* set null address                  */
  }

  /*
  ** If there's still valid data
  */

  else

    if (pvd->npgBufferReq < pvd->npgBuffer)
    {

    /*
    ** Shrink the plane buffer
    */

      p = VDHReallocPages(pvd->pBuffer,
                          pvd->npgBufferReq,
                          NULL);
      AssertNONZERO(p);
      pvd->pBuffer = p;                /* update with new address           */
      pvd->npgBuffer = pvd->npgBufferReq;/* update with new buffer size     */
    }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGALockIO()
 *
 * DESCRIPTION   = Prevent VDM from doing further I/O
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = I/O inhibited
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  /*
  ** Claim the IOOWNED bit
  */

  while (vdhBTS(&pvd->flVDMXGA,
                LOG2(VDM_IOOWNED)))    /* set I/O blocked                   */
  {
    ResetEventSem(pvd->hevXGAWakeUp);
    pvd->flVDMXGA |= VDM_IOWAKEME;     /* indicate VDM at rest              */

    if (pvd->flVDMXGA&VDM_IOOWNED)     /* I/O still blocked                 */
    {

      if (!VDHWaitEventSem(pvd->hevXGAWakeUp,
                           MAX_VDM_WAIT))/* wait                            */
        break;             /* 8514 FLAG: -- assume we got ERROR_TIMEOUT     */
    }
    pvd->flVDMXGA &= ~VDM_IOWAKEME;    /* indicate VDM awaken               */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAEnterIO()
 *
 * DESCRIPTION   = Verify that VDM is allowed to do I/O
 *
 * INPUT         = None
 *
 * OUTPUT        = I/O may proceed
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGAEnterIO(register ULONG port,ULONG n)
{

  while (vdhBTS(&VDMData.flVDMXGA,
                LOG2(VDM_IOOWNED)))
  {
    ResetEventSem(VDMData.hevXGAWakeUp);
    VDMData.flVDMXGA |= (VDM_IOWAKEME|VDM_BLOCKED);

    /*
    ** Now that we've armed the WAKEUP semaphore and set the WAKEME
    ** bit, make sure IOOWNED still set;  if it isn't, then we may have
    ** missed the chance to be awakened, not to mention the fact that it
    ** may be moot now anyway
    */

    if (VDMData.flVDMXGA&VDM_IOOWNED)
    {

      /*
      ** serialize access to the video state
      */

      RequestMutexSem(VDMData.hmxXGAState);/*                               */

      /*
      ** This will convey to the Shield that the VDM is suspended
      */

      vXGAUpdateShieldState(CURRENT_VDM);
      ReleaseMutexSem(VDMData.hmxXGAState);/*                               */

      if (!WaitEventSem(VDMData.hevXGAWakeUp))
        return  FALSE;          /* FLAG:-- assume we got ERROR_INTERRUPT    */

      /*
      ** due to DosKillProcess by Shell
      */
    }

    VDMData.flVDMXGA &= ~VDM_IOWAKEME;
  }

  /*
  ** Check to see if we should disable trapping after first access now
  */

  if ((VDMData.flVDMXGA&(VDM_FGND|VDM_IOTRAPPED)) == VDM_FGND)
  {
    register INT i;
    register INT k = port&0x000f;      /* determine trap handler index      */


    switch (k)
    {
      case  AXGA_OPERATING_MODE :      /* don't disable Operating Mode Reg  */
        break;
      case  AXGA_APERTURE_CONTROL :    /* don't disable Aperture Control    */
        break;
      case  AXGA_VIRTUAL_MEMORY_CONTROLLER :/* don't disable VM Control Reg */
        break;
      case  AXGA_APERTURE_INDEX :      /* don't disable Aperture Index Reg  */
        break;
      case  AXGA_INDEX_SELECT :        /* disable index select register     */
        VDHSetIOHookState(CURRENT_VDM,
                          port,
                          1,
                          &iohXGAirregIndex,
                          FALSE);
        break;
      default  :

        if (k < AXGA_INDEX_SELECT)
        {                              /* I/O Register 21x2 - 21x9?         */
          VDHSetIOHookState(CURRENT_VDM,
                            port,
                            1,
                            &aiohBReg[k],
                            FALSE);
        }

        else
        {                              /* Index Register 21xB - 21xF        */
          VDHSetIOHookState(CURRENT_VDM,
                            port,
                            1,
                            &iohXGAirregData,
                            FALSE);
        }
        break;
    }
  }
  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAExitIO()
 *
 * DESCRIPTION   = Mark VDM I/O completed
 *
 * INPUT         = None
 *
 * OUTPUT        = I/O completed
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAExitIO()
{
  VDMData.flVDMXGA &= ~VDM_IOOWNED;

  if (VDMData.flVDMXGA&VDM_IOWAKEME)
    PostEventSem(VDMData.hevXGAWakeUp);
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAInitMap()
 *
 * DESCRIPTION   = Initialize data for mapping entries
 *
 *                 This registered subroutine is called either at create
 *                 time or when the first page fault occurs.  Depending on
 *                 the moment the page 640K since that region will already
 *                 be locked during foreground.
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vXGAInitMap(HVDM hvdm)
{

  /*
  ** Allocate EVENT semaphore to serialize LIM memory processing
  */

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


  if (!vXGAAllocTbl(hvdm))
    return  FALSE;

  /*
  ** Indicate VDM instance data ok if map/unmap notification occurs
  */

  VDMData.flVDMXGA &= ~VDM_NOTDONE;
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAMapHndlr()
 *
 * DESCRIPTION   = Handle Lim Map notification
 *
 *                 This registered subroutine is called each time pages are
 *                 mapped.
 *
 *                 Note: that before a map notification occurs, an unmap
 *                       notification was sent.
 *
 * INPUT         = hvdm -> VDM
 *                 LinAddr -> linear address to map
 *                 Pages -> #pages to map
 *                 Flag  -> indicates whether the area about to be mapped is:
 *                          invalid, linear, physical, black hole, or switch map.
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID EXPENTRY VXGAMapHndlr(HVDM hvdm,ULONG LinAddr,ULONG Pages,ULONG flag)
{
  TBLMAP_S *Tblptr;                    /* temp variable to track tbl
                                          entries                           */
  INT i;
  USHORT j = 0;                        /* indicator for address 0
                                                                            */
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** Ignore any notifications while we're on our way out
  */

  if (pvd->flVDMXGA&VDM_GOINGDOWN)     /* VDM terminating                   */
    return ;

  /*
  ** Ignore all mappings to Black Holes and Invalid regions
  */

  if ((flag == VDHMT_BLACK_HOLE) || (flag == VDHMT_INVALID))
    return ;

  /*
  ** Ignore all mappings if we got an Int4B notification                    
  */

  if (pvd->flVDMXGA & VDM_INT4B)       /* VDM terminating                   */
    return ;                                                    /*          */

  /*
  ** Don't need to map addresses between A00000 - C00000 or anything
  ** above A0000 that has been mapped physical
  */

  if (LinAddr >= 0xA0000)              /* don't even bother if addr outa
                                          range                             */

    if ((flag == VDHMT_PHYSICAL) || (LinAddr < 0xC0000) || /*               */
       (LinAddr == 0xFF000))           /*                                   */
      return ;

  for (i = nConfigStart; i <= nConfigEnd; i++)
  {

    if (XGAENV[i].IORegBase)

      if ((LinAddr == XGAENV[i].ROMAddr) || /* don't map the 8K ROMAddr     */
         (LinAddr == (XGAENV[i].ROMAddr-4096)))
        return ;
  }

  /*
  ** Can't do anything until the table in the VDMData area is prepped
  ** and ready to go
  */

  if (pvd->flVDMXGA&VDM_NOTDONE)       /* VDMDATA not set up yet            */
  {

    if (!vXGAInitMap(hvdm))            /* initialize setup for mappin       */
      return ;
  }

  /*
  ** We are only interested in addresses in the 640K DOS region at
  ** create time.  After then, all maps are ignored.
  */

  if ((LinAddr < 0xa0000) &&           /* ignore addresses <640K since
                                          already                           */
     (pvd->flVDMXGA&VDM_640KMAPPED))   /* ...added to table                 */
    return ;

  /*
  ** Ignore map notification for address 1Meg unless 0 is already mapped
  ** because XMS maps the 64K region starting from 1 Meg to address 0.
  ** If 0 is already in the table and 1 Meg is then mapped, then it
  ** is possible that the A20 line was turned on and this is a valid
  ** entry.
  */

  if (LinAddr == 0x100000)             /* address being mapped = 1 Meg
                                                                            */
  {                                    /*                                   */
    Tblptr = pvd->TblMap;              /* set to start of map table
                                                                            */

    for (i = 0; i < pvd->TblEntriesPresent; i++)/* search thru table
                                                                            */
    {                                  /*                                   */

      if (Tblptr->MapAddr == (PBYTE)-1)/* looking for addr 0                */
      {                                /*                                   */
        j = 1;                         /* we found it                       */
        break;                         /* search no more                    */
      }
      Tblptr++;                        /* next table entry                  */
    }

    if (!j)                            /* no mapping for address 0 in table
                                                                            */
      return ;                         /* don't map 1 Meg                   */
  }

  /*
  ** Treat address 0 as a special case.  Change to address of -1.
  ** This is to distinguish it from an available slot to a used slot.
  */

  if (!LinAddr)                        /* request to map address 0          */
    LinAddr = -1;                      /* make a valid address for the map
                                          tbl                               */
  RequestMutexSem(pvd->hmxXGAMapSem);  /* wait for mapping semaphore        */

  if (pvd->TblEntriesPresent == pvd->TblEntries)/* no available entry       */
  {
    vXGAGetLIMMem(hvdm,
                  NULL);               /* get bigger table                  */
  }
  Tblptr = pvd->TblMap;                /* set to start of map table         */
  i = 0;

  while ((i < pvd->TblEntries) &&      /* search through entire table       */
     (Tblptr->MapAddr))                /* until an empty structure found    */
  {
    i++;                               /* next entry count                  */
    Tblptr++;                          /* point to next Table structure     */
  }
  Tblptr->MapAddr = (PBYTE)LinAddr;    /* set linear addr into MapAddr      */
  Tblptr->MapPages = Pages;            /* set cpages into MapPages          */
  pvd->TblEntriesPresent++;            /* increment # entries present       */

  if ((pvd->flVDMXGA&(VDM_MMIOINIT|VDM_FGND)) == (VDM_MMIOINIT|VDM_FGND))
    vXGAGetLIMMem(hvdm,
                  Tblptr);             /* lock down LIM memory              */
  ReleaseMutexSem(pvd->hmxXGAMapSem);  /* clear mapping semaphore           */
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAUnMapHndlr()
 *
 * DESCRIPTION   = Handle Lim Unmap notification
 *
 *                 This registered subroutine is called each time pages
 *                 relvant to the VDM are unmapped.  Actually an unmap
 *                 notification is called before a map occurs, so it really
 *                 reflects the map that is about to occur on the specific
 *                 address.
 *
 * INPUT         = hvdm -> VDM
 *                 LinAddr -> linear address to unmap
 *                 Pages -> #pages to unmap
 *                 Flag  -> indicates whether the area about to be mapped is:
 *                          invalid, linear, physical, black hole, or switch map.
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID EXPENTRY VXGAUnMapHndlr(HVDM hvdm,ULONG LinAddr,ULONG Pages,ULONG flag)
{
  TBLMAP_S *Tblptr;                   /* temp variable to track tbl entries */
  INT i;
  INT NumberEntries = 0;
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** Can't do anything until the table in the VDMData area is prepped
  ** and ready to go.  Ignore all unmaps until create has completed
  ** or if the VDM is terminating.
  */

  if (pvd->flVDMXGA&(VDM_NOTDONE|VDM_GOINGDOWN))
    return ;

  /*
  ** Ignore the following addresses:
  ** - Between A0000-C0000.  These areas will not be in the table
  ** and are already taken care of by VVGA.
  */
/*  if (LinAddr < 0xc0000)         **don't even bother if addr outa range ***/
/*    return;                                                               */

  if ((LinAddr >= 0xa0000) &&       /* don't even bother if addr outa range */
     (LinAddr < 0xc0000))
    return ;

  /*
  ** Treat address 0 as a special case.  Change to address of -1.
  */

  if (LinAddr == 0)                    /* request to map address 0          */
    LinAddr = -1;                      /* make a valid address for the map
                                          tbl                               */
  RequestMutexSem(pvd->hmxXGAMapSem);  /* wait for mapping semaphore        */
  i = 0;                               /* initialize counter                */
  Tblptr = pvd->TblMap;                /* set to top of map table           */

  while ((i < pvd->TblEntries) &&      /* search through entire tbl         */
     (Tblptr->MapAddr != (PBYTE)LinAddr))/* until found match               */
  {
    i++;                               /* next entry count                  */
    Tblptr++;                          /* point to next Table structure     */
  }

  if (i < pvd->TblEntries)             /* found a match                     */
  {

    if (Tblptr->MapHandle)             /* previsouly locked                 */
    {
      VDHUnlockMem(Tblptr->MapHandle); /* unlock MapHandle                  */
      Tblptr->MapHandle = 0;           /* clear out MapHandle               */
    }
    Tblptr->MapAddr = 0;               /* set to empty structure            */
    pvd->TblEntriesPresent--;          /* adjust # entries present          */
  }
  ReleaseMutexSem(pvd->hmxXGAMapSem);  /* clear mapping semaphore           */
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAGetLimMem()
 *
 * DESCRIPTION   = Allocate memory for LIM Map notification
 *
 *                 This registered subroutine is called to either allocate a
 *                 table to record LIM map/unmap notifications or to lock
 *                 down the corresponding LIM memory.
 *
 * INPUT         = hvdm -> VDM
 *                 EntryAddr -> address of TblMap structure
 *                    0 = no entries available (allocate table)
 *                   !0 = address of current entry (lock LIM memory)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAGetLIMMem(HVDM hvdm,TBLMAP_S *EntryAddr)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  PBYTE rc;
  PBYTE TempAddr;                      /*                                   */

  pvd->flVDMXGA |= VDM_GETLIMMEM;      /* indicate memory request           */

  while (pvd->flVDMXGA&VDM_GETLIMMEM)  /* loop until obtain memory          */
  {
    pvd->flVDMXGA &= ~VDM_GETLIMMEM;   /* assume it will work               */

    if (!EntryAddr)                    /* no value specified                */
      rc = vXGAAllocTbl(hvdm);         /* allocate LIM map table            */

    else                               /* lock LIM memory                   */
    {
      TempAddr = EntryAddr->MapAddr;   /*                                   */

      if (TempAddr == (PBYTE)-1)       /*                                   */
        TempAddr = 0;                  /*                                   */
      (HLOCK)rc = (EntryAddr->MapHandle = LOCKMEM(TempAddr,
                                                  EntryAddr->MapPages));
    }

    if (!rc)                           /* error occurred                    */
    {
      vXGAPopupErr();                  /* spit out the message              */

      if (!EntryAddr)                  /* trying to get bigger table        */
      {
        pvd->flVDMXGA |= VDM_GETLIMMEM;/* time to spin                      */
        VDHPostEventSem(pvd->hevXGAFGevent);/* give FG the go-ahead         */
        ResetEventSem(pvd->hevXGALIMMem);/* clear semaphore                 */
        VDHWaitEventSem(pvd->hevXGALIMMem,
                        MAX_VDM_WAIT); /* 4ever & aday                      */
      }
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadOpMode()
 *
 * DESCRIPTION   = Read XGA operating mode register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA operating mode register (AXGA_).
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadOpMode(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[0];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteOpmode()
 *
 * DESCRIPTION   = Write XGA Operating Mode er
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the XGA operating mode register (AXGA_).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteOpMode(BYTE bData,ULONG port,PCRF pcrf)
{
  register int i;
  int xga_mode;
  SHORT instance;

  instance = (int)(port >> 4)&0x0f;

  if (VDMData.vXGARegs[instance].abregXGAIOReg[0] == bData)
  {                                                                  //          
     if (!((bData == 4) && (VDMData.flVDMXGA&VDM_OPMODEXGA)))        //          
        return ;                      /* nothing to do, get out                  */
  }                                                                  //          

/*          Moved down after VXGAEnterIO.  VDMData.vXGARegs[instance].abregXGAIOReg[0] = bData; */
  /*
  ** if current VDM is background and the requested mode isn't
  ** Extended Graphics mode then go ahead and shadow it
  */

  if (!(VDMData.flVDMXGA&VDM_FGND) && !(bData&4))
  {                                    /*                                   */

    if (bData == 3 || bData == 0x11)
    {                                  /*                                   */
      VDMData.nXGAin132ColConfig = instance;/*                              */
      return ;                         /*                                   */
    }

    else
    {                                  /*                                   */

      if (bData == 1 && VDMData.nXGAin132ColConfig == instance)
      {                                /*                                   */
        VDMData.nXGAin132ColConfig = -1;/*                                  */
        return ;                       /*                                   */
      }                                /*                                   */
    }                                  /*                                   */
  }

  if (vXGAEnterIO(port,
                  1))
  {
    OUTB(port,
         bData);
    VDMData.vXGARegs[instance].abregXGAIOReg[0] = bData;         /*         */

    if (!(bData&4))
    {                                  /* if leaving native mode            */

      /*
      ** tell VVGA to resume save/restore the current XGA
      ** leaving native mode is the same one that booted
      ** up in VGA mode
      */

      if ((instance == InitXGAinVGA) && hvddVideo)
      {
        VDHRequestVDD(hvddVideo,
                      CURRENT_VDM,
                      VVDDEVREQ_SAVERESTORE,
                      (PVOID)TRUE,
                      NULL);
      }

      /*
      ** if no configurations are in xga mode then unlock
      */

      xga_mode = FALSE;

      for (i = nConfigStart; i <= nConfigEnd; i++)
      {

        if (XGAENV[i].IORegBase)
        {

          if (VDMData.vXGARegs[i].abregXGAIOReg[0]&4)
          {
            xga_mode = TRUE;
            break;
          }
        }
      }

      if (!xga_mode)
      {
        VDMData.flVDMXGA &= ~VDM_IOINIT;/* Clear Extended Mode flag         */

        /*
        ** tell VVGA no need to repaint on the next session switch
        */

        if (hvddVideo)
        {
          VDHRequestVDD(hvddVideo,
                        CURRENT_VDM,
                        VVDDEVREQ_REPAINT,
                        (PVOID)TRUE,
                        NULL);
        }

        /*
        ** if VDM memory has been locked down
        */

        if (VDMData.flVDMXGA&VDM_LOCKED)
        {

          /*
          ** unlock VDM memory
          */

          vXGALockVDM(VDMData.hvdmXGA,
                      FALSE);
        }

        /*
        **        Prevent background VDM from using the XGA Coprocessor
        **
        ** NOTE:  ROM area is already reserved and mapped invalid by the VBIOS
        **        VDD so there is no need for the XGA VDD to do this.
        **        However, it appears that for XGAs on the planar, there is no
        **        ROM stamp so the ROM area (including memory mapped registers)
        **        was ignored by VBIOS.  It was decided for VDDInit to do the
        **        ReservePages, and Create to do the MapPages anyways.
        */

        for (i = nConfigStart; i <= nConfigEnd; i++)
        {

          if ((XGAENV[i].IORegBase) && /* make sure valid                   */
             (!XGAENV[i].DupROMAddr))
          {                            /* and not duplicate@                */

            /*
            ** make each ROM page invalid
            */

            PRINTDEBUGa("*****  VDHMapPages invalid %x \n", VDMData.hvdmXGA);

            XGAENV[i].MapTarget.vdhmt_hmap = VDMData.mmr_hmap[i];/*
                                                                            */
            VDHMapPages(&XGAENV[i].MapSource,
                        &XGAENV[i].MapTarget,
                        VDHMT_INVALID);/* trap page fault                   */
          }
        }
        VDMData.flVDMXGA &= ~VDM_MMIOINIT;/* reset mm regs used             */
      }
    }

    else
    {
      VDMData.flVDMXGA |= VDM_IOINIT;  /* Extended Graphics Mode            */
      VDMData.flVDMXGA &= ~VDM_OPMODEXGA; /* Clear first time flag             */

      if (VDMData.nSaveRestoreConfig == -1)/* must identify XGA             */
        VDMData.nSaveRestoreConfig = instance;/* trap this XGA              */

      /*
      ** tell VVGA to repaint on the next session switch
      */

      if (hvddVideo)
      {
        VDHRequestVDD(hvddVideo,
                      CURRENT_VDM,
                      VVDDEVREQ_REPAINT,
                      (PVOID)TRUE,
                      NULL);
      }

      /*
      ** tell VVGA to NOT save/restore the only XGA in the
      ** the system that is currently set to enhanced mode
      */

      if ((instance == InitXGAinVGA) && hvddVideo)
      {
        VDHRequestVDD(hvddVideo,
                      CURRENT_VDM,
                      VVDDEVREQ_SAVERESTORE,
                      (PVOID)FALSE,
                      NULL);
      }

      vXGAUpdateShieldState(CURRENT_VDM);                       /*          */

    }
    vXGAExitIO();
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadApertureCntl()
 *
 * DESCRIPTION   = Read XGA aperture control register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 reads from bData == output data the XGA aperture control
 *                 register (AXGA_).  port == port address to write pcrf ->
 *                 VDM register frame Returns data from port
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadApertureCntl(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteApertureCntl()
 *
 * DESCRIPTION   = Write XGA aperture control register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the XGA aperture control register (AXGA_).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteApertureCntl(BYTE bData,ULONG port,PCRF pcrf)
{
  SHORT instance = (port >> 4)&0x0f;   /* XGA instance                      */
  ULONG rc;                            /* return from unmapA0000            */

/*  INT3();                                                                 */

  if (!(VDMData.flVDMXGA&VDM_FGND))
  {                                    /*                                   */

    VDMData.vXGARegs[instance].abregXGAIOReg[port&0x0f] = bData;  /* 73890 */
    return;                                                       /* 73890 */

/*73890    if (VDMData.vXGARegs[instance].abregXGAIOReg[1] == bData) */ /*             */
/*73890      return ; */             /* same value, nothing to do, get out           */
  }                                    /*                                   */

  if (vXGAEnterIO(port,
                  1))
  {
    OUTB(port,
         bData);

       /*
       ** shadow the Aperture setting
                                                                            */

    VDMData.vXGARegs[instance].abregXGAIOReg[port&0x0f] = bData;

    switch (bData)
    {
      case 0 :                         /* reset aperture?                   */

        if (VDMData.ApertSource[instance].vdhms_laddr)
        {

          /*
          ** CAUTION - Don't clear vdhmt_hmap
          */

          VDHMapPages(&VDMData.ApertSource[instance],
                      &VDMData.ApertTarget[instance],
                      VDHMT_INVALID);
          VDHGetError();               // get error rc from mappages           
          VDMData.ApertSource[instance].vdhms_laddr = 0L;
          VDMData.nApertureEnabled--;
        }
        break;
     case 1 :                         /* enable A0000?                     */

        /*
        ** Tell VVGA to unmap the a0000                                     
        */

        rc = VDHRequestVDD(hvddVideo,                           //          
                           CURRENT_VDM,                         //          
                           VVDDEVREQ_UNMAPVRAM,                 //          
                           (PVOID)TRUE,                         //          
                           NULL);                               //          

        if (VDMData.ApertSource[instance].vdhms_laddr)
        {

          /*
          ** CAUTION - Don't clear vdhmt_hmap
          */

          VDMData.ApertSource[instance].vdhms_laddr = 0xa0000;/*            */
          VDHMapPages(&VDMData.ApertSource[instance],
                      &VDMData.ApertTarget[instance],
                      VDHMT_INVALID);
          VDHGetError();               // get error rc from mappages           
          VDMData.nApertureEnabled--;
        }

/*          VDMData.ApertSource[instance].vdhms_laddr =                     */
/*                                        XGAENV[instance].VRAMAddr;          */

        VDMData.ApertSource[instance].vdhms_laddr = 0xa0000;/*              */
        VDMData.ApertTarget[instance].vdhmt_laddr = EGAVGAMEM_START;
        VDMData.ApertTarget[instance].vdhmt_hmap = 0L; /*init handle           */
        VDHMapPages(&VDMData.ApertSource[instance],
                    &VDMData.ApertTarget[instance],
                    VDHMT_PHYSICAL);
        VDHGetError();                 // get error rc from mappages           
        VDMData.nApertureEnabled++;
        break;
      case 2 :                         /* enable B0000;                     */

        /*
        ** Tell VVGA to unmap the b0000                                     
        */

        rc = VDHRequestVDD(hvddVideo,                           //          
                           CURRENT_VDM,                         //          
                           VVDDEVREQ_UNMAPVRAM,                 //          
                           (PVOID)TRUE,                         //          
                           NULL);                               //          

        if (VDMData.ApertSource[instance].vdhms_laddr)
        {

          /*
          ** CAUTION - Don't clear vdhmt_hmap
          */

          VDMData.ApertSource[instance].vdhms_laddr = 0xb0000;/*            */
          VDHMapPages(&VDMData.ApertSource[instance],
                      &VDMData.ApertTarget[instance],
                      VDHMT_INVALID);
          VDHGetError();               // get error rc from mappages           
          VDMData.nApertureEnabled--;
        }

/*          VDMData.ApertSource[instance].vdhms_laddr =                     */
/*                                        XGAENV[instance].VRAMAddr;          */

        VDMData.ApertSource[instance].vdhms_laddr = 0xb0000;/*              */
        VDMData.ApertTarget[instance].vdhmt_laddr = MONOMEM_START;
        VDMData.ApertTarget[instance].vdhmt_hmap = 0L; /*init handle           */
        VDHMapPages(&VDMData.ApertSource[instance],
                    &VDMData.ApertTarget[instance],
                    VDHMT_PHYSICAL);
        VDHGetError();                 // get error rc from mappages           
        VDMData.nApertureEnabled++;
        break;
    }
    VDMData.flVDMXGA |= VDM_IOINIT;
    vXGAExitIO();
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadReserved()
 *
 * DESCRIPTION   = Read XGA reserved register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA I/O Register 21x2 or 21x3..
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadReserved(ULONG port,PCRF pcrf)
{
  return 0;
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteReserved()
 *
 * DESCRIPTION   = Write XGA aperture control register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the XGA I/O Register 21x2 or 21x3.
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteReserved(BYTE bData,ULONG port,PCRF pcrf)
{
  return ;
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadIntEnable()
 *
 * DESCRIPTION   = Read XGA interrupt enable register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA interrupt enable register (AXGA_).
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadIntEnable(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteIntEnable()
 *
 * DESCRIPTION   = Write XGA Interrupt Enable register
 *
 *                 This registered subroutine is called whenever a VDM writes
 *                 to the XGA interrupt enable register (AXGA_).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteIntEnable(BYTE bData,ULONG port,PCRF pcrf)
{
  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f] = bData;

  /*
  ** Allow data to be shadow without blocking the VDM
  */

  if (!(VDMData.flVDMXGA&VDM_FGND))    /*                                   */
    return ;                           /*                                   */

  if (vXGAEnterIO(port,
                  1))
  {
    OUTB(port,
         bData);
    VDMData.flVDMXGA |= VDM_IOINIT;
    vXGAExitIO();
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadIntStatus()
 *
 * DESCRIPTION   = Read XGA interrupt status register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA interrupt status register (AXGA_).
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadIntStatus(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteIntStatus()
 *
 * DESCRIPTION   = Write XGA aperture control register
 *
 *                 This registered subroutine is called whenever a VDM writes
 *                 to the XGA interrupt status register (AXGA_).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteIntStatus(BYTE bData,ULONG port,PCRF pcrf)
{
  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f] = bData;

  /*
  ** Allow data to be shadow without blocking the VDM
  */

  if (!(VDMData.flVDMXGA&VDM_FGND))    /*                                   */
    return ;                           /*                                   */

  if (vXGAEnterIO(port,
                  1))
  {
    OUTB(port,
         bData);
    VDMData.flVDMXGA |= VDM_IOINIT;
    vXGAExitIO();
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadVirtMemCntlr()
 *
 * DESCRIPTION   = Read XGA virtual memory controller register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA virtual memory controller register (AXGA_).
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadVirtMemCntlr(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteVirtMemCntlr()
 *
 * DESCRIPTION   = Write XGA virtual memory controller register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the XGA virtual memory controller register
 *                 (AXGA_).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteVirtMemCntlr(BYTE bData,ULONG port,PCRF pcrf)
{
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadVirtMemIntStatus()
 *
 * DESCRIPTION   = Read XGA virtual memory interrupt status register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA virtual memory controller register (AXGA_).
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadVirtMemIntStatus(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteVirtMemIntStatus()
 *
 * DESCRIPTION   = Write XGA virtual memory interrupt status register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the XGA virtual memory controller register
 *                 (AXGA_).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteVirtMemIntStatus(BYTE bData,ULONG port,PCRF pcrf)
{
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadApertureIndex()
 *
 * DESCRIPTION   = Read XGA aperture index register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA aperture index register (AXGA_).
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadApertureIndex(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(int)(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteApertureIndex()
 *
 * DESCRIPTION   = Write XGA aperture control register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the XGA aperture index register (AXGA_).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteApertureIndex(BYTE bData,ULONG port,PCRF pcrf)
{
  SHORT instance = (port >> 4)&0x0f;

  if (!(VDMData.flVDMXGA&VDM_FGND))                               /* 73890 */
  {                                                               /* 73890 */
                                                                  /* 73890 */
    VDMData.vXGARegs[instance].abregXGAIOReg[port&0x0f] = bData;  /* 73890 */
    return;                                                       /* 73890 */
  }                                                               /* 73890 */

  if (vXGAEnterIO(port,
                  1))
  {
    OUTB(port,
         bData);

/*     ** Map the current aperture to VRAM based on the index value **          */
/*                                                                          */
/*   if (VDMData.ApertSource[instance].vdhms_laddr) {                       */
/*                                                                          */
/*      ** CAUTION - Don't clear vdhmt_hmap **                               */

/*      VDHMapPages(&VDMData.ApertSource[instance],                         */
/*                  &VDMData.ApertTarget[instance],                         */
/*                  VDHMT_INVALID);                                         */
/*                                                                          */
/*      VDMData.ApertSource[instance].vdhms_laddr =                         */
/*                  XGAENV[instance].VRAMAddr + (bData * 65536);            */
/*                                                                          */
/*      VDHMapPages(&VDMData.ApertSource[instance],                         */
/*                  &VDMData.ApertTarget[instance],                         */
/*                  VDHMT_PHYSICAL);                                        */
/*   }                                                                      */

       VDMData.vXGARegs[instance].abregXGAIOReg[port&0x0f] = bData;
    VDMData.flVDMXGA |= VDM_IOINIT;
    vXGAExitIO();
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadMemAccess()
 *
 * DESCRIPTION   = Read Memory Access Mode Register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 a byte from the Memory Access Mode Register to get the
 *                 Pixel Size.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadMemAccess(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteMemAccess()
 *
 * DESCRIPTION   = Write to Memory Access Mode Register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes a byte to the Memory Access Mode Register to
 *                 change the Pixel Size.
 *
 * INPUT         = bLow == output data
 *                 port == port address to write
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteMemAccess(BYTE bLow,ULONG port,PCRF pcrf)
{

  if (vXGAEnterIO(port,
                  1))
  {
    OUTB(port,
         bLow);

    /*
    ** Now shadow the I/O Register
    */

    VDMData.vXGARegs[(port >> 4)&0x0f].abregXGAIOReg[port&0x0f] = bLow;
    VDMData.flVDMXGA |= VDM_IOINIT;
    vXGAExitIO();
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadIndex()
 *
 * DESCRIPTION   = Read I/O Register Index
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 the Index Register 21xA.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadIndex(ULONG port,PCRF pcrf)
{
  return  VDMData.vXGARegs[(port >> 4)&0x0f].abregXGAIOReg[port&0x0f];
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteIndex()
 *
 * DESCRIPTION   = Write to I/O Register Index
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the Index Register 21xA.
 *
 * INPUT         = bLow == output data
 *                 port == port address to write
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteIndex(BYTE bLow,ULONG port,PCRF pcrf)
{

  /*
  ** Now shadow the Index value
  */

  VDMData.vXGARegs[(port >> 4)&0x0f].abregXGAIOReg[INDEX_SELECT] = bLow;/*
                                                                            */

  /*
  ** Allow Index to be shadow without blocking the VDM
  */

  if (!(VDMData.flVDMXGA&VDM_FGND))    /*                                   */
    return ;                           /*                                   */

  if (vXGAEnterIO(port,
                  1))
  {
    OUTB(port,
         bLow);
    VDMData.flVDMXGA |= VDM_IOINIT;
    vXGAExitIO();
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadIndexDataByte()
 *
 * DESCRIPTION   = Read XGA index data register
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA Index Data Register 21xB - 21xF.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BYTE HOOKENTRY VXGAReadIndexDataByte(ULONG port,PCRF pcrf)
{
  register int instance = (port >> 4)&0x0f;
  register int j;
  BYTE b;


  if (VDMData.flVDMXGA & VDM_FGND)
  {
    j = INB((port & 0xfff0) + INDEX_SELECT);/* get index select from HW      */
  }

  else
  {
    j = VDMData.vXGARegs[instance].abregXGAIOReg[INDEX_SELECT];
  }
  b = VDMData.vXGARegs[instance].abregXGAIRData[j];

  /*
  ** Allow certain shadow registers to be read from background
  */

  if (!(VDMData.flVDMXGA&VDM_FGND))
  {                                    /*                                   */

    if (j < AINDX_SPRITEPALETTEIDXLOPREF || /*                              */
       j == AINDX_PALETTEMASK ||       /*                                   */
       j == AINDX_PALETTESEQUENCE ||   /*                                   */
       (j > AINDX_SPRITEPREFETCH && j <= AINDX_EXTCLOCKSELECT))/*
                                                                            */
      return  b;                       /*                                   */
  }                                    /*                                   */


  switch (j)
  {
//           case  AINDX_RESERVED0 :   /* return shadow of Reserved Register*/
//             break;
    case  AINDX_AUTOCONFIG :           /* return shadow of R/O Register     */
      break;
//           case  AINDX_DISPIDCOMPARATOR : /* return shadow of R/0 Register*/
//             break;
    case  AINDX_MYSTERYREG :           /* return shadow of R/0 Register     */
      break;
    case  AINDX_HORZSYNCPOSITION1 :    /* return shadow of W/O register     */
      break;
    case  AINDX_HORZSYNCPOSITION2 :    /* return shadow of W/O register     */
      break;
    default  :

      if (vXGAEnterIO(port,
                      1))
      {
        b = INB(port);
        VDMData.flVDMXGA |= VDM_IOINIT;
        vXGAExitIO();
      }
      break;
  }
  return  b;
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteIndexDataByte()
 *
 * DESCRIPTION   = Write XGA index data register
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to one of the XGA index data registers
 *                 (AXGA_INDEX_DATA_B - AXGA_INDEX_DATA_F).
 *
 * INPUT         = bData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteIndexDataByte(BYTE bData,ULONG port,PCRF pcrf)
{
  register int instance,j;

  instance = (int)(port >> 4)&0x0f;

  if (VDMData.flVDMXGA&VDM_FGND)
  {
    j = INB((port&0xfff0)+INDEX_SELECT);
  }

  else
  {
    j = VDMData.vXGARegs[instance].abregXGAIOReg[INDEX_SELECT];
  }

  switch (j)
  {
//           case  AINDX_RESERVED0 :   /* DO NOT WRITE to Index Register 0  */
//             break;
    case  AINDX_AUTOCONFIG :           /* ignore WRITE to R/0 Register      */
      break;
    case  AINDX_DISPIDCOMPARATOR :     /* ignore WRITE to R/0 Register      */
      break;
    case  AINDX_MYSTERYREG :           /* ignore WRITE to R/0 Register      */
      break;
    default  :

      /*
      ** Now shadow the data
      */

      VDMData.vXGARegs[instance].abregXGAIRData[j] = bData;

      if (!(VDMData.flVDMXGA&VDM_FGND))
      {                                /*                                   */

        if (j < AINDX_SPRITEPALETTEIDXLO || /*                              */
           j == AINDX_PALETTEMASK ||   /*                                   */
           j == AINDX_PALETTESEQUENCE || /*                                 */
           (j > AINDX_SPRITEPREFETCH && j <= AINDX_EXTCLOCKSELECT))/*
                                                                            */
          return ;                     /*                                   */
      }                                /*                                   */

      if (vXGAEnterIO(port,
                      1))
      {
        OUTB(port,
             bData);
        VDMData.flVDMXGA |= VDM_IOINIT;
        vXGAExitIO();

      /*
      ** Now tell the shield about the new changes if the                   
      ** conditions are A-OK
      */
        if (((j == AINDX_DISPCONTROL2)   ||
             (j == AINDX_HORZDISPENDLO)  ||
             (j == AINDX_VERTDISPENDHI)  ||
             (j == AINDX_VERTDISPENDLO)) &&
             (VDMData.vXGARegs[instance].abregXGAIOReg[0] == 4)) /*            */
           vXGAUpdateShieldState(CURRENT_VDM);
      }
      break;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteIndexWord()
 *
 * DESCRIPTION   = Write XGA Index Register Word Handler
 *
 *                 This registered subroutine is called whenever a VDM
 *                 writes to the XGA indexed register (ie, one of those
 *                 listed under AXGA_INDEX_SELECT).
 *
 * INPUT         = wData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteIndexWord(WORD wData,ULONG port,PCRF pcrf)
{
  register int instance = (port >> 4)&0x0f;
  WORD ioIndex;

  ioIndex = wData&0x00ff;

  switch (ioIndex)
  {
//           case  AINDX_RESERVED0:    /* DO NOT WRITE to Index Register 0  */
//             break;
    case  AINDX_AUTOCONFIG :           /* ignore WRITE to R/0 Register      */
      break;
    case  AINDX_DISPIDCOMPARATOR :     /* ignore WRITE to R/0 Register      */
      break;
    case  AINDX_MYSTERYREG :           /* ignore WRITE to R/0 Register      */
      break;
    default  :

      /*
      ** Now shadow the index
      */

      VDMData.vXGARegs[instance].abregXGAIOReg[INDEX_SELECT] = ioIndex;

      /*
      ** Now shadow the data
      */

      VDMData.vXGARegs[instance].abregXGAIRData[ioIndex] = BYTEOF(wData,
                                                                  1);

      if (!(VDMData.flVDMXGA&VDM_FGND))
      {                                /*                                   */

        if (ioIndex < AINDX_SPRITEPALETTEIDXLO || /*                        */
           ioIndex == AINDX_PALETTEMASK || /*                               */
           ioIndex == AINDX_PALETTESEQUENCE || /*                           */
           (ioIndex > AINDX_SPRITEPREFETCH && /*                            */
           ioIndex <= AINDX_EXTCLOCKSELECT))/*                              */
          return ;                     /*                                   */
      }                                /*                                   */

      if (vXGAEnterIO(port,
                      1))
      {


          _asm {
             mov  edx, port
             mov   ax, wData
             out   dx, ax
          }


        VDMData.flVDMXGA |= VDM_IOINIT;
        vXGAExitIO();

      /*
      ** Now tell the shield about the new changes if the                   
      ** conditions are A-OK
      */
        if (((ioIndex == AINDX_DISPCONTROL2)   ||
             (ioIndex == AINDX_HORZDISPENDLO)  ||
             (ioIndex == AINDX_VERTDISPENDHI)  ||
             (ioIndex == AINDX_VERTDISPENDLO)) &&
            (VDMData.vXGARegs[instance].abregXGAIOReg[0] == 4)) /* V2.1TPL24 */
           vXGAUpdateShieldState(CURRENT_VDM);
      }
      break;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAReadIndexDataWord()
 *
 * DESCRIPTION   = Read XGA Index Data Register Word Handler
 *
 *                 This registered subroutine is called whenever a VDM reads
 *                 from the XGA Index Data Register 21xB - 21xF.
 *
 * INPUT         = port == port address to read
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

WORD HOOKENTRY VXGAReadIndexDataWord(ULONG port,PCRF pcrf)
{
  register int instance = (port >> 4)&0x0f;
  register int j;
  WORD wData;


  if (VDMData.flVDMXGA&VDM_FGND)
  {
    j = INB((port&0xfff0)+INDEX_SELECT);/* get index select from HW         */
  }

  else
  {
    j = VDMData.vXGARegs[instance].abregXGAIOReg[INDEX_SELECT];
  }
  wData = VDMData.vXGARegs[instance].abregXGAIRData[j];

  switch (j)
  {
//           case  AINDX_RESERVED0 :   /* return shadow of Reserved Register*/
//             break;
    case  AINDX_AUTOCONFIG :           /* return shadow of R/O Register     */
      break;
//           case  AINDX_DISPIDCOMPARATOR : /* return shadow of R/0 Register*/
//             break;
    case  AINDX_MYSTERYREG :           /* return shadow of R/0 Register     */
      break;
    case  AINDX_HORZSYNCPOSITION1 :    /* return shadow of W/O register     */
      break;
    case  AINDX_HORZSYNCPOSITION2 :    /* return shadow of W/O register     */
      break;
    default  :

      /*
      ** Allow certain shadow registers to be read from background
      */

      if (!(VDMData.flVDMXGA&VDM_FGND))
      {                                /*                                   */

        if (j < AINDX_SPRITEPALETTEIDXLOPREF || /*                          */
           j == AINDX_PALETTEMASK ||   /*                                   */
           j == AINDX_PALETTESEQUENCE || /*                                 */
           (j > AINDX_SPRITEPREFETCH && j <= AINDX_EXTCLOCKSELECT))/*
                                                                            */
          return  wData;               /*                                   */
      }                                /*                                   */


      if (vXGAEnterIO(port,
                      1))
      {


          _asm {
             mov  edx, port
             in    ax, dx
             mov   wData, ax
          }


        VDMData.flVDMXGA |= VDM_IOINIT;
        vXGAExitIO();
      }
      break;
  }
  return  wData;
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAWriteIndexDataWord()
 *
 * DESCRIPTION   = Write XGA Index Register Word Handler
 *
 *                 This registered subroutine is called whenever a VDM writes
 *                 to the XGA indexed register (ie, one of those listed under
 *                 AXGA_INDEX_SELECT or AXGA_INDEX_DATA_B through
 *                 AXGA_INDEX_DATA_E).
 *
 * INPUT         = wData == output data
 *                 port  == port address to write
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAWriteIndexDataWord(WORD wData,ULONG port,PCRF pcrf)
{
  register int instance = (port >> 4)&0x0f;
  int j;                               /*                                   */
  WORD ioIndex;


  if ((port&0x000f) == 0x000a)
  {
    ioIndex = wData&0x00ff;

    switch (ioIndex)
    {
//           case  AINDX_RESERVED0 :   /* DO NOT WRITE to Index Register 0  */
//              break;
      case  AINDX_AUTOCONFIG :         /* ignore WRITE to R/0 Register      */
        break;
      case  AINDX_DISPIDCOMPARATOR :   /* ignore WRITE to R/0 Register      */
        break;
      case  AINDX_MYSTERYREG :         /* ignore WRITE to R/0 Register      */
        break;
      default  :

        /*
        ** Now shadow the index
        */

        VDMData.vXGARegs[instance].abregXGAIOReg[INDEX_SELECT] = ioIndex;

        /*
        ** Now shadow the data
        */

        VDMData.vXGARegs[instance].abregXGAIRData[ioIndex] = BYTEOF(wData,
                                                                    1);

        if (!(VDMData.flVDMXGA&VDM_FGND))
        {                              /*                                   */

          if (ioIndex < AINDX_SPRITEPALETTEIDXLO || /*                      */
             ioIndex == AINDX_PALETTEMASK || /*                             */
             ioIndex == AINDX_PALETTESEQUENCE || /*                         */
             (ioIndex > AINDX_SPRITEPREFETCH && /*                          */
             ioIndex <= AINDX_EXTCLOCKSELECT))/*                            */
            return ;                   /*                                   */
        }                              /*                                   */

        if (vXGAEnterIO(port,
                        1))
        {


             _asm {
                mov  edx, port
                mov   ax, wData
                out   dx, ax
             }


          VDMData.flVDMXGA |= VDM_IOINIT;
          vXGAExitIO();

      /*
      ** Now tell the shield about the new changes if the                   
      ** conditions are A-OK
      */
          if (((ioIndex == AINDX_DISPCONTROL2)   ||
               (ioIndex == AINDX_HORZDISPENDLO)  ||
               (ioIndex == AINDX_VERTDISPENDHI)  ||
               (ioIndex == AINDX_VERTDISPENDLO)) &&
               (VDMData.vXGARegs[instance].abregXGAIOReg[0] == 4)) /*            */
             vXGAUpdateShieldState(CURRENT_VDM);
        }
        break;
    }
  }

  else
  {

    /*
    ** writing word of data to 21xb-21xf
    */

    /*
    ** Data is being written to the index register.  If the
    ** register written to is one of those registers used
    ** by the Mod 90 BIOS *AND* the value being written is
    ** the same value in the shadow register, then ignore
    ** the request and go away.
    */

    if (!(VDMData.flVDMXGA&VDM_FGND))
    {                                  /*                                   */
      j = VDMData.vXGARegs[instance].abregXGAIOReg[INDEX_SELECT];/*
                                                                            */

      if (j < AINDX_SPRITEPALETTEIDXLOPREF || /*                            */
         j == AINDX_PALETTEMASK ||     /*                                   */
         j == AINDX_PALETTESEQUENCE || /*                                   */
         (j > AINDX_SPRITEPREFETCH &&  /*                                   */
         j <= AINDX_EXTCLOCKSELECT))
      {                                /*                                   */
        VDMData.vXGARegs[instance].abregXGAIRData[j] = /*                   */
           BYTEOF(wData,
                  0);                  /*                                   */
        return ;                       /*                                   */
      }
    }                                  /*                                   */

    if (vXGAEnterIO(port,
                    1))
    {


          _asm {
             mov  edx, port
             mov   ax, wData
             out   dx, ax
          }


      VDMData.flVDMXGA |= VDM_IOINIT;
      vXGAExitIO();

      /*
      ** Now tell the shield about the new changes if the                   
      ** conditions are A-OK
      */
      if (((ioIndex == AINDX_DISPCONTROL2)   ||
           (ioIndex == AINDX_HORZDISPENDLO)  ||
           (ioIndex == AINDX_VERTDISPENDHI)  ||
           (ioIndex == AINDX_VERTDISPENDLO)) &&
           (VDMData.vXGARegs[instance].abregXGAIOReg[0] == 4)) /*            */
         vXGAUpdateShieldState(CURRENT_VDM);
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGARWIndexDataDWord()
 *
 * DESCRIPTION   = Read/Write dword to XGA indexed register
 *
 *                 This registered subroutine is called whenever a VDM writes
 *                 to the XGA indexed register (ie, one of those listed under
 *                 AXGA_DISP_CONTROLLER_INDX).
 *
 * INPUT         = ulOutputDataport == data for dword writes
 *                 pulInputData     == pointer to put input data
 *                 port             == port address to write
 *                 flType           == I/O type
 *                 pcrf             -> VDM register frame
 *
 * OUTPUT        = Returns data from port
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

ULONG HOOKENTRY VXGARWIndexDataDword(ULONG ulOutputDataport,PBYTE pulInputData
                                      ,ULONG port,ULONG flType,PCRF pcrf)
{
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAPgFaultHndlr()
 *
 * DESCRIPTION   = Memory mapped registers fault hook
 *
 *                 When the coprocessor's memory mapped registers are
 *                 accessed, a page fault will occur:
 *
 *                 1.)  to determine the XGA the VDD is responsible for
 *                      save/restore if nSaveRestoreConfig has not yet been
 *                      determined
 *
 *                 2.)  to block the VDM if the co-processor was referenced
 *                      while running background
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAPgFaultHndlr(PVDM pvdmFault)
{
  INT count;

/* ULONG i;                                                                 */

  PRINTDEBUG("*****  I am in vXGAPgFaultHndlr \n");

/*  INT3();                                                                 */
  /*
  ** Hang out in here until successful
  */

  if (VDMData.flVDMXGA&VDM_FGND)       /* VDM foreground                    */
  {

    /*
    ** Interrogate which XGA is being touched and indicate it is the one to
    ** support for I/O trapping.  The address being referenced must fall
    ** within the range of the 128 byte memory mapped register area.
    */

    for (count = nConfigStart; count <= nConfigEnd; count++)
    {

      if (XGAENV[count].IORegBase)
      {

/*    i = XGAENV[count].COPAddr;                ** MM-regs base val  **          */
/*    if (((ULONG)pvdmFault >= i)  && ((ULONG)pvdmFault < i+128))           */
/*    {                                                                     */
/*       if (VDMData.nSaveRestoreConfig == -1)  ** must identify XGA **          */
/*          VDMData.nSaveRestoreConfig = count; ** trap this XGA     **          */
        /*
        ** Make all memory mapped pages present for the application
        */

        VDMData.flVDMXGA |= VDM_MMIOINIT;/* indic mm regs used              */

        for (count = nConfigStart; count <= nConfigEnd; count++)
        {

          if ((XGAENV[count].IORegBase) && /* make sure valid               */
             (!XGAENV[count].DupROMAddr))/* and not duplicate@              */
          {
            PRINTDEBUGa("*****  VDHMapPages physical %x\n", VDMData.hvdmXGA);

            XGAENV[count].MapTarget.vdhmt_hmap = 0L;/* init handle          */

            if (!VDHMapPages(&XGAENV[count].MapSource,
                             &XGAENV[count].MapTarget,
                             VDHMT_PHYSICAL))/* make page present           */
            {
              vXGAPopupErr();          /* issue error popup                 */
              return ;                 /* that's it for processing this
                                          fault                             */
            }
            VDMData.mmr_hmap[count] =  /*                                   */
               XGAENV[count].MapTarget.vdhmt_hmap;/*                        */
          }
        }

        /*
        ** Lock down the 640K DOS region to ensure memory present
        ** But only if no Int4B notification came in                        
        */

        /*
        ** fix up the extra page directory
        */

        if (!(VDMData.flVDMXGA & VDM_INT4B)) /*no Int4B supp                */
        {                                    /*                             */
          if  (!VDMData.DOSPTLinAddr)        /*VDM PD not setup             */
          {

            if (vXGAPDFixUp(VDMData.hvdmXGA,
                            &XGAENV[count]))/*                              */
            {                            /*                                 */
              vXGAPopupErr();            /* issue err popup                 */
              return ;                   /* return to caller                */
            }
          }

          if (vXGALockVDM(VDMData.hvdmXGA,
                          TRUE))         /* lock 640K errorr                */
            vXGAPopupErr();              /* issue err popup                 */
          break;                         /* don't bother checking other XGAs*/
        }                                /* end Int4B test                  */

/* }                                                                        */

      }
    }
  }

  else                                 /* VDM background/windowed           */
  {
    /*
    ** update the Shield with the mode information                          
    */
    RequestMutexSem(VDMData.hmxXGAState);
    vXGAUpdateShieldState(CURRENT_VDM);
    ReleaseMutexSem(VDMData.hmxXGAState);            /* end of              */

    VDMData.flVDMXGA |= VDM_BLOCKED;   /* block VDM                         */
    VDMData.flVDMXGA |= VDM_FROZEN;    /* about to be frozen                */
    vXGAAddEvent(VDMData.hvdmXGA,
                 VVDEVENT_MODE,
                 NULL,
                 0);                   /*                                   */
    VDHFreezeVDM(0);                   /* freeze that puppy                 */
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAPopupErr()
 *
 * DESCRIPTION   = Memory mapped registers fault hook error procedure
 *
 *                 Failure occured during page fault processing for one of
 *                 the following:
 *
 *                     1.)  Couldn't map the memory mapped I/O page valid
 *
 *                     2.)  Couldn't lock down 640K DOS region
 *
 * INPUT         = None
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY vXGAPopupErr()
{
  INT resp_val;

  /*
  ** Must set display to VGA mode before issuing popup.
  ** Suspend VDM from further processing.
  */

  VDMData.flVDMXGA |= VDM_BLOCKED;     /* indicate VDM suspended            */

/*  VXGASetBgnd(0);                           ** send this VDM backgnd    ***/

  vXGAEnableVGA(0);                    /* transition to VGA mode            */

  /*
  ** Send Int 10 notification to switch to mode 3
  */

  VDHArmContextHook(VDMData.hhookInt10Context,
                    VDMData.hvdmXGA);

  /*
  ** Wait for Int 10 to complete or timeout
  */

  VDMData.flVDMXGA &= ~VDM_INT2FWAKEME;
  ResetEventSem(VDMData.hevXGAWakeUp);
  VDHWaitEventSem(VDMData.hevXGAWakeUp,
                  MAX_VDM_WAIT);

  /*
  ** Now issue the message popup saying we're in trouble
  */

  POPUP(resp_val);                     /* spit out the message              */
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAInt10Context()
 *
 * DESCRIPTION   = INT 10 notification context routine
 *
 *                 This routine is created at VDM creation time through
 *                 VDHAllocHook.  It is called to set the display mode to
 *                 VGA while currently executing in XGA mode.
 *
 * INPUT         = p      == undefined
 *                 pcrf   -> VDM register frame (NULL if called from VDD)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VXGAInt10Context(PVOID p,register PCRF pcrf)
{
  VDHPushRegs(VDHREG_AX);

  /*
  ** set to mode 3
  */

  AX(pcrf) = 300;

  /*
  ** arm notification hook
  */

  VDHPushInt(INT10_SETMODE);
  VDHArmReturnHook(VDMData.hhookInt10Ret,
                   VDHARH_RECURSIVE_IRET);
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAInt10Return()
 *
 * DESCRIPTION   = INT 10 return hook routine
 *
 *                 This routine is created at VDM creation time through
 *                 VDHAllocHook.  It is called on completion of INT 10
 *                 notification.
 *
 * INPUT         = pvoid == undefined
 *                 pcrf  -> VDM register frame
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

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

  /*
  ** Indicate successful return from Int 10 notification
  */

  VDMData.flVDMXGA |= VDM_INT2FWAKEME;
  PostEventSem(VDMData.hevXGAWakeUp);
  VDHPopRegs(VDHREG_AX);
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGASysReqProc()
 *
 * DESCRIPTION   = DosRequestVDD router
 *
 *                 This subroutine is registered during VDD initialization
 *                 via VDHRegisterVDD, and receives requests from OS/2
 *                 applications.
 *
 * INPUT         = sgid   == screen group
 *                 ulFunc == function code
 *                 nbIn   -> input buffer size (0 if none)
 *                 pIn    -> input buffer
 *                 nbOut  -> output buffer size (0 if none)
 *                 pOut   -> output buffer
 *
 * OUTPUT        = SUCCESS
 *                     Zero
 *                 FAILURE
 *                     Error code (ie, invalid function, etc)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG EXPENTRY VXGASysReqProc(SGID sgid,ULONG ulFunc,ULONG nbIn,PVOID pIn,ULONG
                              nbOut,PVOID pOut)
{
  HVDM hvdm = INVALID_HVDM;


  if (sgid)
  {
    hvdm = VDHHandleFromSGID(sgid);

    if (hvdm)
    {

      if ((pVDMData(hvdm)->flVDMXGA&VDM_IOINIT) == VDM_IOINIT)   /*          */
        if (ulFunc >= VVDSYSREQ_QUERYMODE && ulFunc <= VVDSYSREQ_COPYBITMAP)
          return (apfnSysReq[ulFunc-VVDSYSREQ_QUERYMODE])(hvdm,
                                                          nbIn,
                                                          pIn,
                                                          nbOut,
                                                          pOut);
    }
  }
  return  VDDREQ_PASS;
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGASysQueryMode()
 *
 * DESCRIPTION   = Query mode data
 *
 *                 This subroutine processes the VVDSYSREQ_QUERYMODE function
 *                 filling in the given VVMODE structure.
 *
 * INPUT         = hvdm -> VDM
 *                 pvvm -> video mode packet
 *
 * OUTPUT        = SUCCESS
 *                     Zero
 *                 FAILURE
 *                     Error code (ie, invalid parameter, etc)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG PRIVENTRY vXGASysQueryMode(HVDM hvdm,ULONG ul1,PVOID p1,ULONG ul2,PVVMODE
                                 pvvm)
{
  register PVDMDATA pvd = pVDMData(hvdm);


  if (ul2 < sizeof(VVMODE) || !pvvm)
    return  ERROR_INVALID_PARAMETER;


  if (!(pvd->flVDMXGA&VDM_IOTRAPPED))
    return  ERROR_BAD_FORMAT;

  if ((pvd->flVDMXGA & (VDM_FGND | VDM_IOINIT)) == /* foreground and            */
     (VDM_FGND | VDM_IOINIT))                      /* in XGA mode               */
  {
    RequestMutexSem(pvd->hmxXGAState);
    *pvvm = pvd->vvmXGA;
    vXGADeleteEvent(hvdm,
                    VVDEVENT_MODE);
    ReleaseMutexSem(pvd->hmxXGAState);

    if (pvvm->vvm_nBitCount > 1)   /* valid mode structure?                   */
       return NO_ERROR;            /* return with mode info                   */
  }
  return  VDDREQ_PASS;             /* pass control to the next VVD in chain */
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGASysQueryCursor()
 *
 * DESCRIPTION   = Query cursor data
 *
 *                 This subroutine processes the VVDSYSREQ_QUERYCURSOR
 *                 function, filling in the given VVCURSOR structure.
 *
 * INPUT         = hvdm -> VDM
 *                 pvvc -> query cursor packet
 *
 * OUTPUT        = SUCCESS
 *                     Zero
 *                 FAILURE
 *                     Error code (ie, invalid parameter, etc)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG PRIVENTRY vXGASysQueryCursor(HVDM hvdm,ULONG ul1,PVOID p1,ULONG ul2,
                                   PVVCURSOR pvvc)
{

  if (ul2 < sizeof(VVCURSOR) || !pvvc)
    return  ERROR_INVALID_PARAMETER;

/*  memset(pvvc, 0, sizeof(VVCURSOR));                                      */

  return  VDDREQ_PASS;             /* pass control to the next VDD in chain */
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGASysQueryPalette()
 *
 * DESCRIPTION   = Query color data
 *
 *                 This subroutine processes the VVDSYSREQ_QUERYPALETTE
 *                 function, filling in the given RGB array.
 *
 * INPUT         = hvdm -> VDM
 *                 prgb -> RGB array
 *
 * OUTPUT        = SUCCESS
 *                     Zero
 *                 FAILURE
 *                     Error code (ie, invalid parameter, etc)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG PRIVENTRY vXGASysQueryPalette(HVDM hvdm,ULONG ul1,PVOID p1,ULONG ul2,
                                    register PRGB prgb)
{
  LONG rc = VDDREQ_PASS;         /* pass control to the next VVD as default */
  ULONG nColors;
  register INT i;
  register PVDMDATA pvd = pVDMData(hvdm);
  PBYTE pPalette = pvd->Palette_Buf;

  RequestMutexSem(pvd->hmxXGAState);
  nColors = 1 << pvd->vvmXGA.vvm_nBitCount;/* calculate # locations         */

  if (!prgb || ul2 < nColors *sizeof(RGB))
    rc = ERROR_INVALID_PARAMETER;

  else
  {

    if ((pvd->flVDMXGA&(VDM_FGND|VDM_IOINIT)) == /* foreground and          */
       (VDM_FGND|VDM_IOINIT))          /* in XGA mode                       */
    {
      vXGAGetPalette(hvdm);            /* read palette values into buffer   */

      /*
      ** Check for Direct Color Mode to return appropriate values
      */

      if (pvd->DCMode&0x0100)          /* Direct Color Mode                 */
      {
        nColors = nColors/2;           /* only need to read half palette    */

        if (!(pvd->DCMode&0x0001))     /* need to read upper half           */
          pPalette = pPalette+512;
      }

      /*
      ** Now read values from palette save buffer.
      ** A simple memcpy will not suffice, because the
      ** DAC data is stored RBGx and required order is BGR
      */

      for (i = 0; i < nColors; i++,
           prgb++)
      {
        prgb->bBlue = pPalette[i *4+2];
        prgb->bGreen = pPalette[i *4+3];
        prgb->bRed = pPalette[i *4+1];
      }
      vXGADeleteEvent(hvdm,
                      VVDEVENT_PALETTE);
    }
  }
  ReleaseMutexSem(pvd->hmxXGAState);
  return  rc;
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGAGetPalette()
 *
 * DESCRIPTION   = Save palette for supported XGA
 *
 *                 Reads the palette registers to save the 256 palette
 *                 combinations of RGB values of the supported XGA for this
 *                 VDM.  The color order saved is R,B,G,x,R,B,G,x,...
 *
 * INPUT         = hvdm -> VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGAGetPalette(HVDM hvdm)
{
  register PVDMDATA pvd = pVDMData(hvdm);
  XGAENV_S *pXGAENV = &XGAENV[CurConfig];
  register INT i;
  PBYTE pPalette = pvd->Palette_Buf;

  AssertNONZERO(pPalette);

  /*
  ** Indicate which XGA we're inquiring into
  */

  if (pvd->nSaveRestoreConfig != -1)   /* memory mapped regs touched        */
    pXGAENV = &XGAENV[pvd->nSaveRestoreConfig];
  pvd->DCMode = 0;                     /* init not Direct Color Mode        */

  /*
  ** Look for Direct Color Mode by querying Memory Access Mode Reg
  */

  if ((INB(pXGAENV->IORegBase+0x09)&0x07) == 4)/* 16 bits=DC mode           */
  {

    /*
    ** read Border Color index register to find out which half of
    ** the palette is to be restored
    */

    OUTB(pXGAENV->IORegBase+INDEX_SELECT,
         0x55);

    /*
    ** Shift the value obtained from the Border Color register
    ** 7 bits to the right.  And this value to get final result:
    ** Left byte = 01 --> Direct Color Mode
    ** Right byte = 00 --> Load upper half of palette 80-FF
    ** Right byte = 01 --> Load lower half of palette 0-7F
    */

    pvd->DCMode = (((INB(pXGAENV->IORegBase+INDEX_DATA) >> 7)|0x0100));
  }


    _asm
    {
         mov    ebx,pXGAENV                  ;setup pHog pointer
         mov    dx,word ptr [ebx].IORegBase  ;get Base IO port address
         add    dx,INDEX_SELECT              ;setup for index select A

         mov    ax,0466h                     ;setup Palette Sequence
         out    dx,ax                        ;  for R,B,G,x read

         mov    ax,0062h                     ;start palette read from
         out    dx,ax                        ;  offset zero

         mov    al,65h                       ;setup for palette read
         out    dx,al                        ;

         inc    dx                           ;setup 21xB for DWORD read

         mov    cx,256                       ;256 sets of R,B,G,x palette values
         mov    ebx,pPalette                 ;setup pointer to pPalette buffer
    ReadPalette:
         in     eax,dx                       ;read R,B,G,x value
         mov    dword ptr [ebx],eax          ;save it in the pPalette buffer
         add    ebx,4                        ;next pPalette DWORD location
         dec    cx                           ;
         jnz    ReadPalette                  ;
    }


}

/***************************************************************************
 *
 * FUNCTION NAME = vXGASysCopyLVB()
 *
 * DESCRIPTION   = Copy rectangle from VDM LVB
 *
 *                 This subroutine processes the VVDSYSREQ_COPYLVB function.
 *
 * INPUT         = hvdm -> VDM
 *                 ul1  == size of rect. desc.
 *                 prcl -> rectangle description
 *                 ul2  == size of shadow LVB buffer
 *                 pb   -> shadow LVB buffer
 *
 * OUTPUT        = SUCCESS
 *                     Zero
 *                 FAILURE
 *                     Error code (ie, invalid parameter, etc)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG PRIVENTRY vXGASysCopyLVB(HVDM hvdm,ULONG ul1,PRECTL prcl,ULONG ul2,PBYTE
                               pb)
{
  return  VDDREQ_PASS;         /* pass control to the next VDD in the chain */
}

/***************************************************************************
 *
 * FUNCTION NAME = vXGASysCopyBitmap()
 *
 * DESCRIPTION   = Copy rectangle from VDM bitmap
 *
 *                 This subroutine processes the VVDSYSREQ_COPYBITMAP
 *                 function.
 *
 * INPUT         = hvdm  -> VDM
 *                 ul1   == size of rect. desc.
 *                 pvvr  -> DD format and rectangle
 *                 ul2   == size of shadow LVB buffer
 *                 pbDst -> shadow LVB buffer
 *
 * OUTPUT        = SUCCESS
 *                     Zero
 *                 FAILURE
 *                     Error code (ie, invalid parameter, etc)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG PRIVENTRY vXGASysCopyBitmap(HVDM hvdm,ULONG ul1,PVVRECT pvvr,ULONG ul2,
                                  register PBYTE pbDst)
{
  INT x,y,nbRow;
  register PBYTE pbSrc;
  PVDMDATA pvd = pVDMData(hvdm);


  if (ul1 < sizeof(VVRECT) || !pvvr)
    return  ERROR_INVALID_PARAMETER;


  if (pvvr->vvr_ulDDFormat || !(pvd->flVDMXGA&VDM_IOTRAPPED))
    return  ERROR_BAD_FORMAT;

  RequestMutexSem(pvd->hmxXGAState);
  pbSrc = pvd->pBuffer;
  nbRow = pvd->vvmXGA.vvm_nCols *pvd->vvmXGA.vvm_nBitCount/8;
  y = pvvr->vvr_rcl.yBottom;
  pbSrc += nbRow *y;

  while (y >= pvvr->vvr_rcl.yTop)
  {

    for (x = 0; x < nbRow; x++)
      *pbDst++ = *pbSrc++;
    pbSrc -= nbRow *2;
    y--;
  }
  ReleaseMutexSem(pvd->hmxXGAState);
  return  NO_ERROR;
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGADevReqProc()
 *
 * DESCRIPTION   = VDHRequestVDD router
 *
 *                 This subroutine is registered during VDD initialization
 *                 via VDHRegisterVDD, and receives requests from other VDDs
 *                 that have have registered under the same name and use
 *                 VDHRequestVDD.  See VVD.H for a description of the
 *                 input/output buffers, if any.
 *
 * INPUT         = hvdm    -> VDM
 *                 ulFunc  == function code
 *                 pbufIn  -> input buffer (not used here)
 *                 pbufOut -> output buffer (not used here)
 *
 * OUTPUT        = SUCCESS
 *                     True
 *                 FAILURE
 *                     False (error code set via VDHSetError)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG EXPENTRY VXGADevReqProc(HVDM hvdm,ULONG ulFunc,PVOID pIn,PVOID pOut)
{

  if (ulFunc == VVDDEVREQ_PM_WINDOW)   /*                                   */
    vXGADevWindowsDeskTop(hvdm,
                          (BOOL)pIn);  /*                                   */
  return  VDDREQ_PASS;         /* pass control to the next VDD in the chain */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvXGADevWindowsDeskTop()
 *
 * DESCRIPTION   = Make a windowed VDM Seamless
 *
 *                 This subroutine processes the VVDDEVREQ_PM_WINDOWS
 *                 function, either enable/disable IOPL privilege and access
 *                 to A0000h.
 *
 * INPUT         = hvdm -> VDM
 *                 fSet == TRUE to make a windowed VDM SEAMLESS,
 *                         FALSE to release
 *
 * OUTPUT        = SUCCESS
 *                     Zero
 *                 FAILURE
 *                     Error code (ie, invalid parameter, etc)
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

LONG PRIVENTRY vXGADevWindowsDeskTop(HVDM hvdm,BOOL fSet)/*                 */
{                                      /*                                   */
  register PVDMDATA pvd = pVDMData(hvdm);/*                                 */
  INT i,j;                             /*                                   */
  USHORT ioPort;                       /*                                   
                                                                            */

  /*
  ** no-op if VDM is not currently background
  */

  if (!(pvd->flVDMXGA&VDM_FGND))
  {                                    /*                                   
                                                                            */

    /*
    ** mark VDM SEAMLESS
    */

    if (fSet)
    {                                  /*                                   */

      for (i = nConfigStart; i <= nConfigEnd; i++)
      {                                /*                                   
                                                                            */
        ioPort = XGAENV[i].IORegBase;  /*                                   */

        if (ioPort)
        {                              /*                                   */

          if (!XGAENV[i].DupROMAddr)
          {                            /*                                   
                                                                            */

            /*
            ** must NULL out map handle
            */

            XGAENV[i].MapTarget.vdhmt_hmap = 0L;/*                          
                                                                            */

            /*
            ** make Memory Mapped I/O registers present
            */

            VDHMapPages(&XGAENV[i].MapSource, /*                            */
                        &XGAENV[i].MapTarget, /*                            */
                        VDHMT_PHYSICAL);/*                                  */
            pvd->mmr_hmap[i] = XGAENV[i].MapTarget.vdhmt_hmap;/*            */
          }                            /*                                   
                                                                            */

          /*
          ** Disable trapping for I/O Registers 21x0 - 21x9
          */

          for (j = 0; j < AXGA_INDEX_SELECT; j++)
          {                            /*                                   */
            VDHSetIOHookState(CURRENT_VDM,
                              ioPort++,
                              1,       /*                                   */
                              &aiohBReg[j],
                              FALSE);  /*                                   */
          }                            /*                                   
                                                                            */

          /*
          ** Disable trapping for Index Registers 21xA
          */

          VDHSetIOHookState(CURRENT_VDM, /*                                 */
                            XGAENV[i].IORegBase+0x0a,
                            1,         /*                                   */
                            &iohXGAirregIndex,
                            FALSE);    /*                                   
                                                                            */

          /*
          ** Disable trapping for Index Registers 21xB - 21xF
          */

          for (j = AXGA_INDEX_DATA_B; j < AXGA_TOTAL; j++)
          {                            /*                                   */
            VDHSetIOHookState(CURRENT_VDM, /*                               */
                              XGAENV[i].IORegBase+j,
                              1,       /*                                   */
                              &iohXGAirregData,
                              FALSE);  /*                                   */
          }                            /*                                   
                                                                            */
        }                              /*                                   */
      }                                /*                                   */
    }                              /* FLAG:may required ELSE case           */
  }                                    /*                                   */
}                                      /*                                   */

/***************************************************************************
 *
 * FUNCTION NAME = vXGADeleteEvent()
 *
 * DESCRIPTION   = Delete video event from the "event queue"
 *
 * INPUT         = hvdm    -> hvdm
 *                 iEvent  == event ordinal
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vXGADeleteEvent(HVDM hvdm,INT iEvent)
{
  VVPOST vvp;


  if (hvddVideo)
  {
    vvp.vvp_iEvent = iEvent;
    vvp.vvp_pEvent = NULL;
    vvp.vvp_flEvent = POSTEVENT_DELETE;
    VDHRequestVDD(hvddVideo,
                  hvdm,
                  VVDDEVREQ_POSTEVENT,
                  SSToDS(&vvp),
                  NULL);
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = VXGAInt4BHandler()                                        
 *
 * DESCRIPTION   = INT 4BH HANDLER.  This is called by VDMA when
 *                 the DOS app issues Int4b
 *                                    function=81
 *                                    sub-function=3
 *                 which means the DOS app has requested physical
 *                 memory for its I/O so XGA will unlock the 640K
 *                 DOS region along with any mapped-in LIM memory,
 *                 and unlock the DOS 640K page table.
 *
 * INPUT         = HVDM  == VDM HANDLE
 *                 ulfun == subfunction
 *                 PCRF  -> VDM REGISTER FRAME
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

LONG EXPENTRY VXGAInt4BHandler(HVDM hvdm,ULONG ulFunc,PVOID pIn,PVOID pOut)
{
  USHORT i;                                                      /*          */

  if (ulFunc == 3)                       /* lock memory request  */
  {
     VDMData.flVDMXGA |= VDM_INT4B;      /* indicate int4B recvd */

     /*
     ** unlock VDM memory
     */
     if (VDMData.flVDMXGA & VDM_LOCKED)
       vXGALockVDM(VDMData.hvdmXGA, FALSE);

     /*
     ** now put ALL XGA into real mode    US=1
     */
     for (i = nConfigStart; i <= nConfigEnd; i++)                /*          */
     {                                                           /*          */
       if (XGAENV[i].IORegBase)                                  /*          */
         OUTB(XGAENV[i].IORegBase+AXGA_VIRTUAL_MEMORY_CONTROLLER,0x04);
     }                                                           /*          */
     return(1);                          /* set good rc          */
  }                                      /* end lock memory req  */
}

#pragma  END_SWAP_CODE






