/*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 = VVPHYS.C
 *
 * DESCRIPTIVE NAME = Virtual Video Physical Page Management
 *
 *
 * VERSION = V2.0
 *
 * DATE      10/18/89
 *
 * DESCRIPTION  This module contains the VVD's routines to manage physical
 *              video pages on behalf of background/windowed VDMs and the PM
 *              display driver.
 *
 * FUNCTIONS    vvUpdatePhysPageMap()  Update the physical page usage table
 *              vvGetPhysPage()        Allocate (or steal) physical page for VDM
 *              vvFreePhysPage()       Free physical page for VDM
 *              vvFreeAllPhysPages()   Free all physical pages (for a dying VDM)
 *              vvGetPhysBytes()       Allocate physical video memory for PM
 *              vvFreePhysBytes()      Free physical video memory for PM
 *              VVUnmapPhysContext()   Unmap a physical page in current VDM
 *              VVUpdateContext()      Update VDM page mappings in context
 *              VVUpdatePhysContext()  Set up I/O state for current VDM
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#include <mvdm.h>
#include <vvd.h>
#include "vvdp.h"
#ifdef  GALE                                                            //J-TS00V
#include "vvgale.h"                                                     //J-TS00V
#endif  //GALE                                                          //J-TS00V

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif
extern ULONG flVVD;
#pragma  BEGIN_SWAP_DATA
extern ULONG nPMWindowedVDMs;
extern HHOOK hhookEventTimer;
extern RLE arleMemory[];
extern LSENTRY lseHeadActive;
extern ULONG ahPhysPage[MAX_PAGESPERPLANE];
extern ULONG aiPhysToVirt[MAX_PAGESPERPLANE];
extern ULONG atimePhysPageAlloc[MAX_PAGESPERPLANE];
extern HMXSEM hmxPhysPageEvent;
extern HMXSEM hmxWindowedEvent;
extern PBYTE pbSEQExtShadowIndx;
extern PRLE prleSEQExtShadowData[MAX_SEQREGS];
extern PBYTE pbGDCExtShadowIndx;
extern PRLE prleGDCExtShadowData[MAX_GDCREGS];

#ifdef   SVGA
extern ULONG ulSVGAAdapterType;
extern PFNSVGAGETBANK apfnSVGAGetBank[];

 /*
 **  Warning Note: SVGAGetBank() can return either the read or
 **  the write bank that is currently active. They may well
 **  not be the same. Most of the time in this module we guess.
 */

#endif
#pragma  END_SWAP_DATA

#ifdef   EGAVGA
   #pragma  BEGIN_GLOBAL_DATA
extern VVDRQ vvdrqVideo;
   #pragma  END_GLOBAL_DATA
#endif
#pragma  BEGIN_SWAP_CODE

/***************************************************************************
 *
 * FUNCTION NAME = vvUpdatePhysPageMap()
 *
 * DESCRIPTION   = Update the physical page usage table
 *
 * INPUT         = pdrq -> display requirements (NULL if none)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvUpdatePhysPageMap(PVVDRQ pdrq)
{
  PORT port;
  ULONG offPage = 0;
  register INT i;
  register PRLE prle;
  PVVREG pvvreg;
  BOOL fAvail = FALSE;
  register PVDMDATA pvd;
  PLSENTRY plse;
#ifdef  GALE                                                            //J-TS00V
  FLAGS flDirty = TRUE;                                                 //J-TS00V
#endif  //GALE                                                          //J-TS00V

  RequestMutexSem(hmxPhysPageEvent);
  flVVD |= VVD_NOPHYSPAGES;

  /*
  ** Make a copy of the new display requirements
  */

  if (pdrq)
    vvdrqVideo = *pdrq;

  /*
  ** Adjust the physical page map as needed
  */

  for (i = 0; i < MAX_PAGESPERPLANE; i++,
       offPage += PAGESIZE)
  {

    if (offPage < vvdrqVideo.vvd_nbReserved)
    {

      if (VDMOWNSPHYSPAGE(i))
      {
        pvd = pVDMData((HVDM)(ahPhysPage[i]));

        /*
        ** Claim semaphores in proper order to avoid deadlock
        */

        ReleaseMutexSem(hmxPhysPageEvent);
        RequestMutexSem(pvd->hmxVideoState);

        /*
        ** Then make sure VDM still owns page
        */

        if (THISVDMOWNSPHYSPAGE(pvd->hvdmVideo,
                                i))
        {
          VDHFreezeVDM(pvd->hvdmVideo);

#ifdef   SVGA
          vvUnvalidatePage(pvd->hvdmVideo,
                           NULL,
                           aiPhysToVirt[i],
                           (*apfnSVGAGetBank[ulSVGAAdapterType])
                              (pvd->hvdmVideo,
                               FALSE));

#else
          vvUnvalidatePage(pvd->hvdmVideo,
                           NULL,
                           aiPhysToVirt[i],
                           BANK0);
#endif
          vvFreePhysPage(pvd->hvdmVideo,
                         aiPhysToVirt[i]);

          if (!vdhBTS(&pvd->flVDMVideo,
                      LOG2(VDM_UPDATEHOOK)))
            VDHArmContextHook(pvd->hhookUpdateContext,
                              pvd->hvdmVideo);
          VDHThawVDM(pvd->hvdmVideo);
        }
        ReleaseMutexSem(pvd->hmxVideoState);
        RequestMutexSem(hmxPhysPageEvent);
      }
      ahPhysPage[i] = PHYSPAGE_RESERVED;
    }

    else

      if (ahPhysPage[i] == PHYSPAGE_RESERVED)
      {
        ahPhysPage[i] = PHYSPAGE_AVAILABLE;
        fAvail++;
      }
  }
  flVVD &= ~VVD_NOPHYSPAGES;

  /*
  ** Record external index and data pointers
  */

  prle = arleMemory;
  pbSEQExtShadowIndx = NULL;
  pbGDCExtShadowIndx = NULL;

  while (port = (prle->rle_port&PORT_MASK))
  {
    prle->rle_pbExtShadowData = NULL;
    prle->rle_pbExtShadowIndx = NULL;

    if (port == PORT_SEQINDX)
      prleSEQExtShadowData[prle->rle_indx] = prle;

    else

      if (port == PORT_GDCINDX)

        prleGDCExtShadowData[prle->rle_indx] = prle;

    if (vvdrqVideo.vvd_nbReserved != ALL_RESERVED)
      vvSetupShadowPtrs(vvdrqVideo.vvd_pShadowData,
                        vvdrqVideo.vvd_nShadowRegs,
                        prle);
    prle++;
  }

  if (pdrq)
  {

    if (vvdrqVideo.vvd_pPhysVRAM != 0)
    {
      flVVD &= ~VVD_PMBGND;

#ifdef  GALE                                                            //J-TS00V
      for (plse = lseHeadActive.lse_plseNext;                           //J-TS00V
           plse; plse = plse->lse_plseNext) {                           //J-TS00V
        pvd = pVDMData(plse->lse_hvdm);                                 //J-TS00V
        if (pvd->flVDMGale                     &&                       //J-TS00V
            ((pvd->ulBIOSMode == 0x03) ||                               //J-TS00V
             (pvd->ulBIOSMode == 0x73))        &&                       //J-TS00V
            (pvd->flVDMVideo & VDM_WINDOWED)   &&                       //J-TS00V
                        /* VVDEVENT_MODE is already posted */           //J-TS00V
            (pvd->vvModeEvent.vvm_ulAdapter)) {                         //J-TS00V
          vvAddEvent(pvd->hvdmVideo, VVDEVENT_LVB,                      //J-TS00V
                     SSToDS(&flDirty), EVENT_ASYNC);                    //J-TS00V
        }                                                               //J-TS00V
      }                                                                 //J-TS00V
#endif  //GALE                                                          //J-TS00V

      RequestMutexSem(hmxWindowedEvent);
      plse = lseHeadActive.lse_plseNext;

      while (plse)
      {
        pvd = pVDMData(plse->lse_hvdm);

        /*
        ** See if there are any suspended VDMs we could wake up
        */

        if (fAvail && pvd->mstateVideo == MEMORY_GRFX)
        {

#ifdef   SVGA                                    /* Don't thaw SVGA modes   */

//                    if (!(((pvd->vvMode.vvm_nRows > 480) || ((pvd->vvMode.vvm_nRows >
//                       200) && (pvd->mstateVideo == MEMORY_GRFX256)))))
           if (!(pvd->vvMode.vvm_nRows > 600 && pvd->vvMode.vvm_nCols > 800))
#endif
               vvThawVDM(pvd->hvdmVideo);
        }

        /*
        ** See if there are any unminimized         we should refresh
        */

        if ((pvd->flVDMVideo&(VDM_WINDOWED|VDM_MINIMIZED|VDM_STATEINIT)) ==
           (VDM_WINDOWED|VDM_STATEINIT))
        {
          vvUpdateScreenState(pvd->hvdmVideo,
                              TRUE);
        }
        plse = plse->lse_plseNext;
      }

      if (nPMWindowedVDMs)
      {
        VDHDisarmTimerHook(hhookEventTimer);
        VDHArmTimerHook(hhookEventTimer,
                        TIMER_CHECK,
                        VDH_TIMER_GLOBAL_CONTEXT);/*                        */
        flVVD |= VVD_TIMERARMED;                 /*                         */
      }
      ReleaseMutexSem(hmxWindowedEvent);
    }

    else
      flVVD |= VVD_PMBGND;
  }
  ReleaseMutexSem(hmxPhysPageEvent);
}

/***************************************************************************
 *
 * FUNCTION NAME = vvGetPhysPage()
 *
 * DESCRIPTION   = Allocate (or steal) physical page for VDM
 *
 * INPUT         = iPage == index of page for current VDM
 *
 * OUTPUT        = TRUE if page was allocated, FALSE if not
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vvGetPhysPage(INT iPage)
{
  register INT i;
  INT iVirt,tmp;
  HHOOK hhook;
  BOOL fSuccess;
  INT iNotMine,iMine;
  HVDM hvdmOther,hvdmOtherTmp;
  ULONG timeNotMine,timeMine;

  AssertTRUE(!(VDMData.flVDMVideo&VDM_FGND));

  if (flVVD&VVD_NOPHYSPAGES)
    return  FALSE;

  /*
  ** Hey, we already get one
  */

  if (VDMData.aiVirtToPhys[iPage])
    return  TRUE;

  RequestMutexSem(hmxPhysPageEvent);


retry:

  /*
  ** For VDM request, search from high end down for a whole free page
  */

  fSuccess = FALSE;
  iNotMine = iMine = -1;
  timeNotMine = timeMine = 0xffffffff;

  for (i = MAX_PAGESPERPLANE-1; i >= 0; i--)
  {

    if (ahPhysPage[i] == PHYSPAGE_AVAILABLE)
    {
      fSuccess++;
      break;
    }

/*** V2.0JWK01
 *
 * The search algorithm has been altered to ensure that the VideoState Sem
 * is not currently owned.  Since it is not owned, we can steal the page
 * without releasing and requesting semaphors, which may have returned an error
 * or caused a block while hmxPhysPageEvent is not owned, invalidating the
 * page info obtained during the search.  Also added some error checking.
 */

    hvdmOtherTmp = (HVDM)(ahPhysPage[i]);       //V2.0JWK01


    /*
    ** Just in case there aren't any free pages, record the least
    ** recently stolen page currently being used by other VDMs
    */

    if (THISVDMOWNSPHYSPAGE(CURRENT_VDM,
                            i))
    {

      if (atimePhysPageAlloc[i] < timeMine)
      {
        if (VDHRequestMutexSem(pVDMData(hvdmOtherTmp)->hmxVideoState, 0)) //V2.0JWK01
        {
            iMine = i;
            timeMine = atimePhysPageAlloc[i];
            VDHReleaseMutexSem(pVDMData(hvdmOtherTmp)->hmxVideoState);    //V2.0JWK01
        }
      }
    }

    else

      if (VDMOWNSPHYSPAGE(i))
      {

        if (atimePhysPageAlloc[i] < timeNotMine)
        {
          if (VDHRequestMutexSem(pVDMData(hvdmOtherTmp)->hmxVideoState, 0)) //V2.0JWK01
          {
            iNotMine = i;
            timeNotMine = atimePhysPageAlloc[i];
            VDHReleaseMutexSem(pVDMData(hvdmOtherTmp)->hmxVideoState);    //V2.0JWK01
          }
        }
      }
  }

  /*
  ** If we didn't find a free page, then we steal from whoever we can
  */

  if (!fSuccess)
  {
    i = -1;

    /*
    ** Steal first from other VDMs, then from self
    */

    if (iNotMine >= 0)
      i = iNotMine;

    else

      if (iMine >= 0)

        i = iMine;

    /*
    ** If there's anything to steal, then free and allocate for us
    */

    if (i >= 0)
    {
      iVirt = aiPhysToVirt[i];
      hvdmOther = (HVDM)(ahPhysPage[i]);

      /*
      ** If we're stealing from ourselves, then we don't need a hook
      */

      if (VDMData.hvdmVideo == hvdmOther)
      {

#ifdef   SVGA
        vvUnvalidatePage(hvdmOther,
                         VDMData.hvdmVideo,
                         iVirt,
                         (*apfnSVGAGetBank[ulSVGAAdapterType])(CURRENT_VDM,
                                                               FALSE));

#else
        vvUnvalidatePage(hvdmOther,
                         VDMData.hvdmVideo,
                         iVirt,
                         BANK0);
#endif
        vvFreePhysPage(hvdmOther,
                       iVirt);
        fSuccess++;
      }

      else
      {
 //V2.0JWK41  if (ALLOCHOOK((PFNARM)VVUnmapPhysContext,
 //V2.0JWK41                1,
 //V2.0JWK41                hhook,
 //V2.0JWK41                tmp))
 //V2.0JWK41  {

          /*
          ** To avoid deadlocks, must release all semaphores
          */

          //V2.0JWK01 ReleaseMutexSem(hmxPhysPageEvent);
          //V2.0JWK01 ReleaseMutexSem(VDMData.hmxVideoState);

          /*
          ** Now reclaim semaphores in proper order for victim VDM
          */

          //V2.0JWK01 RequestMutexSem(pVDMData(hvdmOther)->hmxVideoState);
          //V2.0JWK01 RequestMutexSem(hmxPhysPageEvent);

          /*
          ** Next, make sure the victim page is still valid
          */

          if (VDHRequestMutexSem(pVDMData(hvdmOther)->hmxVideoState, 0))
          {
            if (iVirt == aiPhysToVirt[i] && hvdmOther == (HVDM)(ahPhysPage[i]))
            {
              hhook = pVDMData(hvdmOther)->hhookUnMapPhysContext;  //V2.0JWK41
              HOOKDATA(hhook, 0) |= 1 << iVirt;                    //V2.0JWK41
 //V2.0JWK41  HOOKDATA(hhook,0) = iVirt;
 //V2.0JWK41  ARMHOOK(hhook,hvdmOther);
              if (!(pVDMData(hvdmOther)->flVDMXVideo & VDMX_UNMAPHOOK)) {   //V2.0JWK41
                  ARMHOOK(hhook, hvdmOther);                                //V2.0JWK41
                  pVDMData(hvdmOther)->flVDMXVideo |= VDMX_UNMAPHOOK;       //V2.0JWK41
              }                                                             //V2.0JWK41

#ifdef   SVGA
              vvUnvalidatePage(hvdmOther,
                               VDMData.hvdmVideo,
                               iVirt,
                               (*apfnSVGAGetBank[ulSVGAAdapterType])(CURRENT_VDM
                                  ,
                                                                   FALSE));

#else
              vvUnvalidatePage(hvdmOther,
                               VDMData.hvdmVideo,
                               iVirt,
                               BANK0);
#endif
              vvFreePhysPage(hvdmOther,
                             iVirt);
              fSuccess++;
            }
            //V2.0JWK01 ReleaseMutexSem(hmxPhysPageEvent);
            ReleaseMutexSem(pVDMData(hvdmOther)->hmxVideoState);
            //V2.0JWK01 RequestMutexSem(VDMData.hmxVideoState);
            //V2.0JWK01 RequestMutexSem(hmxPhysPageEvent);

            if (!fSuccess || ahPhysPage[i] != PHYSPAGE_AVAILABLE)
            {
              goto retry;
            }
          }
 //V2.0JWK41  }
      }
    }
  }

  /*
  ** Allocate page, and record mapping
  */

  if (fSuccess)
  {
    ahPhysPage[i] = (ULONG)(VDMData.hvdmVideo);
    aiPhysToVirt[i] = iPage;
    atimePhysPageAlloc[i] = VDHQuerySysValue(NULL,
                                             VDHGSV_MSECSBOOT);
    VDMData.aiVirtToPhys[iPage] = i;

    /*
    ** If this is the first page allocated for this VDM,
    ** set its PHYSPAGE bit and request the video controller
    */

    if (!VDMData.nPhysPages++)
    {
      VDMData.flVDMVideo |= VDM_PHYSPAGE;

      /*
      ** To avoid deadlock with PM threads coming in through
      ** GetPhysBytes, we must release PhysPageEvent semaphore first
      */

      ReleaseMutexSem(hmxPhysPageEvent);
      vvRequestController(VDMData.hvdmVideo,
                          FALSE);
      return  fSuccess;
    }
  }

  ReleaseMutexSem(hmxPhysPageEvent);
  return  fSuccess;
}

/***************************************************************************
 *
 * FUNCTION NAME = vvFreePhysPage()
 *
 * DESCRIPTION   = Free physical page for VDM
 *
 *
 * INPUT         = hvdm  == VDM handle
 *                 iPage == index of page for current VDM
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvFreePhysPage(HVDM hvdm,INT iPage)
{
  register INT i;
  register PVDMDATA pvd = pVDMData(hvdm);

  RequestMutexSem(hmxPhysPageEvent);

  if (i = pvd->aiVirtToPhys[iPage])
  {
    AssertTRUE(aiPhysToVirt[i] == iPage);
    pvd->aiVirtToPhys[iPage] = 0;                /* zero the owner's
                                                    physical index          */
    ahPhysPage[i] = NULL;                        /* zero the owner          */
    aiPhysToVirt[i] = 0;                         /* zero the owner's
                                                    virtual page            */
    atimePhysPageAlloc[i] = 0;                   /* zero the time of last
                                                    allocation              */

    if (!--pvd->nPhysPages)
      pvd->flVDMVideo &= ~VDM_PHYSPAGE;
  }
  ReleaseMutexSem(hmxPhysPageEvent);
}

/***************************************************************************
 *
 * FUNCTION NAME = vvFreeAllPhysPages()
 *
 * DESCRIPTION   = Free all physical pages (for a dying VDM)
 *
 * INPUT         = hvdm   == VDM handle
 *                 fDying == TRUE if VDM is dying, FALSE otherwise
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvFreeAllPhysPages(HVDM hvdm,BOOL fDying)
{
  register INT i;
  register PVDMDATA pvd = pVDMData(hvdm);

  /*
  ** First, a quick check before we start taking resources
  */

  if (pvd->flVDMVideo&VDM_PHYSPAGE)
  {
    //V2.0JWK42 switched order of next two semaphor calls to prevent deadlock

        /*** Don't let PHYSPAGE state change from underneath us ***/  //V2.0JWK42
        RequestMutexSem(hmxPhysPageEvent);                            //V2.0JWK42
                                                                      //V2.0JWK42
        /*** Request AND lock the controller ***/                     //V2.0JWK42
        vvRequestController(pvd->hvdmVideo, TRUE);                    //V2.0JWK42

//V2.0JWK42    /*
//V2.0JWK42    ** Request AND lock the controller
//V2.0JWK42    */
//V2.0JWK42
//V2.0JWK42    vvRequestController(pvd->hvdmVideo,
//V2.0JWK42                        TRUE);
//V2.0JWK42
//V2.0JWK42    /*
//V2.0JWK42    ** Don't let PHYSPAGE state change from underneath us
//V2.0JWK42    */
//V2.0JWK42
//V2.0JWK42    RequestMutexSem(hmxPhysPageEvent);

    if (pvd->flVDMVideo&VDM_PHYSPAGE)
    {

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

        if (THISVDMOWNSPHYSPAGE(hvdm,
                                i))
        {

          if (!fDying)

#ifdef   SVGA
               vvUnvalidatePage(hvdm,
                                NULL,
                                aiPhysToVirt[i],
                                (*apfnSVGAGetBank[ulSVGAAdapterType])(hvdm,
                                                                      FALSE));

#else
          vvUnvalidatePage(hvdm,
                           NULL,
                           aiPhysToVirt[i],
                           BANK0);
#endif
          vvFreePhysPage(hvdm,
                         aiPhysToVirt[i]);
        }
      }
    }
    ReleaseMutexSem(hmxPhysPageEvent);

    /*
    ** Controller is up for grabs now
    */

    vvFreeController(pvd->hvdmVideo);
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = vvGetPhysBytes()
 *
 * DESCRIPTION   = Allocate physical video memory for PM
 *
 *                 WARNING WARNING WARNING
 *
 *                 Although it is not clear by just looking at this code, it
 *                 is perfectly legitimate for the video controller to be
 *                 locked for use by PM when this request is made.  This
 *                 fact, in turn, dictates the semaphore hierarchy that must
 *                 be followed throughout this module:  Request controller
 *                 first and PhysPageEvent semaphore last.
 *
 * INPUT         = nBytes == # bytes required
 *
 * OUTPUT        = Offset of physical video memory, NULL if none
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

ULONG PRIVENTRY vvGetPhysBytes(ULONG nBytes)
{
  ULONG p = 0;
  register INT i,j,k;

  /*
  ** Fail request if there are any ACTIVE VDMs running around
  */

  if (!lseHeadActive.lse_plseNext)
  {
    RequestMutexSem(hmxPhysPageEvent);           /*                         */

    /*
    ** Since the VGA Controller ownership can change by the time this
    ** point is reached, lets make sure the Controller is locked when
    ** this thread claims it to avoid deadlock with vvGetPhysPage
    */


#ifdef   EGAVGA                                  /*                         */
    vvRequestController(DISPLAY_OWNER,
                    LOCKBUTDONOTBLOCK);          /*                         */
#endif                                           /*                         */

    /*
    ** For PM request, search from low end up (and no stealing!)
    */

    for (i = 0,
         j = -1,
         k = 0; i < MAX_PAGESPERPLANE; i++)
    {

      if (ahPhysPage[i] == PHYSPAGE_AVAILABLE)
      {

        if (j < 0)
        {
          j = i;                                 /* save index of first
                                                    page                    */
          k = PAGESIZE;                          /* initialize byte count   */
        }

        else
          k += PAGESIZE;                         /* otherwise, bump byte
                                                    count                   */
      }

      else
        j = -1;

      if (k >= nBytes)
      {
        p = j *PAGESIZE+ahPhysPage[j];

        for (i = j; k > 0; i++)
        {
          j = PAGESIZE-ahPhysPage[i];            /* get # bytes in page     */
          ahPhysPage[i] += min(j,
                               k);
          k -= j;                                /* note that this is more
                                                    general                 */
        }                                        /* than we need to be....  */
        break;
      }
    }

#ifdef   EGAVGA                                  /*                         */
    vvFreeController(DISPLAY_OWNER);             /*                         */
#endif                                           /*                         */
    ReleaseMutexSem(hmxPhysPageEvent);           /*                         */
  }
  return  p;
}

/***************************************************************************
 *
 * FUNCTION NAME = vvFreePhysBytes()
 *
 * DESCRIPTION   = Free physical video memory for PM
 *
 *                 WARNING WARNING WARNING Although it is not clear by just
 *                 looking at this code, it is perfectly legitimate for the
 *                 video controller to be locked for use by PM when this
 *                 request is made.  This fact, in turn, dictates the
 *                 semaphore hierarchy that must be followed throughout this
 *                 module:  Request controller first and PhysPageEvent
 *                 semaphore last.
 *
 * INPUT         = nBytes == # bytes required
 *                 p      == offset of physical video memory
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID PRIVENTRY vvFreePhysBytes(ULONG nBytes,ULONG p)
{
  register INT i,k;

  RequestMutexSem(hmxPhysPageEvent);

  /*
  ** Since the VGA Controller ownership can change by the time this
  ** point is reached, lets make sure the Controller is locked when
  ** this thread claims it to avoid deadlock with vvGetPhysPage
  */

#ifdef   EGAVGA                                  /*                         */
  vvRequestController(DISPLAY_OWNER,
                    LOCKBUTDONOTBLOCK);          /*                         */
#endif                                           /*                         */

  for (i = p/PAGESIZE,
       k = nBytes; k > 0; i++)
  {
    k -= ahPhysPage[i];
    ahPhysPage[i] = PHYSPAGE_AVAILABLE;
  }

#ifdef   EGAVGA                                  /*                         */
  vvFreeController(DISPLAY_OWNER);               /*                         */
#endif                                           /*                         */
  ReleaseMutexSem(hmxPhysPageEvent);
}

/***************************************************************************
 *
 * FUNCTION NAME = VVUnmapPhysContext()
 *
 * DESCRIPTION   = Unmap a physical page in current VDM
 *
 *                 This is called whenever we have stolen a physical page
 *                 for a VDM.  It unmaps the specified page so that if the
 *                 VDM tries to touch it again, we will catch a page fault
 *                 first.
 *
 * INPUT         = hhook == hook handle
 *               (1st reference item is bitmap of stolen pages to be unmapped) //V2.0JWK41
 *                 pcrf -> VDM register frame
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VVUnmapPhysContext(HHOOK hhook,PCRF pcrf)
{
  PBVDM pvdm;
  register ULONG flags;                                              //V2.0JWK41
  register ULONG i = 0;                                              //V2.0JWK41



  VDMData.flVDMXVideo &= ~VDMX_UNMAPHOOK;                            //V2.0JWK41
  flags = HOOKDATA(hhook,0);                                         //V2.0JWK41
                                                                     //V2.0JWK41
  while (flags) {                                                    //V2.0JWK41
                                                                     //V2.0JWK41
        if (flags & 1) {                                             //V2.0JWK41
            pvdm = i*PAGESIZE + VDMData.pvdmPhysVRAMActive;          //V2.0JWK41
            vvMapPage(pvdm, NULL, ALL_PLANES, BANK0, VDHMT_INVALID); //V2.0JWK41
        }                                                            //V2.0JWK41
        flags >>= 1;                                                 //V2.0JWK41
        i++;                                                         //V2.0JWK41
  }                                                                  //V2.0JWK41
  HOOKDATA(hhook,0) = 0;                                             //V2.0JWK41


//V2.0JWK41  pvdm = HOOKDATA(hhook,
//V2.0JWK41                  0)*PAGESIZE+VDMData.pvdmPhysVRAMActive;
//V2.0JWK41  FREEHOOK(hhook);
//V2.0JWK41  vvMapPage(pvdm,
//V2.0JWK41            NULL,
//V2.0JWK41            ALL_PLANES,
//V2.0JWK41            BANK0,                                              /*            */
//V2.0JWK41            VDHMT_INVALID);


}

/***************************************************************************
 *
 * FUNCTION NAME = VVUpdateContext()
 *
 * DESCRIPTION   = Update VDM page mappings in context
 *
 *
 * INPUT         = p == undefined
 *                 pcrf -> VDM register frame (ignored)
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VVUpdateContext(PVOID p,PCRF pcrf)
{
#ifdef  XVIO                                                            //J-TS00V
  if ((VDMData.flVDMVideoJ & VDMJ_GRAPHICSWRITE) &&                     //J-TS00V
      (VDMData.flVDMVideoJ & VDMJ_CANCELWRITE)) {                       //J-TS00V
                    /* if XVIO is already hided, do nothig */           //J-TS00V
    VDMData.flVDMVideoJ &= ~(VDMJ_GRAPHICSWRITE | VDMJ_CANCELWRITE);    //J-TS00V
  } else if (VDMData.flVDMVideoJ & VDMJ_GRAPHICSWRITE) {                //J-TS00V
    RequestMutexSem(VDMData.hmxVideoState);                             //J-TS00V
    VDHFreezeVDM(VDMData.hvdmVideo);                                    //J-TS00V
    if (VDMData.flVDMVideo & VDM_WINDOWED) {                            //J-TS00V
      vvRequestController(VDMData.hvdmVideo, TRUE);                     //J-TS00V
      vvUnlockController();                                             //J-TS00V
    }                                                                   //J-TS00V
    vvExtWriteStrGale(VDMData.hvdmVideo,                                //J-TS00V
                      &VDMData.XVIOData.vxWStr,                         //J-TS00V
                      VDMData.XVIOData.GaleXVIOLVB);                    //J-TS00V
    VDMData.flVDMVideoJ &= ~VDMJ_GRAPHICSWRITE;                         //J-TS00V
    VDHThawVDM(VDMData.hvdmVideo);                                      //J-TS00V
    ReleaseMutexSem(VDMData.hmxVideoState);                             //J-TS00V
  }                                                                     //J-TS00V
#endif  //XVIO                                                          //J-TS00V

#ifdef SVGA
  if ((ulSVGAAdapterType == S3_ADAPTER) &&
      (VDMData.flVDMXVideo & VDMX_NOIOTRAPPING) &&
      !(VDMData.flVDMVideo & VDM_UPDATEHOOK))
  {
      v8514SetIOHooks(TRUE);
      return;
  }
#endif

  /*
  ** Set up all appropriate mappings
  */

  VDMData.flVDMVideo &= ~VDM_UPDATEHOOK;
  VVEnableBuffer(TRUE,
                 pcrf);
}

/***************************************************************************
 *
 * FUNCTION NAME = VVUpdatePhysContext()
 *
 * DESCRIPTION   = Set up I/O state for current VDM
 *
 *                 This sets up the hardware for a VDM with PHYSPAGE memory.
 *                 Note that we first have to successfully request ownership
 *                 of the video controller, which may block us temporarily.
 *
 * INPUT         =  p    -> refdata (none)
 *                  pcrf -> VDM register frame
 *
 * OUTPUT        =  None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

VOID HOOKENTRY VVUpdatePhysContext(PVOID p,PCRF pcrf)
{
  VDMData.flVDMVideo &= ~VDM_PHYSHOOK;

  /*
  ** First, a quick check before we start taking resources
  */

  if (VDMData.nPhysPages)
  {

    /*
    ** Don't let PHYSPAGE state change from underneath us
    */

    RequestMutexSem(VDMData.hmxVideoState);

    /*
    ** Request AND lock the controller
    */

    vvRequestController(VDMData.hvdmVideo,
                        TRUE);

    if (VDMData.nPhysPages)
    {

      /*
      ** Restore latches and I/O state, IN THAT ORDER
      */

      vvRestoreLatches(CURRENT_VDM,
                       FALSE);
      vvSetIOState(CURRENT_VDM,
                   arleMemory,
                   SETIO_LIMIT_SHADOWED);
    }

    /*
    ** Controller is still ours, but can be stolen now
    */

    vvUnlockController();
    ReleaseMutexSem(VDMData.hmxVideoState);
  }
}

#pragma  END_SWAP_CODE

