/*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.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   File            = SEAMLESS.C                                     */
/*                                                                    */
/*   Description     = Seamless         XGA functions                 */
/*                                                                    */
/*   Function        = InitialiseSeamless                             */
/*                     SeamlessInitSem                                */
/*                     SeamlessVDMCreated                             */
/*                     SeamlessVDMDestroyed                           */
/*                     SeamlessSendDirty                              */
/*                     SeamlessDeath                                  */
/*                     SeamlessResurection                            */
/*                     SeamlessHeartBeat                              */
/*                                                                    */
/*                                                                    */
/* CHANGE ACTIVITY =                                                  */
/*   DATE      FLAG        APAR   CHANGE DESCRIPTION                  */
/*   --------  ----------  -----  ------------------------------------*/
/*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx                             */
/*   04/04/93              63295  Invalidate seamless cache after     */
/*                                last seamless app. exits.           */
/*   02/09/94  77206       77206  Set pointer to cursor status.       */
/**********************************************************************/


#define INCL_DOSMVDM
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_VMOUSE
#ifdef DCAF                                                               //DCAF
#define INCL_GRE_SCREEN                                                   //DCAF
#endif                                                                    //DCAF
#include <eddbcone.h>
#include <eddinclt.h>
#include <edddtypt.h>
#include <eddmextf.h>
#include <cursor.h>
#include <seamless.h>
#ifdef VRAMPTR
#include <eddncach.h>
#endif /* VRAMPTR */

#ifdef DCAF                                                               //DCAF
#include <dcaf.h>                                                         //DCAF
#endif                                                                    //DCAF

#ifdef _8514
#include <8514.h>
#include <cacheman.h>
extern PHWMAP           pHWMap;
extern PCACHEMAP        pCacheMap;
extern VOID             CacheManager(BOOL);
extern VOID             eddt_InvalidateCache (VOID);
extern BitmapHeader     NewPatternTable[];
extern ULONG            ColorPatPhysical;
#endif

#ifdef SEAMLESS

extern DDTType      DDT;
extern ULONG        ulDirectDeviceDefaultPaletteSize;
extern BOOL         fXgaDead;
extern ULONG        pSysCacheStartPhy;
extern ULONG        pVRAMCacheStart;
extern ULONG        pCurCacheBasePhy;
extern CURSORDATA   cursor_data;
extern RGB2         HWPalette[];
extern ULONG        pPhunkPhys;
extern PVOID        pPhunkVirt;

#ifdef DCAF                                                               //DCAF
/**********************************************************************/  //DCAF
/* Declare the Seamless SCA.                                          */  //DCAF
/*                                                                    */  //DCAF
/* All Seamless bounding rectangles will be accumulated into this     */  //DCAF
/* SCA, and then merged with the contents of the normal SCAs when     */  //DCAF
/* one is queried (using GetScreenChangeArea).                        */  //DCAF
/*                                                                    */  //DCAF
/* We use a separate SCA for Seamless because we need to grant        */  //DCAF
/* addressability to it during initialisation. The normal SCAs are    */  //DCAF
/* allocated memory in the Global Heap, and therefore cannot be       */  //DCAF
/* given addressibility at init time (unless we gave addressability   */  //DCAF
/* to the whole heap - which would be very undesirable!).             */  //DCAF
/**********************************************************************/  //DCAF
SCA     scaSeamless;                                                      //DCAF

#ifdef  S3
extern SCA          pscaStart;
#endif

#endif                                                                    //DCAF

/**********************************************************************/
/* These two dummy C functions allow us to calculate the address and  */
/* length of the cursor C code that requires addressability for the   */
/*         VDMs.                                                      */
/**********************************************************************/
extern  VOID    StartOfCursorCCode(VOID);
extern  VOID    EndOfCursorCCode(VOID);

#ifdef DCAF                                                               //DCAF
/**********************************************************************/  //DCAF
/* These two functions allow us to calculate the address and length   */  //DCAF
/* of the DCAF bounds accumulation code.                              */  //DCAF
/**********************************************************************/  //DCAF
extern  VOID    AccumulateScreenBounds(PRECTL   prclArgBound);            //DCAF
extern  VOID    EndOfAccumulateScreenBounds(VOID);                        //DCAF
#endif                                                                    //DCAF

/**********************************************************************/
/* These two public assembler labels allow us to calculate the        */
/* address and length of the cursor C code that requires              */
/* addressability for the         VDMs.                               */
/**********************************************************************/
extern  VOID    start_of_cursor_code(VOID);
extern  VOID    end_of_cursor_code(VOID);
extern  VOID    start_of_seamless_thunks(VOID);
extern  VOID    end_of_seamless_thunks(VOID);

/**********************************************************************/
/* These three functions are the 16:16 thunk entry points for the     */
/* cursor exclusion code.                                             */
/**********************************************************************/
extern  VOID    SeamlessExcludeCursor(VOID);
extern  VOID    SeamlessDisableCursor(VOID);
extern  VOID    SeamlessEnableCursor(VOID);
extern  VOID    DoFlatToSel(PVOID);


BYTE         SeamlessStack[SEAMLESS_STACK_SIZE];

SEAMLESSDATA SeamlessData;
PVOID        pSeamlessData = &SeamlessData;
SM_PMDISP    SeamlessAddresses[20];
ULONG        fSeamlessEnabled;
ULONG        fSeamlessActive;
ULONG        fSeamlessCCConflict;
ULONG        ulSeamlessVDMCount;
ULONG        ulHeartBeat;
USHORT       usHeartBeatPID = 0;
USHORT       usHeartBeatTID = 0;
FSRSEM       FSRDriverSem;
VMSSIZE      vmsSize;

#ifdef _8514
    PVOID         *pWindowsSharedData;
    SEAMLESSDATA  *pSeamlessData16 = &SeamlessData;
#endif


/**********************************************************************/
/* InitialiseSeamless lets the VWIN know that we support seamless and */
/* sets up all the global data that the         driver needs access   */
/* to.                                                                */
/**********************************************************************/
VOID InitialiseSeamless(VOID)
{
    HVDD  hSeamlessVDD;
    ULONG returnCode;
    ULONG i;

#ifndef _8514  /* XGA */

    /******************************************************************/
    /* Set our flag indicating that there are currently no seamless   */
    /*         VDMs running.                                          */
    /******************************************************************/
    fSeamlessActive = FALSE;

    /******************************************************************/
    /* Open the Seamless VDD ("VWIN").                                */
    /******************************************************************/
    returnCode = DosOpenVDD("VWIN", &hSeamlessVDD);

    if (returnCode != 0)
    {
        /**************************************************************/
        /* The DosOpenVDD call encountered an error of some sort.  We */
        /* will not support seamless         in this case so there is */
        /* no need to do any initialisation.  (We assume that the     */
        /* error was because seamless         is not enabled).        */
        /**************************************************************/
        fSeamlessEnabled = FALSE;
        return;
    }

    /******************************************************************/
    /* The DosOpenVDD for VWIN was successful so we know that the     */
    /* seamless         feature is enabled.                           */
    /******************************************************************/
    fSeamlessEnabled = TRUE;

    /******************************************************************/
    /* Set up the pass through data for the VWIN initilise call.      */
    /******************************************************************/
    SeamlessData.LevelID[0] = 'X';
    SeamlessData.LevelID[1] = 'G';
    SeamlessData.LevelID[2] = '0';
    SeamlessData.LevelID[3] = '1';

    SeamlessData.usIORegBase      = aiXGAAdapter.usIORegBase;
    SeamlessData.pMemRegBase      = aiXGAAdapter.pMemRegBase;
    SeamlessData.ulVramBase       = aiXGAAdapter.ulVRAMBase;
    SeamlessData.ulVramSize       = aiXGAAdapter.lMemorySize;
    SeamlessData.fUseExternalPolling = (BYTE)
                     ((aiXGAAdapter.usFlags & XGA_EXTERNAL_POLLING)!=0);

    SeamlessData.usScreenWidthMM  = ai2XGAAdapter.usScreenWidth;
    SeamlessData.usScreenHeightMM = ai2XGAAdapter.usScreenHeight;

    SeamlessData.usScreenWidthPels  = DDT.ScreenWidth;
    SeamlessData.usScreenHeightPels = DDT.ScreenHeight;
    SeamlessData.bBitsPerPel = (BYTE) DDT.BitCount;

    SeamlessData.pSemaphore = &FSRDriverSem;
    SeamlessData.pHeartBeat = &ulHeartBeat;

    SeamlessData.pNumDefaultColors = &ulDirectDeviceDefaultPaletteSize;

    // 77206  re-introduce code for seamless cursor status. (REGR:75458)
    SeamlessData.pCursorStatus  = (PBYTE)&cursor_data.cursor_status; //77206

    SeamlessData.pExcludeCursor = (ULONG)SeamlessExcludeCursor;
    SeamlessData.pDisableCursor = (ULONG)SeamlessDisableCursor;
    SeamlessData.pEnableCursor  = (ULONG)SeamlessEnableCursor;
    DoFlatToSel(&SeamlessData.pExcludeCursor);
    DoFlatToSel(&SeamlessData.pDisableCursor);
    DoFlatToSel(&SeamlessData.pEnableCursor);


    /******************************************************************/
    /* Set up the fields related to seamless palette management.      */
    /******************************************************************/
    if (DDT.BitCount == 8)
    {
        SeamlessData.fPaletteIsFixed = FALSE;
    }
    else
    {
        SeamlessData.fPaletteIsFixed = TRUE;
    }

    SeamlessData.ulLastPalUpdate = 0;
    SeamlessData.pHWPalette = &HWPalette[0];
    DoFlatToSel(&SeamlessData.pHWPalette);

    /******************************************************************/
    /* Set up the fields related to the Phunk.  JC                    */
    /******************************************************************/
    SeamlessData.pPhysSharedBuff = (pPhunkPhys - END_BYTES_PHUNK_OFFSET);
    SeamlessData.pVirtSharedBuff = ((PBYTE)pPhunkVirt - END_BYTES_PHUNK_OFFSET);

#else  /* 8514 stuff */

    /******************************************************************/
    /* Set our flag indicating that there are currently no seamless   */
    /*         VDMs running.                                          */
    /******************************************************************/
    fSeamlessActive = FALSE;

    /******************************************************************/
    /* Open the Seamless VDD ("VWIN").                                */
    /******************************************************************/
    returnCode = DosOpenVDD("VWIN", &hSeamlessVDD);

    if (returnCode != 0)
    {
        /**************************************************************/
        /* The DosOpenVDD call encountered an error of some sort.  We */
        /* will not support seamless         in this case so there is */
        /* no need to do any initialisation.  (We assume that the     */
        /* error was because seamless         is not enabled).        */
        /**************************************************************/
        fSeamlessEnabled = FALSE;
        return;
    }

    /******************************************************************/
    /* The DosOpenVDD for VWIN was successful so we know that the     */
    /* seamless         feature is enabled.                           */
    /******************************************************************/
    fSeamlessEnabled = TRUE;

    /******************************************************************/
    /* Set up the pass through data for the VWIN initilise call.      */
    /******************************************************************/
#ifdef S3

    SeamlessData.LevelID[0] = 'S';
    SeamlessData.LevelID[1] = '3';

    // SeamlessData.LevelID[2] = '0';
    // SeamlessData.LevelID[3] = '1';

    switch((ULONG)((DDT.ScreenWidth << 16) + DDT.ScreenHeight))
    {
    case 0x02800190:
       SeamlessData.LevelID[2] = 'A';      // 640 x 400
       break;
    case 0x028001E0:
       SeamlessData.LevelID[2] = 'B';      // 640 x 480
       break;
    case 0x03200258:
       SeamlessData.LevelID[2] = 'C';      // 800 x 600
       break;
    case 0x04000300:
       SeamlessData.LevelID[2] = 'D';      // 1024 x 768
       break;
    case 0x050003C0:
       SeamlessData.LevelID[2] = 'E';      // 1280 x 960
       break;
    case 0x05000400:
       SeamlessData.LevelID[2] = 'F';      // 1280 x 1024
       break;
    case 0x05500400:
       SeamlessData.LevelID[2] = 'G';      // 1360 x 1024
       break;
    case 0x064004B0:
       SeamlessData.LevelID[2] = 'H';      // 1600 x 1200
       break;
    default:
       SeamlessData.LevelID[2] = 'Z';      // TBD
       break;
    }

    switch (DDT.BitCount)
    {
    case 1:
       SeamlessData.LevelID[3] = '0';       // 1 bpp
       break;
    case 4:
       SeamlessData.LevelID[3] = '2';       // 4 bpp
       break;
    case 8:
       SeamlessData.LevelID[3] = '3';       // 8 bpp
       break;
    case 16:
       SeamlessData.LevelID[3] = '5';       // 16 bpp
       break;
    case 24:
       SeamlessData.LevelID[3] = '6';       // 16 bpp
       break;
    default:
       SeamlessData.LevelID[3] = '9';       // TBD
       break;
    }

    SeamlessData.ulScreenWidthPels  = (ULONG) DDT.ScreenWidth;
    SeamlessData.ulScreenHeightPels = (ULONG) DDT.ScreenHeight;
    SeamlessData.ulBitsPerPel       = (ULONG) DDT.BitCount;
#else
    SeamlessData.LevelID[0] = '8';
    SeamlessData.LevelID[1] = '5';
    SeamlessData.LevelID[2] = '0';
    SeamlessData.LevelID[3] = '1';
#endif

#ifdef S3
    SeamlessData.pCursorStatus  = (PVOID)&(cursor_data.cursor_status);
    DoFlatToSel(&SeamlessData.pCursorStatus);
    SeamlessData.pDCAFActive    = (PVOID)&(pscaStart);
    DoFlatToSel(&SeamlessData.pDCAFActive);

    if (DDT.fScreenFlags & USE_8BIT_DAC)
        SeamlessData.ulDACRange = 255;
    else
        SeamlessData.ulDACRange = 63;
#endif

    SeamlessData.pExcludeCursor = (ULONG)SeamlessExcludeCursor;
    SeamlessData.pDisableCursor = (ULONG)SeamlessDisableCursor;
    SeamlessData.pEnableCursor  = (ULONG)SeamlessEnableCursor;
    DoFlatToSel(&SeamlessData.pExcludeCursor);
    DoFlatToSel(&SeamlessData.pDisableCursor);
    DoFlatToSel(&SeamlessData.pEnableCursor);

    SeamlessData.pSemaphore = (PVOID) &FSRDriverSem;
    SeamlessData.pHeartBeat = (PVOID) &ulHeartBeat;
    DoFlatToSel(&SeamlessData.pSemaphore);
    DoFlatToSel(&SeamlessData.pHeartBeat);

    SeamlessData.pWindowsPrivateArea = (PVOID) pWindowsSharedData;
    DoFlatToSel(&SeamlessData.pWindowsPrivateArea);

    SeamlessData.FirstVDM = TRUE;

    /******************************************************************/
    /* Set up the fields related to seamless palette management.      */
    /******************************************************************/
    if (DDT.BitCount == 8)
    {
        SeamlessData.fPaletteIsFixed = FALSE;
    }
    else
    {
        SeamlessData.fPaletteIsFixed = TRUE;
    }

    SeamlessData.ulLastPalUpdate = 0;
    SeamlessData.pHWPalette = &HWPalette[0];
    DoFlatToSel(&SeamlessData.pHWPalette);

    DoFlatToSel(&pSeamlessData16);


#endif /* 8514 stuff */

    /******************************************************************/
    /* Set up the data structure that defines what addresses we are   */
    /* passing to the         driver.  VWIN will make sure that the   */
    /*         driver has addressability to all of the data.          */
    /******************************************************************/

    /******************************************************************/
    /* Initialise a count of how many addresses we have set up.       */
    /******************************************************************/
    i = 0;

    /******************************************************************/
    /* The FSR driver exclusion semaphore.                            */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(FSRSEM);
    SeamlessAddresses[i++].pointer = &FSRDriverSem;

    /******************************************************************/
    /* The heart beat count used to stop         VDM hanging system.  */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(ULONG);
    SeamlessAddresses[i++].pointer = &ulHeartBeat;

#ifdef _8514
    /******************************************************************/
    /* The tiled data segment that will be used by all VDMs.          */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(ULONG);
    SeamlessAddresses[i++].pointer = pWindowsSharedData;
#endif

#ifndef _8514
    /******************************************************************/
    /* The current number of defaults in the HW palette.              */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(ULONG);
    SeamlessAddresses[i++].pointer = &ulDirectDeviceDefaultPaletteSize;
#endif

    /******************************************************************/
    /* The HWPalette structure.                                       */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = 1024;
    SeamlessAddresses[i++].pointer = &HWPalette[0];

#ifndef _8514
    /******************************************************************/
    /* The Phunk buffer.  JC                                          */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = EXTENDED_PHUNK_SIZE;
    SeamlessAddresses[i++].pointer = SeamlessData.pVirtSharedBuff;
#endif

    /******************************************************************/
    /* The cursor exclusion code.                                     */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING2 | SM_CODE_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = (ULONG)EndOfCursorCCode
                                           - (ULONG)StartOfCursorCCode;
    SeamlessAddresses[i++].pointer = (PVOID)StartOfCursorCCode;


    SeamlessAddresses[i].flOptions = SM_RING2 | SM_CODE_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = (ULONG)end_of_cursor_code
                                          - (ULONG)start_of_cursor_code;
    SeamlessAddresses[i++].pointer = (PVOID)start_of_cursor_code;

    /******************************************************************/
    /* Thunks for function entry points for         VDMs.             */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING2 | SM_CODE_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = (ULONG)end_of_seamless_thunks
                                          - (ULONG)start_of_seamless_thunks;
    SeamlessAddresses[i++].pointer = (PVOID)start_of_seamless_thunks;

    /******************************************************************/
    /* The cursor exclusion data.                                     */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(CURSORDATA);
    SeamlessAddresses[i++].pointer = &cursor_data;

    /******************************************************************/
    /* Stack used by VDM when it thunks to PM cursor routines.        */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = SEAMLESS_STACK_SIZE;
    SeamlessAddresses[i++].pointer = &SeamlessStack;

    /******************************************************************/
    /* Seamless Data structure.                                       */
    /******************************************************************/
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(SEAMLESSDATA);
    SeamlessAddresses[i++].pointer = &SeamlessData;

#ifdef DCAF                                                               //DCAF
    /******************************************************************/  //DCAF
    /* The DCAF bounds accumulation routine.                          */  //DCAF
    /******************************************************************/  //DCAF
    SeamlessAddresses[i].flOptions = SM_RING2 | SM_CODE_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength = (ULONG)EndOfAccumulateScreenBounds -  //DCAF
                                            (ULONG)AccumulateScreenBounds;//DCAF
    SeamlessAddresses[i++].pointer = (PVOID)AccumulateScreenBounds;       //DCAF
                                                                          //DCAF
    /******************************************************************/  //DCAF
    /* The DCAF Seamless data.                                        */  //DCAF
    /******************************************************************/  //DCAF
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength = sizeof(SCA);                          //DCAF
    SeamlessAddresses[i++].pointer =  &scaSeamless;                       //DCAF
                                                                          //DCAF
    /******************************************************************/  //DCAF
    /* The DDT (we need to access the screen width and screen         */  //DCAF
    /* height at Seamless Time.                                       */  //DCAF
    /******************************************************************/  //DCAF
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_DATA_ADDRESS | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength = sizeof(DDTType);                      //DCAF
    SeamlessAddresses[i++].pointer =  &DDT;                               //DCAF
#endif                                                                    //DCAF

    /******************************************************************/
    /* The "pass through" data.                                       */
    /******************************************************************/
#ifdef _8514
    SeamlessAddresses[i].flOptions = SM_PASSTHRU | SM_ADDRESS_16BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(SEAMLESSDATA);
    SeamlessAddresses[i++].pointer = (PVOID) pSeamlessData16;
#else
    SeamlessAddresses[i].flOptions = SM_RING3 | SM_PASSTHRU | SM_ADDRESS_32BIT | SM_MATCH_LINEAR;
    SeamlessAddresses[i].ulLength  = sizeof(SEAMLESSDATA);
    SeamlessAddresses[i++].pointer = pSeamlessData;
#endif

    /******************************************************************/
    /* Pass the initialisation data to VWIN to give         access to */
    /* the global data we wish to share.                              */
    /******************************************************************/
    returnCode = DosRequestVDD(hSeamlessVDD, NULL, VWIN_INIT,
                               i, &SeamlessAddresses,
                               0, NULL);
    if (returnCode != 0)
    {
        /**************************************************************/
        /* The DosRequestVDD call encountered an error of some sort.  */
        /* We will not support seamless         in this case so there */
        /* is no need to do any more initialisation.                  */
        /**************************************************************/
        fSeamlessEnabled = FALSE;
        DosCloseVDD(hSeamlessVDD);
        return;
    }

    /******************************************************************/
    /* We must also pass the screen size information for the virtual  */
    /* mouse code to use.                                             */
    /******************************************************************/
    vmsSize.vmss_nb             =  sizeof(VMSSIZE);
    vmsSize.vmss_lMode          = 18;
    vmsSize.vmss_ulWidth        = DDT.ScreenWidth;
    vmsSize.vmss_ulHeight       = DDT.ScreenHeight;
    vmsSize.vmss_ulCellWidth    = 1;
    vmsSize.vmss_ulCellHeight   = 1;
//    vmsSize.vmss_ulPtrWidth   = DDT.CursorWidth;
//    vmsSize.vmss_ulPtrHeight  = DDT.CursorHeight;
    vmsSize.vmss_ulPtrWidth     = 40;
    vmsSize.vmss_ulPtrHeight    = 20;
    vmsSize.vmss_ulPtrUnitWidth = 8;

    returnCode = DosRequestVDD(hSeamlessVDD, NULL, VWIN_SETSIZE,
                               sizeof(VMSSIZE), &vmsSize,
                               0, NULL);
    if (returnCode != 0)
    {
        /**************************************************************/
        /* The DosRequestVDD call encountered an error of some sort.  */
        /* We will not support seamless         in this case.         */
        /**************************************************************/
        fSeamlessEnabled = FALSE;
    }

    /******************************************************************/
    /* Close the VDD.                                                 */
    /******************************************************************/
    DosCloseVDD(hSeamlessVDD);


    /******************************************************************/
    /* Lastly we must decide whether there will be a conflict between */
    /* our VRAM character cache and the         driver VRAM usage. If */
    /* we have a 1M card then the         driver can spare us the 64k */
    /* we need.                                                       */
    /******************************************************************/
#ifndef   _8514
    if ( (aiXGAAdapter.lMemorySize -
         (ULONG)(((ULONG)DDT.BitCount *
                 (ULONG)DDT.ScreenWidth * (ULONG)DDT.ScreenHeight) / 8)) <
                 (86 * 1024 + 64 * 1024) )
    {
             fSeamlessCCConflict = TRUE;
    }
    else
    {
             fSeamlessCCConflict = FALSE;
    }
#else
        //@DMS We have been gauranteed a 1meg card !!!
             fSeamlessCCConflict = FALSE;
#endif

}

ULONG SeamlessInitSem(VOID)
{
    FSRDriverSem.Length = sizeof(FSRSEM);
    FSRDriverSem.ProcID = 0;
    FSRDriverSem.ThrdID = 0;
    FSRDriverSem.Usage  = 0;
    FSRDriverSem.Client = 0;
    FSRDriverSem.Timeout= 10000;  /* 10 seconds time out */
    FSRDriverSem.RAMsem = 0;
    return(NO_ERROR);
}

VOID SeamlessForceSemRelease(VOID)
{
    PTIB pThreadInfo;
    PPIB pProcessInfo;

#ifdef FIREWALLS
    /******************************************************************/
    /* It does not make sense to be called if the semaphore is not    */
    /* currently owned.                                               */
    /******************************************************************/
    if (FSRDriverSem.Usage == 0)
    {
        haltproc();
    }
#endif

    /******************************************************************/
    /* Set the semphore owner to be us.  (HACKER!!!)  The changing    */
    /* of the semaphore owner must be atomic to avoid letting in any  */
    /* other threads.                                                 */
    /******************************************************************/
    DosGetInfoBlocks(&pThreadInfo,
                     &pProcessInfo);
//  FSRDriverSem.ProcID = (USHORT) pProcessInfo->pib_ulpid;
//  FSRDriverSem.ThrdID = (USHORT) pThreadInfo->tib_ptib2->tib2_ultid;

    *((PULONG)&FSRDriverSem.ProcID) =
                        ((pThreadInfo->tib_ptib2->tib2_ultid) << 16)
                      | (pProcessInfo->pib_ulpid);

    /******************************************************************/
    /* Free the semaphore.                                            */
    /******************************************************************/
    while (FSRDriverSem.Usage != 0)
    {
        ReleaseDriverSemaphore();
    }
}


/**********************************************************************/
/* This function should be called when a seamless         VDM is      */
/* created.                                                           */
/**********************************************************************/
VOID SeamlessVDMCreated(VOID)
{
    ulSeamlessVDMCount++;

    /******************************************************************/
    /* If this is the first seamless         VDM to be created.  We   */
    /* must stop doing things now that are not compatible with the    */
    /*         device driver.                                         */
    /******************************************************************/
    if (ulSeamlessVDMCount == 1)
    {
        fSeamlessActive = TRUE;

        /**************************************************************/
        /* We can not use the VRAM character cache any more so we     */
        /* must use our copy in system memory.                        */
        /**************************************************************/
        pCurCacheBasePhy = pSysCacheStartPhy;

#ifdef VRAMPTR
        /**************************************************************/
        /* Invalidate the VRAM bitmap cache. No new bitmaps will be   */
        /* added while fSeamlessActive is TRUE.                       */
        /**************************************************************/
        shutdown_bm_cache();
#endif /* VRAMPTR */

#ifdef _8514
        /**************************************************************/
        /* Invalidate the VRAM font cache.  The location of the font  */
        /* cache will be moved and limited slightly in capacity.      */
        /*                                                            */
        /* Also, the bitmap cache will be limited to allow for a full */
        /* 128 scan lines to be used by the seamless         driver.  */
        /**************************************************************/
        CacheManager ( TURN_SEAMLESS_ON );
        eddt_InvalidateCache();

        /**************************************************************/
        /* Also, the bitmap cache will be limited to allow for a full */
        /* 128 scan lines to be used by the seamless         driver.  */
        /**************************************************************/
        #ifdef _8514
        max_cached_bitmaps = pCacheMap->max_bitmaps;

        (ULONG)NewPatternTable[PATSYM_DITHERED].BMPhys = pCacheMap->color_dither;
        (ULONG)NewPatternTable[PATSYM_MONODITH].BMPhys = pCacheMap->mono_dither;
        ColorPatPhysical = pCacheMap->color_dither;

        #endif
        next_eviction = max_cached_bitmaps == 0 ? 0 : max_cached_bitmaps - 1;

#endif
    }
}


/**********************************************************************/
/* This function should be called when a seamless         VDM is      */
/* destroyed.                                                         */
/**********************************************************************/
VOID SeamlessVDMDestroyed(VOID)
{
#ifdef FIREWALLS
    /******************************************************************/
    /* If we currently think we have no VDMs then something has gone  */
    /* badly wrong!                                                   */
    /******************************************************************/
    if (ulSeamlessVDMCount == 0)
    {
        haltproc();
    }
#endif /* FIREWALLS */

    ulSeamlessVDMCount--;
    if (ulSeamlessVDMCount == 0)
    {
        /**************************************************************/
        /* There are now no seamless         device drivers running.  */
        /**************************************************************/
        fSeamlessActive = FALSE;

#ifndef _8514
        /**************************************************************/
        /* Start using the VRAM character cache again.                */
        /**************************************************************/
        if (!fXgaDead)
        {
            CopyCCToVRAM();
            pCurCacheBasePhy = pVRAMCacheStart;
        }
#else /* NDEF _8514 */

        /**************************************************************/
        /* Invalidate the VRAM font cache.  The location of the font  */
        /* cache will be restored to its full capacity using the      */
        /* bottom half of off-screen vram.                            */
        /**************************************************************/
        CacheManager( TURN_SEAMLESS_OFF );
        eddt_InvalidateCache();

        /**************************************************************/
        /* Flush the bitmap cache and restore it to its full capacity.*/
        /**************************************************************/
        shutdown_bm_cache();
        #ifdef _8514
        max_cached_bitmaps = pCacheMap->max_bitmaps;

        (ULONG)NewPatternTable[PATSYM_DITHERED].BMPhys = pCacheMap->color_dither;
        (ULONG)NewPatternTable[PATSYM_MONODITH].BMPhys = pCacheMap->mono_dither;
        ColorPatPhysical = pCacheMap->color_dither;

        #endif
        next_eviction = max_cached_bitmaps == 0 ? 0 : max_cached_bitmaps - 1;

        memset(pWindowsSharedData, 0, WINDOWS_PRIVATE_AREA_SIZE); /*            */
#endif

    }

}


/**********************************************************************/
/* Send VWIN the VDM "dirty" notification. This is used at death and  */
/* resurection to indicate to the VDMs to suspend drawing or resume   */
/* redrawing and repaint.                                             */
/**********************************************************************/
VOID SeamlessSendDirty(ULONG SuspendOrResume)
{
    HVDD  hSeamlessVDD;
    ULONG ulReturnCode;

    if (fSeamlessEnabled)
    {
        /**************************************************************/
        /* Open the Seamless VDD ("VWIN").                            */
        /**************************************************************/
        ulReturnCode = DosOpenVDD("VWIN", &hSeamlessVDD);

        if (ulReturnCode != 0)
        {
            /**********************************************************/
            /* The DosOpenVDD call encountered an error of some sort! */
            /**********************************************************/
            LogDosError(ulReturnCode);
            return;
        }

        /**************************************************************/
        /* Send VWIN the VDM "dirty" notification.                    */
        /**************************************************************/
        DosRequestVDD(hSeamlessVDD,
                      -1,               // Broadcast to all VDMs
                      VWIN_VDMDIRTY,
                      SuspendOrResume,  // Suspend or Resume drawing
                      NULL,
                      1,                // Force repaint if resuming
                      NULL);

        /**************************************************************/
        /* Close the handle to VWIN.                                  */
        /**************************************************************/
        DosCloseVDD(hSeamlessVDD);
    }
}

VOID SeamlessDeath(VOID)
{
    SeamlessSendDirty(VDMDIRTY_SUSPEND_DRAW);
}

VOID SeamlessResurection(VOID)
{
    SeamlessSendDirty(VDMDIRTY_RESUME_DRAW);
}


/**********************************************************************/
/* This function carries out "Heat Beat Processing" as defined by DCR */
/* 1545 (CP20).  It detects when the         driver has died while    */
/* holding the semaphore and tidies up if need be.                    */
/**********************************************************************/
VOID SeamlessHeartbeat(VOID)
{
    HVDD  hSeamlessVDD;
    ULONG ulReturnCode;

    /******************************************************************/
    /* If seamless         is not enabled then we do nothing.         */
    /******************************************************************/
    if (fSeamlessEnabled)
    {
        /**************************************************************/
        /* See if we are timing out for the second time with the same */
        /* PID, TID, and heartbeat.                                   */
        /**************************************************************/
        if (   (usHeartBeatPID == FSRDriverSem.ProcID)
            && (usHeartBeatTID == FSRDriverSem.ThrdID)
            && (ulHeartBeat == 0))
        {
            /**********************************************************/
            /* This is the second time we have timed out with the     */
            /* same PID and TID owning the semaphore and the heart    */
            /* beat has not changed.  We must call VWIN to see if a   */
            /* clean up is required.                                  */
            /**********************************************************/
            /**********************************************************/
            /* Open the Seamless VDD ("VWIN").                        */
            /**********************************************************/
            ulReturnCode = DosOpenVDD("VWIN", &hSeamlessVDD);

            if (ulReturnCode != 0)
            {
                /******************************************************/
                /* The DosOpenVDD call encountered an error of some   */
                /* sort!                                              */
                /******************************************************/
                LogDosError(ulReturnCode);
                return;
            }

            /**********************************************************/
            /* Send VWIN the timeout on semaphore signal.             */
            /**********************************************************/
            ulReturnCode = DosRequestVDD(hSeamlessVDD,
                                NULL,
                                VWIN_HEARTBEAT,
                                FSRDriverSem.ProcID,
                                NULL,
                                FSRDriverSem.ThrdID,
                                NULL);

            if ((ulReturnCode == 0) || (ulReturnCode == 1))
            {
                /******************************************************/
                /* The return code indicates that we should cleanup.  */
                /* (0 -> VDM was destroyed by VWIN)                   */
                /* (1 -> process no longer exists )                   */
                /******************************************************/
                SeamlessForceSemRelease();


                /******************************************************/
                /* Cleanup other heart beat stuff.                    */
                /******************************************************/
                usHeartBeatPID = 0;
                usHeartBeatTID = 0;
                ulHeartBeat = 0;
            }

            /**********************************************************/
            /* Close the handle to VWIN.                              */
            /**********************************************************/
            DosCloseVDD(hSeamlessVDD);
        }
        else
        {
            /**********************************************************/
            /* Just record the PID and TID of the semaphore owner and */
            /* reset the heart beat counter.                          */
            /**********************************************************/
            usHeartBeatPID = FSRDriverSem.ProcID;
            usHeartBeatTID = FSRDriverSem.ThrdID;
            ulHeartBeat = 0;
        }
    }
}


#endif /* SEAMLESS */
