/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* 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 = svgamain.c
 *
 * DESCRIPTIVE NAME = Super VGA specific routines.
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION Base video device handler  - Initialization,
 *                                                  Save, Restore.
 *
 *             This source is compiled to produce a video
 *             device handler for Super VGA.
 *             The video device handler consists of hardware
 *             dependent functions, which are invoked directly
 *             by the OS/2 base video subsystem.
 *
 *             Vital assumption: that there exists a base VGA
 *             sub-system handler, this module provides support
 *             for a superset of VGA and therefore relies on its
 *             existence.
 *
 * FUNCTIONS   DevEnable
 *             InitEnv, SaveEnv, RestoreEnv
 *             RetConfigInfo
 *             GetMode, SetMode
 *
 * DEPENDENCIES:  vdhvga
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

/*
**      Include files
*/

#define  INCL_BASE                     /* ALL of OS/2 Base                  */
#define  INCL_DOSDEVICES               /* Device specific, ring 2 support   */
#define  INCL_DOSINFOSEG
#include <os2.h>
#include "svgatype.h"                  /* Type definitions                  */


/*
**      Data Externals
*/

extern BOOL InitDone,PMILoaded;
extern USHORT HugeShift;
extern SEL GlobalInfoSeg;
extern ENTRYPOINT FAR *ChainedEntryPoint[];
extern ENTRYPOINT FAR *SVGAEntryPoint[];
extern ENTRYPOINT DebugRouter;
extern OEMSVGAINFO SVGAHardware;
extern PVIDEOMODE pModes;              /*            */
extern PMEMORYMAPS pMemoryMaps;        /*            */

#if      DEBUG
extern DEBUGDATA DebugFn[];
#endif
int NEAR ProcessPMIFile(char *);
USHORT FAR HardwareColor(VOID);
VOID EXPENTRY AccessRegister(PREGADDRESS,USHORT,PBYTE);
USHORT PASCAL NEAR SaveRestorePVB(PVDHSAVEREST,USHORT,PENVIRONMENT);
VOID EXPENTRY AccessVideoEnable(USHORT,USHORT,USHORT FAR *);
VOID PASCAL NEAR SaveRestoreHW(PENVIRONMENT,USHORT);
USHORT PASCAL NEAR GetAdapterConfig(VOID);
USHORT PASCAL NEAR SetAdapterMemory(VOID);      /*            */
USHORT NEAR SetSVGAMode(PENVIRONMENT,PVDH_MODE);
USHORT NEAR GetSVGAMode(PENVIRONMENT,PVDH_MODE);
VOID NEAR FixSVGARegisters(PENVIRONMENT);
VOID PASCAL NEAR SetModeFont(USHORT,PENVIRONMENT,BOOL,PUSHORT); /*            */
VOID NEAR SetupTridentRegisters(VOID);
USHORT APIENTRY FAR SetMode(PENVIRONMENT,PVDH_MODE,ULONG); /*            */

/*****************************************************************************
 *
 * FUNCTION NAME = DevEnable()
 *
 *  DESCRIPTIVE NAME: Initialize one call vector table
 *
 *  FUNCTION: DevEnable is called via the Presentation Manager DDI
 *            interface.  The entry points of all VDH routines are
 *            appropriately entered into the call vector table.
 *            In addition, display adapter configuration is verified.
 *
 *  ENTRY POINT: DevEnable
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR * Parameter2  ( far pointer to parameter 2 packet )
 *                      FAR *Flags
 *                      FAR *CallVectorTable
 *             FAR * Parameter1  ( far pointer to parameter 1 packet )
 *                      ULONG EngineVersion ( Graphics engine ver. )
 *                      ULONG TableSize ( Length of call table )
 *             ULONG Subfunction ( Enable subfunction )
 *             FAR *CallVectorTable[] ( BVS's table of entry points )
 *         (Referenced)
 *             VDHEntryPoint[] (global data - table of entry points )
 *
 *  EXIT-NORMAL: AX = 0
 *               Entries in SVGAEntryPoint table are copied to
 *                  CallVectorTable
 *
 *  EXIT-ERROR: AX = 0xFFFF if invalid subfunction
 *
 *  EFFECTS: Huge shift value is saved in HugeShift
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: None
 *    DATA:
 *
 *  Get huge shift value for later use during
 *    save/rest of display buffer
 *  Get adapter configuration info for later use
 *    in initialising 'environment' variables.
 *
 ****************************************************************************/

USHORT APIENTRY DevEnable(char FAR *Parm2,char FAR *Parm1,ULONG Subfunction)
{
  ENTRYPOINTTABLE DefaultTable;
  ULONG TableSize,i,j;
  USHORT rc = 0xFFFF;
  SEL    lis;

  if ((Subfunction == FnFillInitDevBlock) || (Subfunction == FnFillLogicalDevBlock))
  {
    rc = 0;

    if (!InitDone && !rc)
    {
      InitDone = TRUE;

      if (!(rc = DosGetHugeShift(&HugeShift) ||
           (rc = DosGetInfoSeg(&GlobalInfoSeg, &lis))))
      {
        HugeShift = 1 << HugeShift;

        if (!(rc = GetAdapterConfig()))
        {
          if (PMILoaded = !ProcessPMIFile(SVGA_DATAFNAME))
            SetAdapterMemory();                       /*            */

          TableSize = ((PDEVPARM1)Parm1)->TableSize;
          DefaultTable = ((PDEVPARM2)Parm2)->CallVectorTable;

          for (i = FnTextBufferUpdate, j = FnChainedBufUpdate; (i <=
             FnGetLVBInfo) && (i < TableSize); i++, j++)
          {                                           /* Save old entry */
            ChainedEntryPoint[j] = DefaultTable[i];

           #if DEBUG
            DefaultTable[i] = &DebugRouter;

           #else                                      /* Override table entry */
            DefaultTable[i] = SVGAEntryPoint[j];
           #endif
          }
        }
      }
    }
  }
  return (rc);
}

/***************************************************************************
 *
 * FUNCTION NAME = InitEnv()
 *
 *  DESCRIPTIVE NAME: Initialize environment
 *
 *  FUNCTION: InitEnv is called by BVS to initialize the video
 *            environment during the creation of a new session.  This
 *            includes initializing the adapter hardware and/or the
 *            environment buffer.
 *
 *  ENTRY POINT: InitEnv
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 257 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 0 - Environment buffer only
 *                                     1 - Hardware also
 *             ULONG Function ( Call vector table entry = 257 )
 *         (Referenced)
 *             Modes[] (global data - table of supported video modes )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR: AX = 0xFFFF
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: None
 *
 *  PSEUDO-CODE
 *    call existing InitEnv (VDHVGA) to do VGA stuff
 *    initialise SVGA specific environment vars.
 *    attempt to set the initial mode (80x25 text)
 *    if mode set fails, chain to VGA to do it
 *
 ****************************************************************************/

USHORT APIENTRY FAR InitEnv(PENVIRONMENT Environment,PVDHSAVEREST ParmBlock,
                             ULONG Function)
{
  USHORT rc = 0xFFFF;
  VDH_MODE ModeParmBlock;
  VDHSAVEREST TmpParmBlock;
  VDHMODEINFO ModeInfo = { 22,1,4,80,25,720,400 };

  if (Function == FnInitializeEnvironment)
  {

    TmpParmBlock = *ParmBlock;
    TmpParmBlock.Flags &= ~ENVFLAG_HARDWARE;
    ChainedInitEnv((PENVIRONMENT)(&Environment->VGAEnvironment),
                                  &TmpParmBlock , Function);

  /*  ** Removing the DosError calls. If an application is registering
  ** their own handler, we would have enabled the exception handling on the
  ** first pop-up in that session, which is forcing the default action. We would
  ** need to query the state of DosError enable/disable in order to restore it.
  ** Until such an API becomes available, keep the state in tact. Nobody on
  ** the team can remember what was the reason for putting the DosError in.
  ** According to Dave Medina, while an exception for one process is being handled,
  ** all other exceptions are delayed.
  */
    Environment->pCmdData = NULL;
    Environment->pSetBankData = NULL;                           /*            */
    Environment->EnvFlags = ENVFLAG_DEFAULT;
    Environment->ModeIndex   = 0;
    Environment->VideoEnable = 1;
    Environment->ChipVersion = SVGAHardware.ChipType;
    Environment->AdapterType = SVGAHardware.AdapterType;
    Environment->ModeDataOffset = FIELDOFFSET(ENVIRONMENT, ModeDataOffset);
    ModeParmBlock.Length = sizeof(VDH_MODE);
    ModeParmBlock.Flags = (ParmBlock->Flags&ENVFLAG_HARDWARE)?ENVFLAG_HARDWARE :0;
    ModeParmBlock.pVDHModeInfo = &ModeInfo;

    rc = SetMode(Environment, &ModeParmBlock, FnSetMode);


    if (rc)
    {

      TmpParmBlock.Flags = ParmBlock->Flags;
      rc = ChainedInitEnv((PENVIRONMENT)(&Environment->VGAEnvironment),
         &TmpParmBlock, Function);

    }
  }

  return (rc);

}

/*****************************************************************************
 *
 *  FUNCTION NAME:    SaveEnv()
 *
 *  DESCRIPTIVE NAME: Save environment
 *
 *  FUNCTION: SaveEnv is called by BVS prior to a screen switch
 *            in order to preserve the display adapter hardware state
 *            and/or the full or partial display buffer.
 *
 *  ENTRY POINT: SaveEnv
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 258 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 0x02 - Hardware state
 *                                     0x04 - Full display buffer
 *                                     0x08 - Partial display buffer
 *                     USHORT PVBHugeSEL = 1st huge selector for PVB
 *             ULONG Function ( Call vector table entry = 258 )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR:  AX = 0xFFFF
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  PSEUDO-CODE
 *
 ****************************************************************************/

USHORT APIENTRY FAR SaveEnv(PENVIRONMENT Environment,PVDHSAVEREST VDHSaveRest,
                             ULONG Function)
{
  USHORT rc,EnvBufferPassed;
  USHORT ColorMode;

  if (!(Environment->EnvFlags & ENVFLAG_SVGAMODE))
    return (ChainedSaveEnv((PENVIRONMENT)&Environment->VGAEnvironment,
       VDHSaveRest, Function));

  rc = ERROR_VIO_INVALID_PARMS;

  EnvBufferPassed = SEG(Environment);                   /* Non-zero = TRUE        */

  if ((Function == FnSaveEnvironment) &&                /* Valid function request */
     (VDHSaveRest->Length >= MINSLEN_SAVERESTOREENV) && /* Valid packet length    */
     VDHSaveRest->Flags &&                              /* An option specified    */
     !(VDHSaveRest->Flags&~VALID_SAVEREST_FLAG) &&      /* No illegal options     */
     !((VDHSaveRest->Flags&SAVEREST_FULLPVB) && (VDHSaveRest->Flags & SAVEREST_PARTPVB)) &&                            /* Not part and full                 */
     !((VDHSaveRest->Length < sizeof(VDHSAVEREST)) &&   /* PVB and no selector    */
     (VDHSaveRest->Flags&(SAVEREST_FULLPVB+SAVEREST_PARTPVB))) &&
     EnvBufferPassed)
  {
    rc = NO_ERROR;                     /* Initialize no error               */

    if (VDHSaveRest->Flags & SAVEREST_HARDWARE)
    {

      AccessVideoEnable(ColorMode, GET, &Environment->VideoEnable);

      SaveRestoreHW(Environment, GET);

      if (VDHSaveRest->Flags & (SAVEREST_FULLPVB|SAVEREST_PARTPVB))
        rc = SaveRestorePVB(VDHSaveRest, SAVE, Environment);

      if (SVGAHardware.AdapterType)
        FixSVGARegisters(Environment);              /*            */
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  FUNCTION NAME:    RestoreEnv()
 *
 *  DESCRIPTIVE NAME: Restore environment
 *
 *  FUNCTION: RestoreEnv is called by BVS following a screen switch
 *            in order to restore the display adapter hardware state
 *            and/or the full or partial display buffer.
 *
 *  ENTRY POINT: RestoreEnv
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 259 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 2 - Hardware state
 *                                     4 - Full display buffer
 *                                     8 - Partial display buffer
 *                     USHORT PVBHugeSEL = 1st huge selector for PVB
 *             ULONG Function ( Call vector table entry = 259 )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR: AX = 0xFFFF
 *
 *  EFFECTS:
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: None
 *
 *  PSEUDO-CODE
 *    Turn off the Video Signal
 *    Output environment buffer to registers
 *    Restore partial or full display buffer
 *    Turn the Video Signal ON if it was on previously
 *    If current cols = 132 then ensure proper register
 *        setup for 132 cols on a restore.
 *
 ****************************************************************************/

USHORT APIENTRY FAR RestoreEnv(PENVIRONMENT Environment,PVDHSAVEREST
                                VDHSaveRest,ULONG Function)
{
  USHORT rc;
  USHORT VideoState,VideoOn,ColorMode,EnvBufferSeg;
  VDH_CURSOR CursorInfo;               /*            */


  if (!(Environment->EnvFlags&ENVFLAG_SVGAMODE))
  {

    if ((VDHSaveRest->Flags&SAVEREST_HARDWARE) && (SVGAHardware.AdapterType ==
       TRIDENT_ADAPTER))
      SetupTridentRegisters();

    if ((VDHSaveRest->Flags&SAVEREST_HARDWARE) && SVGAHardware.AdapterType)
      FixSVGARegisters(Environment);
    rc = ChainedRestoreEnv((PENVIRONMENT)&Environment->VGAEnvironment,
       VDHSaveRest, Function);
  }

  else
  {
    rc = ERROR_VIO_INVALID_PARMS;
    EnvBufferSeg = SEG(Environment);   /* Non-zero = TRUE                   */

    if ((Function == FnRestoreEnvironment) &&             /* Valid function request */
       (VDHSaveRest->Length >= MINSLEN_SAVERESTOREENV) && /* Valid packet length    */
       VDHSaveRest->Flags &&                              /* An option specified    */
       !(VDHSaveRest->Flags&~VALID_SAVEREST_FLAG) &&      /* No illegal options     */
       !((VDHSaveRest->Flags&SAVEREST_FULLPVB) && (VDHSaveRest->Flags
       &SAVEREST_PARTPVB)) &&                             /* Not part and full      */
       !((VDHSaveRest->Length < sizeof(VDHSAVEREST)) &&   /* PVB and no selector    */
       (VDHSaveRest->Flags&(SAVEREST_FULLPVB+SAVEREST_PARTPVB))) &&
       EnvBufferSeg &&
       Environment->pCmdData)                             /*            */
    {
      rc = NO_ERROR;                   /* Initialize no error               */
      VideoState = Environment->VideoEnable;
      Environment->VideoEnable = 0;
      ColorMode = HardwareColor();     /* color/mono mode                   */
      VideoOn = 0;
      AccessVideoEnable(ColorMode, SET, &VideoOn);

      if (VDHSaveRest->Flags & SAVEREST_HARDWARE)
        SaveRestoreHW(Environment, SET);

      if (VDHSaveRest->Flags & (SAVEREST_FULLPVB|SAVEREST_PARTPVB))
        rc = SaveRestorePVB(VDHSaveRest, RESTORE, Environment);

      if (pModes &&
         !(pModes[Environment->ModeIndex].fbType & MODE_FLAG_GRAPHICS))
      {
        if (VDHSaveRest->Flags & (SAVEREST_FULLPVB|SAVEREST_PARTPVB))   /*           */
          SetModeFont(Environment->ModeIndex, Environment, TRUE, NULL); /*           */

        /* get cursor type and position from env, not h/ware */
        CursorInfo.Length = MINSLEN_CURSOR_TYPE;                  /*           */
        CursorInfo.Flags = 6;

        if (!(rc = ChainedGetCursorInfo((PENVIRONMENT)
           (&Environment->VGAEnvironment), &CursorInfo, FnGetCursorInfo)))
        {

          CursorInfo.Flags |= 1;
          rc = ChainedSetCursorInfo((PENVIRONMENT)
             (&Environment->VGAEnvironment), &CursorInfo, FnSetCursorInfo);
        }

      }                                

      if (VideoState)
      {
        AccessVideoEnable(ColorMode, SET, &VideoState);
        Environment->VideoEnable = 1;
      }
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  FUNCTION NAME:    RetConfigInfo()
 *
 *
 *  DESCRIPTIVE NAME: Return Adapter/Display Configuration Info
 *
 *  FUNCTION:
 *
 *  ENTRY POINT:
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry  )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 2 - Hardware state
 *                                     4 - Full display buffer
 *                                     8 - Partial display buffer
 *                     FAR * VIOGETCONFIG structure
 *             ULONG Function ( Call vector table entry =  )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR: AX = 0xFFFF
 *
 *  EFFECTS:
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  PSEUDO-CODE
 *
 *    chain to existing VDHVGA
 *    if successful (ie. its there), and adapter type is SVGA
 *        modify h/ware state buffer size for local info
 *        modify max buffer size for full/partial saves
 *
 ****************************************************************************/

USHORT APIENTRY FAR RetConfigInfo(PENVIRONMENT Environment,PVDHCONFIG
                                   ParmBlock,ULONG Function)
{
  USHORT rc = 0xFFFF,SetLength;
  PVDHCONFIGINFO pReqConfig;


  if (Function == FnReturnConfigInfo)
  {
    pReqConfig = ParmBlock->ConfigDataPTR;
    SetLength = (pReqConfig->cb == 2);
    rc = ChainedRetConfigInfo(Environment, ParmBlock, Function);

    if (!rc && !SetLength && SVGAHardware.AdapterType)
    {

      if (pReqConfig->cb > (FIELDOFFSET(VDHCONFIGINFO, adapter)))
        pReqConfig->adapter = DISPLAY_SVGA;

      if (pReqConfig->cb > (FIELDOFFSET(VDHCONFIGINFO, display)))
        pReqConfig->display = MONITOR_OEM;

      if (pReqConfig->cb > (FIELDOFFSET(VDHCONFIGINFO, cbMemory)))
        pReqConfig->cbMemory = SVGAHardware.Memory;         /*            */

      if (pReqConfig->cb > (FIELDOFFSET(VDHCONFIGINFO, HWBufferSize)))
      {
        pReqConfig->HWBufferSize += sizeof(ENVIRONMENT);

        if (pReqConfig->cb > (FIELDOFFSET(VDHCONFIGINFO, FullSaveSize)))
        {
            pReqConfig->FullSaveSize = SVGAHardware.Memory; /*            */

          if (pReqConfig->cb > (FIELDOFFSET(VDHCONFIGINFO, PartSaveSize)))
          {
            pReqConfig->PartSaveSize = SVGA_PARTSAVESIZE;
          }
        }
      }
    }
  }
  return (rc);
}


/*****************************************************************************
 *
 *  FUNCTION NAME:    GetMode()
 *
 *  DESCRIPTIVE NAME: Return current video mode info
 *
 *  FUNCTION:
 *
 *  ENTRY POINT:
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry  )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 2 - Hardware state
 *                                     4 - Full display buffer
 *                                     8 - Partial display buffer
 *                     USHORT PVBHugeSEL = 1st huge selector for PVB
 *             ULONG Function ( Call vector table entry =  )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR: AX = 0xFFFF
 *
 *  EFFECTS:
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

USHORT APIENTRY FAR GetMode(PENVIRONMENT Environment,PVDH_MODE ParmBlock,ULONG
                             Function)
{
  USHORT rc = 0xFFFF;                  /* Preset error                      */


  if (Function == FnGetMode)
  {

    if (Environment->EnvFlags&ENVFLAG_SVGAMODE)
      rc = GetSVGAMode(Environment, ParmBlock);

    else
      rc = ChainedGetMode((PENVIRONMENT)(&Environment->VGAEnvironment),
         ParmBlock, Function);

    if (!rc && (ParmBlock->Length >= sizeof(VDH_MODE)) &&
        (ParmBlock->Flags <= 1) &&
        (ParmBlock->pVDHModeInfo->cb >= FIELDOFFSET(VDHMODEINFO,ExtDataArea)))
    {
      ParmBlock->pVDHModeInfo->FullBufferSize = SVGAHardware.Memory;
      ParmBlock->pVDHModeInfo->PartialBufferSize = SVGA_PARTSAVESIZE;
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  FUNCTION NAME:    SetMode()
 *
 *
 *  DESCRIPTIVE NAME: Set video mode
 *
 *  FUNCTION:
 *
 *  ENTRY POINT:
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry  )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 2 - Hardware state
 *                                     4 - Full display buffer
 *                                     8 - Partial display buffer
 *                     USHORT PVBHugeSEL = 1st huge selector for PVB
 *             ULONG Function ( Call vector table entry =  )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR: AX = 0xFFFF
 *
 *  EFFECTS:
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

USHORT APIENTRY FAR SetMode(PENVIRONMENT Environment,PVDH_MODE ParmBlock,ULONG
                             Function)
{
  USHORT rc = ERROR_VIO_MODE, usSaveFlags;              /*            */


  if (Function == FnSetMode)
  {
    usSaveFlags = Environment->EnvFlags;                /*            */
    if (rc = SetSVGAMode(Environment, ParmBlock))
    {

      if (!((ParmBlock->pVDHModeInfo->cb >= FIELDOFFSET(VDHMODEINFO, row)) &&
         (ParmBlock->pVDHModeInfo->col == 132)))
      {

        if ((ParmBlock->Flags&ENVFLAG_HARDWARE) && (SVGAHardware.AdapterType
           == TRIDENT_ADAPTER))
          SetupTridentRegisters();

        if ((ParmBlock->Flags & ENVFLAG_HARDWARE) &&             /*            */
             SVGAHardware.AdapterType)                           /*            */
            FixSVGARegisters(Environment);                       /*            */

        Environment->EnvFlags &= ~ENVFLAG_SVGAMODE;
        rc = ChainedSetMode((PENVIRONMENT)(&Environment->VGAEnvironment),
           ParmBlock, Function);
        /*      
        ** If chained mode failed, restore the environment flags, so
        ** that subsequent GetMode returns the correct information.
        */
        if (rc)                                                 /*            */
          Environment->EnvFlags = usSaveFlags;
      }

    }

    else
      Environment->EnvFlags |= ENVFLAG_SVGAMODE;
  }
  return (rc);
}


/*****************************************************************************
 *
 *  FUNCTION NAME:    TerminateEnv()
 *
 *
 *  DESCRIPTIVE NAME: Terminate Environment - session is being destroyed
 *
 *  FUNCTION:
 *
 *  ENTRY POINT:
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry  )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet (6)
 *                     USHORT Flags  = reserved
 *                     USHORT PVBHugeSEL = huge selector for PVB
 *             ULONG Function ( Call vector table entry =  )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR: AX = 0xFFFF
 *
 *  EFFECTS:
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

USHORT APIENTRY FAR TerminateEnv(PENVIRONMENT Environment,
                                 VOID FAR * ParmBlock,
                                 ULONG Function)
{
  USHORT rc = 0xFFFF;                  /* Preset error                      */

  if (Function == FnExtendedVioCall)
  {

    if ( Environment->pCmdData && !SVGAFreeMem(&Environment->pCmdData) )
      rc = 0;

  }

  return rc;
}


/*****************************************************************************
 *
 *  FUNCTION NAME:    ChainRouter()
 *
 *
 *  DESCRIPTIVE NAME: Call default entry in call vector table
 *
 *  FUNCTION: During VDH chaining, the environment buffer of the
 *            previous call table entry is tacked on to the end of the
 *            current VDH environment buffer.  If a particular VDH
 *            service is not supported, the VDH has to call the
 *            previous entry with its environment.
 *
 *  ENTRY POINT: UnsupportedService
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *             ULONG Function ( Call vector table entry )
 *
 *  EXIT:      AX = return code from call table vector routine
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 ****************************************************************************/

USHORT APIENTRY FAR ChainRouter(PENVIRONMENT Environment,char FAR *ParmBlock,
                                 ULONG Function)
{
  return ((*ChainedEntryPoint[Function-FnTextBufferUpdate])((PENVIRONMENT)
     (&Environment->VGAEnvironment), ParmBlock, Function));
}

#if      DEBUG
/***************************************************************************
 *
 * FUNCTION NAME = DebugRouter()
 *
 * DESCRIPTION   =
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

#include   <string.h>
#pragma  intrinsic(strcpy)
USHORT APIENTRY FAR DebugRouter(PENVIRONMENT Environment,char FAR *ParmBlock,
                                 ULONG Function)
{
  char s[80];


  if (DebugFn[Function-FnTextBufferUpdate].inuse)
  {
    strcpy(s, "SVGA: ");
    strcpy(s+6, DebugFn[Function-FnTextBufferUpdate].name);
    DPRINTF(s);
  }
  return ((*SVGAEntryPoint[Function-FnTextBufferUpdate])(Environment,
     ParmBlock, Function));
}

#endif                                 /* DEBUG */
