/*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.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = S3QESC                                         */
/*                                                                    */
/*   Description     = Display Device Driver Escape functions:        */
/*                     Escape,                                        */
/*                     QueryEscSupport,                               */
/*                                                                    */
/*   Function        = Escape routes a call to an Escape Subfunction  */
/*                     using the given Escape Code.                   */
/*                     QueryEscSupport indicates which Escape         */
/*                     Subfunctions are supported.                    */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/

#ifdef S3

#define GET_S3_ADDR
#define INCL_DOSFILEMGR
#define INCL_DOSMISC
#define INCL_DOSDEVICES
#define INCL_GRE_DEVICE
#include <eddinclt.h>
#include <eddvcone.h>
#include <edddtypt.h>
#include <eddqextf.h>
#include <eddgextf.h>
#include <eddmextf.h>
#include <cursor.h>
#include <cacheman.h>

#ifdef GET_S3_ADDR
#include <eddesres.h>
ULONG FindS3Aperture(PAPERTURE);
#define EISA_BUS  0
#define LOCAL_BUS 1
#define ISA_BUS   3
extern ULONG               pVRAM;
ULONG  flTestFirst = 0;
ULONG  pTest = NULL;
#endif

extern  PHWMAP             pHWMap;

extern DDTType             DDT;
extern AvioFontTableType   AvioBaseFont[NO_OF_AVIO_FONTS];
extern SHORT               softDrawInUse;
extern CURSORDATA          cursor_data;

/**********************************************************************/
/* Function prototype needed because of forward reference             */
/**********************************************************************/
ULONG SwitchBank(ULONG, PULONG);

#define APERTURE_SAVED 0x01

extern ADAPTER8514  ai8514Adapter;
extern FSRSEM       FSRDriverSem;

typedef struct
{
  USHORT control;
  USHORT index;
  ULONG  flags;
} SAVEDAPERTURE;

typedef struct  SCRNTX
{
        ULONG stx_Address;
        ULONG stx_Size;
        ULONG stx_flFlag;
} SCRNTX;

typedef struct  SCRNRX
{
        ULONG srx_ScrnPtr;
} SCRNRX;

/* Globals */
APERTURE best_aperture = { 0, 0, 0 };
SAVEDAPERTURE saved_aperture = { 0, 0, 0 };

/**********************************************************************/
/* Defect 66836 - We must set the PEL order field of the Memery       */
/* Access Mode Register to Intel format for the multi-media folks.    */
/* The         display driver is setting this field to Motorola       */
/* format when blitting in a seamless window.                         */
/*                                                                    */
/* Save a local copy of the Memory Access Mode Register               */
/**********************************************************************/
USHORT usMAMR;


/**********************************************************************/
/*                                                                    */
/*   4 SMV (software motion video) DevEscapes added for DCR 96:       */
/*                                                                    */
/*   - GETAPERTURE returns the size and physical address of the       */
/*     largest available aperture.                                    */
/*                                                                    */
/*   - ACQUIREFB allows the caller exclusive access to the adapter    */
/*                                                                    */
/*   - DEACQUIREFB releases the adapter for use by other components   */
/*                                                                    */
/*   - SWITCHBANK allows the caller to select which bank of VRAM is   */
/*     mapped into the aperture (64K only).                           */
/*                                                                    */
/**********************************************************************/

/***EP  GetAperture() - Get the video aperture
 *
 *  This DevEsc will be called be an application in order to get
 *  the aperture information.
 *
 *  ENTRY
 *      PULONG pcOutCount -> Pointer to a ULONG that contains
 *                           the number of bytes being requested.
 *
 *      PAPERTURE pAperture -> Pointer to the APERTURE structure
 *                                shown below. We will fill this in.
 *
 *      typedef struct
 *      {
 *        ULONG ulPhysAddr;      // Physical address of the VRAM
 *        ULONG ulApertureSize;  // Aperture size in bytes
 *        ULONG ulScanLineSize;  // Scan line size in bytes
 *        RECTL rctlScreen;      // Screen dimensions
 *      } APERTURE;
 *
 *      typedef APERTURE *PAPERTURE;
 *
 *
 *  EXIT
 *      SUCCESS - Structure is updated
 *
 *  Defects 62446 and 68657 - On some 386 SX machines, the VE bit of POS
 *  register base+4 is ON indicating that the 4M aperture is enabled.
 *  The 4M aperture should never be ON on an SX system because these
 *  systems have a 16 bit data bus.  This is a HW error probably located
 *  in the POST code. This problem is also carried over to systems with
 *  an XGA/2 adapter when DMQS is used.  The DMQS information is also
 *  incorrect under this circumstance.
 *
 *  As a workaround we check the 1M aperture first.  If the 1M aperture
 *  is not enabled we must check the system interface bus size via
 *  the Auto-config register.
 *
 *  BTW: This problem was first noticed on a model 57 SX machine.
 *
 */

ULONG GetAperture(PULONG pcOutCount, PAPERTURE pAperture)
{

  #ifdef GET_S3_ADDR
  FindS3Aperture( pAperture );
  #else
  pAperture->ulPhysAddr = 0xa0000;
  pAperture->ulApertureSize = 64 * 1024;
  #endif

  if ( DDT.BitCount == 8 )
  {
     if ( DDT.ScreenWidth == RES_1280_WIDTH )
     {
        // 1280 scan line
        pAperture->ulScanLineSize = 1280;
     }
     else
     {
          // 1k scan line
        pAperture->ulScanLineSize = 1024;
     }

  }
  else
     if (DDT.BitCount == 24)
     {
        //-----------------------------------------------
        //      for 24bpp Multimedia (Defect 95371).
        //-----------------------------------------------
        pAperture->ulScanLineSize = -pHWMap->phys_width;
     }
     else
     {
        //-----------------------------------------------
        // 16 bpp.
        //-----------------------------------------------
        pAperture->ulScanLineSize = DDT.ScreenWidth;
     }

  pAperture->rctlScreen.xLeft = 0;
  pAperture->rctlScreen.xRight = DDT.ScreenWidth-1;
  pAperture->rctlScreen.yBottom = DDT.ScreenHeight-1;
  pAperture->rctlScreen.yTop = 0;

  *pcOutCount = sizeof(APERTURE);

  return(DEV_OK);

} /* GetAperture */

/***EP  AcquireFB() - Acquire the frame buffer
 *
 *  This DevEsc will be called be an application in order to get
 *  exclusive access to the frame buffer.
 *
 *  ENTRY
 *      ULONG cInCount - Bytes count of caller data
 *
 *      PACQUIREFB pAcquireFB - Pointer to the ACQUIREFB structure.
 *                              This structure is shown below and defined
 *                              in PMDEV.H.
 *
 *  typedef struct
 *  {
 *    ULONG fAFBFlags;    // Action flags
 *    ULONG ulBankNumber; // Which bank # is being requested
 *                        //-----------------------------------------------
 *                        // This is needed so they don't have to switch
 *                        // banks before aquireing the frame buffer.
 *                        //-----------------------------------------------
 *    RECTL rctlXRegion;  // Cursor Xclude region.
 *  } ACQUIREFB;       // Aquire frame buffer
 *
 *  typedef ACQUIREFB *PACQUIREFB;
 *
 *  Where fAFBFlags bits are defined as;
 *
 *  Bit 0 - (AFB_SWITCH = 1)  // Switch bank before giving access
 *          OFF               // No bank switching.
 *
 *  EXIT
 *      SUCCESS
 *          return(DEV_OK) - App now has exclusive access to the frame buffer.
 *      FAILURE
 *          LogError(PMERR_INV_ESCAPE_DATA);
 *          return(DEVESC_ERROR);
 *
 */

ULONG AcquireFB(ULONG cInCount, PACQUIREFB pAcquireFB)
{
  register USHORT sem_result;
  register USHORT ax;
  register USHORT bx;

  IgnoreParam(cInCount);

  sem_result = RequestDriverSemaphore();

  if ( sem_result != NULL )
  {
    /**************************************************************/
    /* Failed to get the semaphore.                               */
    /**************************************************************/
    return(DEVESC_ERROR);
  }

  //-------------------------------------------------------------------
  // The check for an idle accelerator has been moved here so that the
  // check is made AFTER we get the semaphore but BEFORE we but the
  // accelerator into linear addressing mode.  CMVC 99406.
  //-------------------------------------------------------------------
  while (  ( inpw(0x9ae8) & 0x00FF ) );
  while (  ( inpw(0x9ae8) & 0x200 ) );

  #ifdef GET_S3_ADDR
  // Get the existing aperture
  outp(S3_NDX_PORT,0x5A);
  saved_aperture.control = (USHORT)inp(S3_RW_PORT);
  outp(S3_NDX_PORT,0x58);
    saved_aperture.index = (USHORT)inp(S3_RW_PORT);
  #endif

  if(pAcquireFB->fAFBFlags & AFB_SWITCH) {
     if( SwitchBank(sizeof(ULONG), &pAcquireFB->ulBankNumber) == DEVESC_ERROR )
        return(DEVESC_ERROR);
  }

  /******************************************************************/
  /* If we are using a software cursor we will update the cursor    */
  /* exclude region. UpdateXcludeRegion will remove the cursor      */
  /* if it is currently in this region.                             */
  /******************************************************************/
  if ( cursor_data.cursor_status & CURSOR_SOFTWARE)
     UpdateXcludeRegion(pAcquireFB->rctlXRegion);

  // Put Driver in LA mode

  _asm { cli }

  #ifdef GET_S3_ADDR
  // Set the new aperture
  outp(S3_NDX_PORT,0x5A);
  outp(S3_RW_PORT,(USHORT)((best_aperture.ulPhysAddr)>>16) );
  outp(S3_NDX_PORT,0x59);
  outp(S3_RW_PORT,(USHORT)((best_aperture.ulPhysAddr)>>24) );
  outp(S3_NDX_PORT,S3_LAW_CTL);
  ax = (USHORT)inp(S3_RW_PORT);
  ax &= 0xFC;

  // pick and set buffer size
  switch (best_aperture.ulApertureSize) {
  case ONE_MEG_ADAPTER:
     bx = 1;
     break;
  case TWO_MEG_ADAPTER:
     bx = 2;
     break;
  case FOUR_MEG_ADAPTER:
     bx = 3;
     break;
  default:
     bx = 0;
     break;
  }
  ax |= bx;

  // turn on linear addressing bit
  ax |= S3_LINEAR_ADDRESSING;
  outp(S3_RW_PORT,ax);

  #else
  outp(S3_NDX_PORT,S3_LAW_CTL);
  ax = (USHORT)inp(S3_RW_PORT);
  ax |= S3_LINEAR_ADDRESSING;
  outp(S3_RW_PORT,ax);
  #endif

  cursor_data.cursor_status |= CURSOR_DRVR_IN_LA;

  _asm { sti }

  return(DEV_OK);

} /* AcquireFB */

/***EP  DeacquireFB() - Release the frame buffer
 *
 *  This DevEsc will be called by an application when it wants
 *  to release its access to the frame buffer.
 *
 *  ENTRY
 *      No input parms
 *
 *  EXIT
 *      SUCCESS
 *          return(DEV_OK)
 *      FAILURE
 *          LogError(PMERR_INV_ESCAPE_DATA);
 *          return(DEVESC_ERROR);
 *
 */

ULONG DeacquireFB(VOID)
{
  ULONG rc = DEV_OK;
  register USHORT ax;

  _asm { cli }

  // Put Driver back in Non-LA mode
  outp(S3_NDX_PORT,S3_LAW_CTL);
  ax = (USHORT)inp(S3_RW_PORT);
  ax &= ~S3_LINEAR_ADDRESSING;
  outp(S3_RW_PORT,ax);

  #ifdef GET_S3_ADDR
  // Set the old aperture
  outp(S3_NDX_PORT,0x5A);
  outp(S3_RW_PORT, (USHORT)saved_aperture.control);
  outp(S3_NDX_PORT,0x59);
  outp(S3_RW_PORT, 0);
  outp(S3_NDX_PORT,S3_LAW_CTL);
  outp(S3_RW_PORT,saved_aperture.index);
  #endif

  /******************************************************************/
  /* No more exclude region                                         */
  /******************************************************************/
  cursor_data.cursor_status &= ~(CURSOR_XREGION | CURSOR_DRVR_IN_LA);

  cursor_data.bank_values = 0;  // Reset Bank Values to 0

  _asm { sti }

  ReleaseDriverSemaphore();
  return(rc);

} /* DeacquireFB */


#ifdef GET_S3_ADDR
/***EP  FindS3Aperture() - Get the video aperture for various S3 machines
 *
 *  ENTRY
 *      PAPERTURE pAperture -> Pointer to the APERTURE structure
 *                                shown below. We will fill this in.
 *      typedef struct
 *      {
 *        ULONG ulPhysAddr;      // Physical address of the VRAM
 *        ULONG ulApertureSize;  // Aperture size in bytes
 *        ULONG ulScanLineSize;  // Scan line size in bytes
 *        RECTL rctlScreen;      // Screen dimensions
 *      } APERTURE;
 *
 *      typedef APERTURE *PAPERTURE;
 *
 *
 *  EXIT
 *      SUCCESS - Structure is updated
 *
 */

ULONG Myatol(PSZ psz)
{

  PSZ    p1;
  ULONG  ulvalue = 0;

  p1 = psz;
  for(;*p1>='0' && *p1<='F';p1++)     /* Convert ASCII to integer hex */
  {
     ulvalue = ulvalue * 0x10;
     if ( ('0'<= *p1) && (*p1 <= '9') ) {
     ulvalue += *p1 - '0';
     }
     else if ( ('A'<= *p1) && (*p1 <= 'F') ) {
     ulvalue += *p1 - 'A' + 10;
     }
  }

  return(ulvalue);
}

ULONG GetHardCodedAddr(PAPERTURE pAperture)
{
  ULONG ulRet = 0;
  PSZ   pszAddr;

  if(!DosScanEnv( "VIDEO_APERTURE" , &pszAddr ))
  {
     if ( ulRet = Myatol( pszAddr ) )
     {
        ulRet = ulRet << 20;
        pAperture->ulPhysAddr = ulRet;
        pAperture->ulApertureSize = ai8514Adapter.lMemorySize;
        ulRet = DEV_OK;

     }
     else
     {
        // if zero addr use able thousand addr
        pAperture->ulPhysAddr = 0xa0000;
        pAperture->ulApertureSize = 64 * 1024;
        ulRet = DEV_OK;
     }

  }

  return(ulRet);

} /*GetHardCodedAddr */


VOID TestAperture(PAPERTURE pAperture)
{
           ULONG  ulBank = 0;
           BYTE   SaveBuffer[5];
  register USHORT ax = 1;

  while ( ( inpw(0x9ae8) & 0x200 ) );

  if ( !RequestDriverSemaphore() )
  {
     // Set the aperture
     _asm { cli }
     outp(S3_NDX_PORT,0x59);
     outp(S3_RW_PORT,0x0);
     outp(S3_NDX_PORT,0x5A);
     outp(S3_RW_PORT,0x0A);

     // turn on LA mode
     outp(S3_NDX_PORT,S3_LAW_CTL);
     ax = (USHORT)inp(S3_RW_PORT);
     ax |= S3_LINEAR_ADDRESSING;
     outp(S3_RW_PORT,ax);

     SwitchBank(sizeof(ULONG), &ulBank);
     _asm { sti }

     memcpy( &SaveBuffer , pVRAM , 5 );
     memcpy( pVRAM , "BINAR" , 5 );

     // Set the new aperture
     _asm { cli }
     // take driver out of la mode to reset aperture
     outp(S3_NDX_PORT,S3_LAW_CTL);
     ax = (USHORT)inp(S3_RW_PORT);
     ax &= 0xEC;
     outp(S3_RW_PORT,ax);

     outp(S3_NDX_PORT,0x5A);
     outp(S3_RW_PORT,(USHORT)((pAperture->ulPhysAddr)>>16) );
     outp(S3_NDX_PORT,0x59);
     outp(S3_RW_PORT,(USHORT)((pAperture->ulPhysAddr)>>24) );
     outp(S3_NDX_PORT,S3_LAW_CTL);
     ax = (USHORT)inp(S3_RW_PORT);
     ax &= 0xFC;

     // Make it one meg and turn on LA mode
     ax |= 0x01 + S3_LINEAR_ADDRESSING;
     outp(S3_RW_PORT,ax);
     _asm { sti }

     // Get the pointer to test
     GetVRAMPointer( best_aperture.ulPhysAddr, 0x1000, &flTestFirst, &pTest );

     // read vram area while in linear mode
     if( memcmp( pTest , "BINAR" , 5 ))
     {
        // if not the same then set aperture addr to A0000
        pAperture->ulPhysAddr = 0xa0000;
        pAperture->ulApertureSize = 64 * 1024;
     }

     // Set the old aperture and law size
     _asm { cli }
     // take driver out of la mode to reset aperture
     outp(S3_NDX_PORT,S3_LAW_CTL);
     ax = (USHORT)inp(S3_RW_PORT);
     // set size to 64k and clear LA bit
     ax &= 0xEC;
     outp(S3_RW_PORT,ax);

     // set window to 64k
     outp(S3_NDX_PORT,0x5A);
     outp(S3_RW_PORT, 0x0A);
     outp(S3_NDX_PORT,0x59);
     outp(S3_RW_PORT, 0);

     // turn on LA mode
     outp(S3_NDX_PORT,S3_LAW_CTL);
     ax = (USHORT)inp(S3_RW_PORT);
     ax |= S3_LINEAR_ADDRESSING;
     outp(S3_RW_PORT,ax);
     _asm { sti }

     // restore what was there
     memcpy( pVRAM , &SaveBuffer , 5 );

     // Put Driver back in Non-LA mode
     _asm { cli }
     outp(S3_NDX_PORT,S3_LAW_CTL);
     ax = (USHORT)inp(S3_RW_PORT);
     ax &= ~S3_LINEAR_ADDRESSING;
     outp(S3_RW_PORT,ax);
     _asm { sti }

     ReleaseDriverSemaphore();
  }

  return;

} /* TestAperture */

ULONG FindS3Aperture(PAPERTURE pAperture)
{
  ULONG ulMem = 0;
  register USHORT ax;

  if ( !flTestFirst ) {
    // now lets see if our memory fits
    if ( !GetHardCodedAddr(pAperture)) {

       // Find out how much memry is loaded on the system
       DosQuerySysInfo( QSV_TOTPHYSMEM , QSV_TOTPHYSMEM , &ulMem , sizeof( ulMem ));

       // ulMem is in bytes we need it in Megabytes
       ulMem = (ulMem >> 20);

       // read index 36 to see what bus we have
       outp(S3_NDX_PORT,S3_CONFIG_REG1);
       ax = (USHORT)inp(S3_RW_PORT);
       ax &= 3;

       if ( ax != ISA_BUS ) {
          if ( ulMem < 60 ) {
             if ( ai8514Adapter.lMemorySize <= FOUR_MEG_ADAPTER ) {
                pAperture->ulPhysAddr = 0x3C00000;
                pAperture->ulApertureSize = ai8514Adapter.lMemorySize;
             }
          }
          else if ( ulMem < 62 ) {
             if ( ai8514Adapter.lMemorySize <= TWO_MEG_ADAPTER ) {
                pAperture->ulPhysAddr = 0x3E00000;
                pAperture->ulApertureSize = ai8514Adapter.lMemorySize;
             }
          }
          else if ( ulMem < 63 ) {
             if ( ai8514Adapter.lMemorySize <= ONE_MEG_ADAPTER ) {
                pAperture->ulPhysAddr = 0x3F00000;
                pAperture->ulApertureSize = ai8514Adapter.lMemorySize;
             }
          }
          else
          {
             pAperture->ulPhysAddr = 0xa0000;
             pAperture->ulApertureSize = 64 * 1024;
          }
       }
       else if ( ulMem < 12 ) {
          if ( ai8514Adapter.lMemorySize <= FOUR_MEG_ADAPTER ) {
             pAperture->ulPhysAddr = 0xC00000;
             pAperture->ulApertureSize = ai8514Adapter.lMemorySize;
          }
       }
       else if ( ulMem < 14 ) {
          if ( ai8514Adapter.lMemorySize <= TWO_MEG_ADAPTER ) {
             pAperture->ulPhysAddr = 0xE00000;
             pAperture->ulApertureSize = ai8514Adapter.lMemorySize;
          }
       }
       else if ( ulMem < 15 ) {
          if ( ai8514Adapter.lMemorySize <= ONE_MEG_ADAPTER ) {
             pAperture->ulPhysAddr = 0xF00000;
             pAperture->ulApertureSize = ai8514Adapter.lMemorySize;
          }
       }
       else
       {
          pAperture->ulPhysAddr = 0xa0000;
          pAperture->ulApertureSize = 64 * 1024;
       }
    }

    //------------------------------------------------------------------
    // Defect 95371.
    //------------------------------------------------------------------
    //if ( DDT.BitCount == 24 )
    //{
    //   pAperture->ulPhysAddr = 0xa0000;
    //   pAperture->ulApertureSize = 64 * 1024;
    //}

    if (pAperture->ulPhysAddr != 0xa0000 ) {
       // this will test the aperture and set it to A0000 if not valid
       best_aperture.ulPhysAddr = pAperture->ulPhysAddr;
       best_aperture.ulApertureSize = pAperture->ulApertureSize;
       TestAperture( pAperture );
    }

    best_aperture.ulPhysAddr = pAperture->ulPhysAddr;
    best_aperture.ulApertureSize = pAperture->ulApertureSize;
  }
  else
  {
     pAperture->ulPhysAddr = best_aperture.ulPhysAddr;
     pAperture->ulApertureSize = best_aperture.ulApertureSize;
  }

  return(DEV_OK);

} /* FindS3Aperture */
#endif

/***EP  SwitchBank() - Switch to a specific bank number.
 *
 *  This DevEsc will be called be an application when it wants to
 *  switch to a specific bank.
 *
 *  ENTRY
 *      ULONG cInCount - Bytes count of caller data
 *
 *      PULONG pInData - Pointer to a ULONG containing the bank number.
 *
 *  EXIT
 *      SUCCESS
 *          return(DEV_OK) - Bank has been switch successfully.
 *      FAILURE
 *          LogError(PMERR_INV_ESCAPE_DATA);
 *          return(DEVESC_ERROR);
 *
 */

ULONG SwitchBank(ULONG cInCount, PULONG pInData)
{
  ULONG MaxBankNo;
  ULONG ulScanSize;
  register USHORT dx;
  register USHORT ax;

  IgnoreParam(cInCount);

  ulScanSize = DDT.ScreenWidth * (DDT.BitCount / 8);
  if(ulScanSize < 1024 ) ulScanSize = 1024;

  MaxBankNo = (DDT.ScreenHeight * ulScanSize) + 0xFFFF / 0x10000;

  if (MaxBankNo==0) MaxBankNo=1;

  /********************************************************************/
  /* Frame buffer must be acquired and bank number must be valid...   */
  /********************************************************************/
  if( *pInData > MaxBankNo)
  {
    LogError(PMERR_INV_ESCAPE_DATA);
    return(DEVESC_ERROR);
  }

  dx = (USHORT)*pInData;
  dx &= 0x003f;

  cursor_data.bank_values = dx;  // Store bank values to be restored
                                 // at cursor interrupt time.

  outp(S3_NDX_PORT,S3_CRTR_LOCK);
  ax = (USHORT)inp(S3_RW_PORT);  // Get current value of CRTR_LOCK Reg.
  ax &= ax & 0xfff0;
  ax |= (dx & 0x0f);             // Or in new low 64K bank value
  outp(S3_RW_PORT,ax);           // Set new CRTR_LOCK Reg.

  outp(S3_NDX_PORT,S3_EX_SCTL_2);
  ax = (USHORT)inp(S3_RW_PORT);  // Get current value of EX_SCTL_2 Reg.
  ax &= 0xfff3;
  ax |= ((dx & 0x30) >> 2);      // Or in new high 64K bank value
  outp(S3_RW_PORT,ax);           // Set new EX_SCTL_2 Reg.

  return(DEV_OK);

} /* SwitchBank */

/**********************************************************************/
/*                                                                    */
/*   Escape will (depending on the given Escape Code):                */
/*                                                                    */
/*   - route the call to an Escape Subfunction and return the result  */
/*     (and the altered parameters)                                   */
/*                                                                    */
/*   - return DEVESC_NOTIMPLEMENTED if the requested Escape           */
/*     Subfunction is not supported by the driver                     */
/*                                                                    */
/**********************************************************************/

DDIENTRY eddq_Escape (HDC       hdc,
                      ULONG     ArgEscape,
                      ULONG     ArgInCount,
                      PULONG    ArgInData,
                      PULONG    ArgOutCount,
                      PULONG    ArgOutData,
                      PDC       pdcArg,
                      ULONG     FunN)

{
    ULONG   retval;

    /******************************************************************/
    /* For DCR 96: add the SwitchBank function. This must be at ring  */
    /* 2 in order to do the in and out to the XGA indexed registers.  */
    /* If this is called at ring3 then making a call to pmwin for     */
    /* VisRegionNotify causes pmwin to trap. Avoid this by setting    */
    /* the DONT_CLEAN option on EnterDriver - this is OK as long as a */
    /* DevEscape is never added which does drawing using the clip     */
    /* region.                                */
    /******************************************************************/

    #define FLAGS EDF_STANDARD | EDF_DONT_CLEAN

    IgnoreParam(hdc);

    /******************************************************************/
    /* Select function according to ArgEscape.                        */
    /******************************************************************/
    switch (ArgEscape)
    {

    case DEVESC_QUERYESCSUPPORT:
        EnterDriver(pdcArg, FunN, FLAGS);
        retval = eddq_QueryEscSupport(ArgInData);
        ExitDriver(pdcArg, FunN,  FLAGS);
        break;

    case DEVESC_QUERYVIOCELLSIZES:
        EnterDriver(pdcArg, FunN, FLAGS);
        retval = eddq_QueryVIOCellSizes(ArgOutCount, ArgOutData);
        ExitDriver(pdcArg, FunN,  FLAGS);
        break;

    case DEVESC_GETAPERTURE:
        EnterDriver(pdcArg, FunN, FLAGS);
        retval = GetAperture(ArgOutCount, (PVOID)ArgOutData);
        ExitDriver(pdcArg, FunN,  FLAGS);
        break;

    case DEVESC_ACQUIREFB:
        //-------------------------------------------------------------
        // We must change this check for an empty FIFO because the
        // 801/805 chips don't have this bit.  Since it will never
        // go high, we wind up hanging the card.  CMVC 97750.
        //
        // We also move the check in front of the call to AcquireFB()
        // so that the check is made before we switch to linear
        // addressing mode.  Register 9AE8 does not return valid data
        // when we're in linear addressing mode.  CMVC 98646.
        //
        // Ooops!  We really need to do this check between the time
        // when we get the semaphore and when we switch to linear
        // addressing. This will be inside AcquireFB().  CMVC 99406.
        //-------------------------------------------------------------
        retval = AcquireFB(ArgInCount, (PVOID)ArgInData);
        break;

    case DEVESC_DEACQUIREFB:
        retval = DeacquireFB();
        break;

    case DEVESC_SWITCHBANK:
        retval = SwitchBank(ArgInCount, ArgInData);
        break;

    default:
        retval = DEVESC_NOTIMPLEMENTED;
        break;
    }

    return(retval);
}

/**********************************************************************/
/*                                                                    */
/*   QueryEscSupport returns a value indicating whether a particular  */
/* Escape Subfunction, referred to by InData, is supported or not by  */
/* the display driver.                                                */
/*                                                                    */
/*   OutCount and OutData are not set or used by QueryEscSupport.     */
/*                                                                    */
/**********************************************************************/
ULONG DRIVERCALL eddq_QueryEscSupport (PULONG ArgInData)
{
    /******************************************************************/
    /* The desired escape function is indicated by ArgInData.         */
    /******************************************************************/
    switch (*ArgInData)
    {

    case DEVESC_QUERYESCSUPPORT:
    case DEVESC_QUERYVIOCELLSIZES:
    case DEVESC_GETAPERTURE:
    case DEVESC_ACQUIREFB:
    case DEVESC_DEACQUIREFB:
    case DEVESC_SWITCHBANK:
        return(DEV_OK);

    default:
        return(DEVESC_NOTIMPLEMENTED);
    }
}

#endif
