/*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 = bvhmain.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 depends on VIDEOPMI to
 *             perform hardware specific functions, such as
 *             mode set, font set, CLUT set and save/restore state.
 *             Cursor function assumes that hardware is VGA compatible.
 *
 *             Vital assumption: for all hardware-bound functions
 *             the environment buffer must be passed, so that
 *             VIDEOPMI relevant data can be setup.
 *
 * FUNCTIONS   DevEnable
 *             InitEnv, SaveEnv, RestoreEnv
 *             GetMode, SetMode
 *             GetFont, SetFont
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

/*
**      Include files
*/

#define  INCL_DOSDEVICES               /* Device specific, ring 2 support   */
#define  INCL_DOSINFOSEG
#include "bvhtype.h"                  /* Type definitions                  */
#include <memory.h>
#pragma  intrinsic(memcpy,memcmp,memset)


/*****************************************************************************
 *
 * 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 BVHEntryPoint 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 (!fNoVideopmi)/*             call vector table will not be updated  */
    if (!InitDone) /* until videopmi is loaded.                          */
    {
      InitDone = TRUE;
      if (!(rc = DosGetHugeShift (&HugeShift) ||
           (rc = DosGetInfoSeg (&GlobalInfoSeg, &lis))))
      {
        HugeShift = 1 << HugeShift;

        TableSize = ((PDEVPARM1)Parm1)->TableSize;
        DefaultTable = ((PDEVPARM2)Parm2)->CallVectorTable;
        for (i = FnTextBufferUpdate, j = FnChainedBufUpdate; (i <=
           FnGetLVBInfo) && (i < TableSize); i++, j++)
        {                                           /* Save old entry */
         #if DEBUG
          DefaultTable[i] = &DebugRouter;

         #else                                      /* Override table entry */

         #ifdef CHAIN_VGA  /* @TSU00 */
          /*
           * save the old call vector table for future chaining.
           */
          ChainedEntryPoint [j] = DefaultTable [i];
         #endif

          if (BVHEntryPoint[j] != UNSUPPORTED_FUNCTION)
            DefaultTable[i] = BVHEntryPoint[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;
  VDHMODEINFO ModeInfo = {12,                       /* cb */
                          MODE_FLAG_NOT_MONO,       /* flag */
                          4,                        /* no. of colors */
                          80,                       /* col */
                          25,                       /* row */
                          720,                      /* hres */
                          400};                     /* vres */

  if (Function == FnInitializeEnvironment)
  {

#ifdef CHAIN_VGA /* @TSU00 */
    /*
     * chain to VGA to initialize the VGA environment
     * but disable the setmode (80 x 25) by disabling the ENVFLAG_HARDWARE
     */
  VDHSAVEREST TmpParmBlock;

    TmpParmBlock = *ParmBlock;
    TmpParmBlock.Flags &= ~ENVFLAG_HARDWARE;

    //          
    // Though the environment is newly allocated, the contents
    // is NOT BLANK. It is copied from the parent process, which is sysinit.
    // VGA_ENV() is going to give a       offset since videopmi is in while
    // for sysinit, videopmi is not in yet.

    Environment->EnvFlags = ENVFLAG_DEFAULT;            //          

    if (fPMINotTried)                                   //          
         Environment->EnvFlags |= ENVFLAG_BEFOREPMI;    //          
    else
         Environment->EnvFlags &= ~ENVFLAG_BEFOREPMI;   //          

    ChainedInitEnv (VGA_ENV(Environment),
                    &TmpParmBlock,
                    Function);
#endif

    Environment->ModeDataOFF = (USHORT) ((ULONG)  &Environment->ModeData  -
                                         (ULONG)  &Environment->ModeDataOFF);
//    Environment->EnvFlags = ENVFLAG_DEFAULT;            //          
//    if (fPMINotTried)                                   //          
//         Environment->EnvFlags |= ENVFLAG_BEFOREPMI;    //          
    Environment->ModeIndex   = MODE_NONE;
    Environment->VideoEnable = 1;
    Environment->pFontData    = NULL;
    SetupEnvCodePage(Environment);
    Environment->UserFont     = USER_FONT_NOT_SELECTABLE;
    Environment->NumUSERFonts = 0;
    Environment->USERFontSel  = 0;
    Environment->ScrollRect.Left = 0;
    Environment->ScrollRect.Top = 0;
    Environment->AttrBufSize = 1;
    Environment->AttrBuf[0] = DefaultAttribute[0];
    Environment->AttrBuf[1] = DefaultAttribute[1];
    Environment->AttrBuf[2] = DefaultAttribute[2];

    Environment->ModeData = (VGA_ENV(Environment))->ModeData; //          

    /*
    ** Initialize the index into display configuration data as NONE.
    ** CFG_INDEX_SET bitflag used to activate the real index when found.
    **           
    */
    Environment->CurrentCFGIndex = 0;
    ModeParmBlock.Length = sizeof(VDH_MODE);
    ModeParmBlock.Flags = (ParmBlock->Flags&UPDATE_HARDWARE)?UPDATE_HARDWARE :0;
    ModeParmBlock.pVDHModeInfo = &ModeInfo;
    rc = SetMode(Environment, &ModeParmBlock, FnSetMode);
#ifdef CHAIN_VGA /* @TSU00 */
    /*
     * If unable to set the mode, call bvhvga to set it.
     */
    if (rc)
    {
       TmpParmBlock.Flags = ParmBlock->Flags;
       rc = ChainedInitEnv (VGA_ENV(Environment),
                            &TmpParmBlock,
                            Function);

       Environment->EnvFlags |= ENVFLAG_VGAMODE;    //          
    }
#endif
  }

  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;
  VDH_VARIABLE TmpVar;
  rc = ERROR_VIO_INVALID_PARMS;

#ifdef CHAIN_VGA   /* @TSU00 */
/*
 * If the mode is set by bvhvga, call bvhvga to save the environment
 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)     //          
    return (ChainedSaveEnv ( VGA_ENV(Environment),
                             VDHSaveRest,
                             Function));
#endif

  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     */
                                                        /* Not part and full                 */
     !((VDHSaveRest->Flags&SAVEREST_FULLPVB) && (VDHSaveRest->Flags & SAVEREST_PARTPVB)) &&
     !((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) ||
        (VDHSaveRest->Flags &                                 //          
                       (SAVEREST_FULLPVB | SAVEREST_PARTPVB)))//          
    {
      if (!(Environment->ModeData.fbType & MODE_FLAG_GRAPHICS))
      {
        /*
        ** Make sure current environment character attributes
        ** correspond to the hardware state, as they have to be restored
        ** after the hardware state is restored, in case any were changed
        ** while in the background.
        */
        TmpVar.Length = MINSLEN_VAR_VIDEOENABLE;
        TmpVar.Flags =  VARIABLE_BLINK | VARIABLE_OVERSCAN | VARIABLE_VIDEOENABLE |
                        VARIABLE_UNDERSCORE | UPDATE_HARDWARE;
        rc = GetVariableInfo(Environment, &TmpVar,FnGetVariableInfo);
      }
      BVHSaveRestoreState(SAVE,Environment, VDHSaveRest);
      FixBVHRegisters(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, j;
  USHORT VideoOn,EnvBufferSeg;
  VDH_CURSOR CursorInfo;
  VDH_VARIABLE TmpVar;
  VDH_PALETTE TmpPal;
  USHORT Palette[PALETTE_REGS];

#ifdef CHAIN_VGA       /* @TSU00  */
/*
 * mode is set by bvhvga. Call bvhvga to restore environment
 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))  //          
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)       //          
  {

    /*
     * call clean up to clean up th extended registers
     */
    if ((VDHSaveRest->Flags & SAVEREST_HARDWARE) && !fNoVideopmi)
      FixBVHRegisters(Environment);

    return ( ChainedRestoreEnv ( VGA_ENV(Environment),
                                 VDHSaveRest,
                                 Function));
  }

#endif

  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)
  {
    rc = NO_ERROR;                   /* Initialize no error               */
    VideoOn = 0;
    AccessVideoEnable(HardwareColor(), SET, &VideoOn);
    /*
    ** Restore CLUT, hardware state, font and PVB.
    */
    BVHSaveRestoreState(RESTORE,Environment,VDHSaveRest);
    if (!(Environment->ModeData.fbType & MODE_FLAG_GRAPHICS))
    {
      /*
      ** Restore character attribute state in case any were changed
      ** while in the background.
      */
      TmpVar.Length = MINSLEN_VAR_VIDEOENABLE;
      TmpVar.Flags =  VARIABLE_BLINK | VARIABLE_OVERSCAN | VARIABLE_VIDEOENABLE |
                      VARIABLE_UNDERSCORE;
      rc = GetVariableInfo(Environment, &TmpVar,FnGetVariableInfo);
      TmpVar.Flags |= UPDATE_HARDWARE;
      rc = SetVariableInfo(Environment, &TmpVar,FnSetVariableInfo);
      CursorInfo.Length = MINSLEN_CURSOR_TYPE;
      CursorInfo.Flags = CURSOR_TYPE+CURSOR_POSITION;
      GetCursorInfo(Environment,&CursorInfo, FnGetCursorInfo);
      CursorInfo.Flags |= UPDATE_HARDWARE;
      SetCursorInfo(Environment,&CursorInfo, FnSetCursorInfo);
    }
    /*
    ** Restore palette registers from the environment, in case any were
    ** changed while in the background.
    */
    if (Environment->EnvFlags & ENVFLAG_BKGNDPALETTE)
    {
      TmpPal.Length = sizeof(VDH_PALETTE);
      TmpPal.Flags = UPDATE_HARDWARE;
      TmpPal.PaletteBuffer.FirstEntry = 0;
      TmpPal.PaletteBuffer.NumEntries = PALETTE_REGS;
      for (j = 0; j < PALETTE_REGS;j++)
        Palette[j] = (USHORT) Environment->bPaletteData[j];
      TmpPal.PaletteBuffer.DataArea = (USHORT FAR *) &Palette;
      rc = SetPaletteReg(Environment, &TmpPal,FnSetPaletteRegisters);
      Environment->EnvFlags &= ~ENVFLAG_BKGNDPALETTE;
    }
  }
  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 = ERROR_VIO_INVALID_PARMS;

  /*
  ** BVHPMI can not get the mode unless it has the environment.
  ** It doesn't have direct access to the hardware.
  */
  if (Function == FnGetMode && SEG(Environment) &&
     (ParmBlock->Length >= sizeof(VDH_MODE)) &&
     (ParmBlock->Flags <= 1))
  {

#ifdef CHAIN_VGA  /* @TSU00 */
//  if (Environment->EnvFlags & ENVFLAG_PMIMODE)     //          
    if (!(Environment->EnvFlags & ENVFLAG_VGAMODE))  //          
#endif

    rc = GetBVHMode(Environment, ParmBlock->pVDHModeInfo,ParmBlock->Flags);

#ifdef CHAIN_VGA  /* @TSU00 */
    else
    {
    rc = ChainedGetMode ( VGA_ENV(Environment),
                          ParmBlock,
                          Function);
/*
    if (ParmBlock->pVDHModeInfo->cb >= FIELDOFFSET(VDHMODEINFO,ExtDataArea))
    {
       ParmBlock->pVDHModeInfo->FullBufferSize = ulTotalMemory;
       ParmBlock->pVDHModeInfo->PartialBufferSize = SVGA_PARTSAVESIZE;
    }
*/
    }
#endif
  }
  return (rc);
}

/*****************************************************************************
 *
 *  FUNCTION NAME:    SetMode()
 *
 *
 *  DESCRIPTIVE NAME: Set video mode
 *
 *  FUNCTION:
 *           verify the validity of parameters and call SetBVHMode()
 *
 *  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_INVALID_PARMS;

  if ((Function == FnSetMode) &&          /* Valid function request       */
     (ParmBlock->Flags <= 0x07) &&        /* Valid flags                  */
     SEG(Environment) && (ParmBlock->Length >= sizeof(VDH_MODE)))

#ifdef CHAIN_VGA  /* @TSU00 */
  {
     USHORT usSaveFlags;

     usSaveFlags = Environment->EnvFlags;                /*            */
     /*
      * set the mode through videopmi. If it cannot be set, call bvhvga.
      */
     if (rc = SetBVHMode (Environment,
                          ParmBlock->pVDHModeInfo,
                          ParmBlock->Flags))
     {
        /*
         * only these modes can be set by bvhvga.
         */
        if (!((ParmBlock->pVDHModeInfo->cb >= FIELDOFFSET(VDHMODEINFO, row)) &&
              (ParmBlock->pVDHModeInfo->col == 132)))
        {
           /*
            * clean up extended registers.
            */
           if ((ParmBlock->Flags & ENVFLAG_HARDWARE) &&
                !fNoVideopmi)
               FixBVHRegisters(Environment);

           /*
            * indicate that this mode is not set by videopmi
            */
//           Environment->EnvFlags &= ~ENVFLAG_PMIMODE;            
           Environment->EnvFlags |= ENVFLAG_VGAMODE;     //          

           rc = ChainedSetMode ( VGA_ENV(Environment),
                                 ParmBlock,
                                 Function);
        }
        /*
         * Either chained mode failed or is not available.
         * Restore the environment flags, so
         * that subsequent GetMode returns the correct information.
         */
        if (rc)                                                 /*            */
          Environment->EnvFlags = usSaveFlags;

     }
     else
        /*
         * mode is set successfully by videopmi
         */
//        Environment->EnvFlags |= ENVFLAG_PMIMODE;              
        Environment->EnvFlags &= ~ENVFLAG_VGAMODE;   //          

  } /* if */

#else

    rc = SetBVHMode(Environment, ParmBlock->pVDHModeInfo, ParmBlock->Flags);

#endif
  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)
  {
#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))             
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)      //          
    return (ChainedExtVioCall ( VGA_ENV(Environment),
                                ParmBlock,
                                Function));
  else
#endif

    if (Environment->USERFontSel && DosFreeSeg(Environment->USERFontSel))
      rc = 0;
  }

  return rc;
}

#ifdef CHAIN_VGA /* @TSU00 */
/*****************************************************************************
 *
 *  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)
{
//   if (Environment->EnvFlags & ENVFLAG_PMIMODE)
//      return ((*ChainedEntryPoint[Function-FnTextBufferUpdate])
//                ( Environment, ParmBlock, Function));
//   else
//      return ((*ChainedEntryPoint[Function-FnTextBufferUpdate])
//                ( VGA_ENV(Environment), ParmBlock, Function));
//          
   if (Environment->EnvFlags & ENVFLAG_VGAMODE)
      return ((*ChainedEntryPoint[Function-FnTextBufferUpdate])
                ( VGA_ENV(Environment), ParmBlock, Function));
   else
      return ((*ChainedEntryPoint[Function-FnTextBufferUpdate])
                ( Environment, ParmBlock, Function));
}
#endif

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SetFont
 *
 *  DESCRIPTIVE NAME: Set font.
 *
 *  FUNCTION: SetFont is called by BVS to load the specified
 *            video text font
 *
 *  ENTRY POINT: SetFont
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 268 )
 *
 *  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
 *                     UCHAR far *FontBuffer
 *                     USHORT     FontLength
 *                     USHORT     PelColumns
 *                     USHORT     PelRows
 *             ULONG Function ( Call vector table entry = 268 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Current font is set
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: PhysToUVirt, FreePhysToUVirt
 *              AccessFont
 *
 ****************************************************************************/

USHORT EXPENTRY SetFont(PENVIRONMENT Environment,
                        PVDH_FONT    ParmBlock,
                        ULONG        Function)
{
  USHORT rc,i,EnvBufferPassed,USERFONT_NOT_FOUND, NewSize;
  PFONTDATA USERFont;
  USHORT VerticalRes;

  rc = ERROR_VIO_INVALID_PARMS;
  EnvBufferPassed = SEG(Environment);

#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
//  if (Environment->EnvFlags & ENVFLAG_VGAMODE)              
  if(EnvBufferPassed &&                           //          
     (Environment->EnvFlags & ENVFLAG_VGAMODE))   //          
    return (ChainedSetCurrentFont ( VGA_ENV(Environment),
                                    ParmBlock,
                                    Function));
#endif

  if ((Function == FnSetFont) &&       /* Valid function request            */
     (ParmBlock->Length >= sizeof(VDH_FONT)) && /* Valid Length             */
     (ParmBlock->PelRows >= 1) &&      /* Valid rows                        */
     (ParmBlock->PelRows <= MAX_FONT_SIZE) && /* Valid rows                 */
     (ParmBlock->PelColumns >= 1) &&   /* Valid cols                        */
     (ParmBlock->PelColumns <= 9) &&   /* Valid cols                        */
     (ParmBlock->Flags <= 1) &&        /* Valid flags                       */
     (EnvBufferPassed))
  {
    rc = ERROR_VIO_MODE;               /* Preset invalid mode               */

    if (!(Environment->ModeData.fbType&MODE_FLAG_GRAPHICS))
    {                                  /* Text mode only                    */
      rc = NO_ERROR;                   /* Parameters are OK                 */

      if (ParmBlock->FontLength < (ParmBlock->PelRows * 256))
        rc = ERROR_VIO_INVALID_PARMS;

      else if (Environment->USERFontSel)
      {
        /*
        **  If a USER font with the same dimensions already exists in
        **  the USER font table, replace it with the new font.
        **  Otherwise, add it to the bottom of the USER font table.
        */

        USERFont = MAKEP(Environment->USERFontSel,0);

        for (i = 0, USERFONT_NOT_FOUND = TRUE; USERFONT_NOT_FOUND &&
            (i < Environment->NumUSERFonts); i++)

          if (((USHORT) USERFont->ulFontHeight == ParmBlock->PelRows) &&
              ((USHORT) USERFont->ulFontWidth == ParmBlock->PelColumns))
            /*
            **  A USER font of the same size is already in the USER font table
            */

            USERFONT_NOT_FOUND = FALSE;
          else
            /*
            **  Point to the next entry in the USER font table
            */

            (ULONG)USERFont = (ULONG)(&USERFont->bFontData[0]) +
                              ((USHORT) USERFont->ulCharCount*
                               (USHORT) USERFont->ulFontHeight);

        if(USERFONT_NOT_FOUND)
        {
          /*
          **  Add the font to the end of the user table.
          **  The number of USER fonts that can be stored are limited to the
          **  amount that can fit in 1 64k segment. The current size fits the
          **  fonts already in the table. Reallocate to get more room.
          */
          rc = ERROR_VIO_FONT;
          NewSize = OFFSETOF(USERFont)+sizeof(FONTDATA)+ParmBlock->PelRows*256-1;
          if ( NewSize <= 0xFFFF)
          {
            if(!DosReallocSeg(NewSize,Environment->USERFontSel))
            {
              rc = NO_ERROR;
              USERFont->ulCharCount =  256;
              USERFont->ulFontHeight = (ULONG) ParmBlock->PelRows;
              USERFont->ulFontWidth =  (ULONG) ParmBlock->PelColumns;
              memcpy(&USERFont->bFontData[0],ParmBlock->FontBuffer,ParmBlock->PelRows*256);
              Environment->NumUSERFonts++;
              Environment->UserFont = USER_FONT_SELECTABLE;
            }
          }
        }
        else
        {
          /*
          **  Replace the font data
          */
          rc = NO_ERROR;
          memcpy(&USERFont->bFontData[0],ParmBlock->FontBuffer,ParmBlock->PelRows*256);
          Environment->UserFont = USER_FONT_SELECTABLE;
        }
      }
      else
      {
        rc = ERROR_VIO_FONT;
        /*
        ** Allocate a small segment first and copy the first user font data.
        */
        if(!DosAllocSeg(sizeof(FONTDATA)+ParmBlock->PelRows*256-1,
                                     (PSEL)&(Environment->USERFontSel),0))
        {
          rc = NO_ERROR;
          USERFont = MAKEP(Environment->USERFontSel,0);
          USERFont->ulCharCount =  256;
          USERFont->ulFontHeight = (ULONG) ParmBlock->PelRows;
          USERFont->ulFontWidth =  (ULONG) ParmBlock->PelColumns;
          memcpy(&USERFont->bFontData[0],ParmBlock->FontBuffer,ParmBlock->PelRows*256);
          Environment->NumUSERFonts++;
          Environment->UserFont = USER_FONT_SELECTABLE;
        }
      }
      if (!rc && (ParmBlock->Flags == UPDATE_HARDWARE))
      {
        rc  = ERROR_VIO_MODE;
        /*
        ** Try to fit the font in and load it. Old BVHVGA limitations of
        ** being an exact fit for the current mode are removed.
        ** The font has to fit horizontally, but not vertically.
        ** It may require double scanning.
        */
        VerticalRes = pModes[Environment->ModeIndex].vres;
        if (!(ParmBlock->PelColumns == (USHORT) Environment->pFontData->ulFontWidth) ||
            ((ParmBlock->PelRows * Environment->ModeData.row) > VerticalRes) ||
            ((ParmBlock->PelRows * Environment->ModeData.row) < VerticalRes<<1))
          return(rc);
        /*
        ** A double scanned mode can not be double scanned again.
        */
        if ((ParmBlock->PelRows * Environment->ModeData.row) == VerticalRes<<1)
          if(Environment->EnvFlags & ENVFLAG_DOUBLESCANMODE)
            return(rc);
          else
            Environment->EnvFlags |= ENVFLAG_DOUBLESCANMODE;
        Environment->ModeData.vres = VerticalRes;
        /*
        ** copy the font to the video buffer
        */
        if (ParmBlock->PelRows == (USHORT) Environment->pFontData->ulFontHeight)
        {
          Environment->pFontData = USERFont;
          if (!BVHAccessFont(SET,Environment->pFontData))
            rc = NO_ERROR;
        }
        else
        {
          Environment->pFontData = USERFont;
          rc = SetHWFont(Environment);
        }
      }
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: GetFont
 *
 *  DESCRIPTIVE NAME: Get font
 *
 *  FUNCTION: GetFont is called by BVS to return the current
 *            active video font.
 *
 *  ENTRY POINT: GetFont
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 267 )
 *
 *  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
 *                     UCHAR far *FontBuffer
 *                     USHORT     FontLength
 *                     USHORT     PelColumns
 *                     USHORT     PelRows
 *             ULONG Function ( Call vector table entry = 267 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Current font is returned to caller
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: PhysToUVirt, FreePhysToUVirt
 *              AccessFont
 *
 ****************************************************************************/

USHORT EXPENTRY GetFont(PENVIRONMENT Environment,
                        PVDH_FONT    ParmBlock,
                        ULONG        Function)
{
  USHORT rc,PelRows,FontSize,EnvBufferPassed;
  SEL Selector;
  PFONTDATA TmpFontData;
  rc = ERROR_VIO_INVALID_PARMS;
  EnvBufferPassed = SEG(Environment);

#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)
    return (ChainedGetCurrentFont ( VGA_ENV(Environment),
                                    ParmBlock,
                                    Function));
#endif
  if (EnvBufferPassed)
  {
    if ((Function == FnGetFont) &&     /* Valid function request            */
       (ParmBlock->Length >= sizeof(VDH_FONT)) && /* Valid Length           */
       (ParmBlock->Flags <= 3))
    {                                  /* Valid flags                       */
      rc = ERROR_VIO_MODE;

      if (!(Environment->ModeData.fbType & MODE_FLAG_GRAPHICS) || /* Text mode?       */
         (ParmBlock->Flags & GET_ROM_FONT))
      {                                /* Get ROM font?                     */
        rc = NO_ERROR;                 /* Parameters are OK                 */
        PelRows = ParmBlock->PelRows;
        if (ParmBlock->Flags == UPDATE_HARDWARE)
        {                              /* Not for Specified Font            */
          PelRows = (USHORT) Environment->pFontData->ulFontHeight;
        }
        FontSize = 256*PelRows;
        if ((ParmBlock->FontLength == NULL) && /* Return font size only   */
           (ParmBlock->FontBuffer == NULL))
        {
          ParmBlock->FontLength = FontSize;
        }
        else
        {
          if (ParmBlock->FontLength < FontSize)
          {
            rc = ERROR_VIO_INVALID_PARMS;
          }
          else
          {                          /* Return complete font information  */
            if (ParmBlock->Flags == UPDATE_HARDWARE)
            {                        /* Hardware font                     */
              ParmBlock->PelColumns = (USHORT) Environment->pFontData->ulFontWidth;
              ParmBlock->PelRows = PelRows;
              ParmBlock->FontLength = FontSize;/* in case too much specified */
              if (DosAllocSeg(FontSize+sizeof(FONTDATA)-1, (PSEL)&Selector, 0))
                return (ERROR_VIO_INVALID_PARMS);
              TmpFontData = (PFONTDATA) MAKEP(Selector, 0);
              /*            
               * BVHAccessFont calls VIDEOPMI, which calls execfont to copy
               * the font. Execfont needs at least ulFontHeight to set the
               * proper offest for copy since the ROM fonts always have 32
               * scan lines and FONTDATA has ulFontHeight scan lines.
               */
              TmpFontData->ulCharCount = 256;                   /*              */
              TmpFontData->ulFontWidth = ParmBlock->PelColumns; /*              */
              TmpFontData->ulFontHeight = ParmBlock->PelRows;   /*              */
              if (BVHAccessFont(GET,TmpFontData))
                return (ERROR_VIO_INVALID_PARMS);
              memcpy(ParmBlock->FontBuffer,&TmpFontData->bFontData[0],FontSize);
              DosFreeSeg(Selector);      /* Deallocate the temporary font buffer  */
            }
            else
            {
              rc = ERROR_VIO_FONT;
              /*
              ** Save current environment font data.
              */
              TmpFontData = Environment->pFontData;
              /*
              ** Query if this font is available. If TRUE,
              ** Environment->pFontData will be set.
              */
              if (FindFont(Environment,ParmBlock))
              {
                /*
                ** Copy font data into the parm buffer
                */
                ParmBlock->FontLength = FontSize;/* in case too much        */
                memcpy(ParmBlock->FontBuffer,
                       &Environment->pFontData->bFontData[0],
                       FontSize);
                /*
                ** Restore Environment font data
                */
                Environment->pFontData = TmpFontData;
                rc = NO_ERROR;
              }
            }
          }
        }
      }
    }
  }
  return (rc);
}
/*****************************************************************************
 *
 *  SUBROUTINE NAME: GetPhysBuf
 *
 *  DESCRIPTIVE NAME: Get LDT selector to physical display buffer
 *
 *  FUNCTION: GetPhysBuf is called by BVS in order to obtain an LDT
 *            selector by which to address the display buffer
 *            corresponding to the current mode or the mode specified.
 *
 *  ENTRY POINT: GetPhysBuf
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 275 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags
 *                     FAR *PhysBufData = VioGetPhysBuf structure
 *             ULONG Function ( Call vector table entry = 275 )
 *
 *  EXIT-NORMAL: AX = 0
 *               An LDT selector to the PVB is returned to caller
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: PhysToUVirt
 *
 ****************************************************************************/

USHORT EXPENTRY GetPhysBuf (PENVIRONMENT Environment,
                            PVDH_GETPVB  ParmBlock,
                            ULONG        Function )
{

  USHORT rc,i,Mode,AmountAllocated;
  ULONG  PVB_BOTTOM,PVBLen, NOT_ALLOCATED;
  FARADDRESS PVB, Temp;
  USHORT far *ReturnDataArea;
  USHORT return_alt_selectors = FALSE;

#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)
    return (ChainedGetPhysBuf ( VGA_ENV(Environment),
                                ParmBlock,
                                Function));
#endif
  rc = ERROR_VIO_PTR;                                 /* LDTSelector not passed */

  if ( ( Function == FnGetPhysBuf )                && /*Valid function request*/
     ( ParmBlock->Length >= sizeof( VDH_GETPVB ) ) && /*Valid structure length*/
     ( ParmBlock->Flags <= 1 ) &&                     /*Valid flags           */
     SEG(Environment) )
  {

//    rc   = NO_ERROR;            
    Mode = Environment->ModeIndex;
    if ( ParmBlock->PVBDataPTR->cb == 0L &&
         ParmBlock->PVBDataPTR->pBuf != 0L )
    {
      /*
      **  Length = 0, use address and length corresponding to the current mode
      **  on this adapter:
      */


      rc   = NO_ERROR;  //          
      PVB.FullAddress = pModes[Mode].BufferAddress;
      PVBLen = pModes[Mode].BufferLength;

      /*
      **  Return selector list in the alternate data structure
      */

      if(((PALT_VIOPHYSBUF) (ParmBlock->PVBDataPTR->pBuf))->cb != 2)
         return_alt_selectors = TRUE;

      ReturnDataArea = (USHORT far *)&(((PALT_VIOPHYSBUF)
                       (ParmBlock->PVBDataPTR->pBuf))->asel[0]);
    }

    else
    {

      if ( ParmBlock->PVBDataPTR->cb != 0L )
      {
        PVBLen = ParmBlock->PVBDataPTR->cb;
        PVB_BOTTOM = (ULONG)(PVB.FullAddress = ParmBlock->PVBDataPTR->pBuf);
        if ((PVB_BOTTOM >= MIN_PVB_BOTTOM)  &&
             ((PVBLen <= pModes[Mode].BufferLength) ||  /*            */
              ((PVB_BOTTOM+PVBLen) <= MAX_PVB_TOP)))    /*            */
            rc = NO_ERROR;

        else
            rc = ERROR_VIO_INVALID_PARMS;

        /*
        **  Return selector list in the passed PhysBuf data structure
        */

        ReturnDataArea = (USHORT far *)&ParmBlock->PVBDataPTR->asel[0];
      }
    }


    if ( !rc )
    {
      for ( i = 0, NOT_ALLOCATED = PVBLen; NOT_ALLOCATED; i++ )
      {

        if ( NOT_ALLOCATED > 0xFFFFL+1L )
        {
          AmountAllocated = 0;                      /* Allocate maximum ( 64K ) */
          NOT_ALLOCATED -= 64L * 1024L;
          rc = PhysToUVirt( PVB, &Temp, AmountAllocated );
          PVB.Part.Selector += 1;
        }

        else
        {
          AmountAllocated = (USHORT)NOT_ALLOCATED;         /* Allocate the rest */
          NOT_ALLOCATED = 0L;
          rc = PhysToUVirt( PVB, &Temp, AmountAllocated );
        }

        if ( !rc )
        {

          if (return_alt_selectors == TRUE)
          {
            ((PALT_VIOPHYSBUF)(ParmBlock->PVBDataPTR->pBuf))->cb =
                                  ((2*(i+1))+2);
            ReturnDataArea[i] = Temp.Part.Selector;
          }

          else
            ReturnDataArea[i] = Temp.Part.Selector;
        }
      }
    }
  }

  return( rc );

}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: FreePhysBuf
 *
 *  DESCRIPTIVE NAME: Deallocate LDT selector
 *
 *  FUNCTION: FreePhysBufe is called by BVS in order to deallocate an
 *            LDT selector which was previously used to address the
 *            physical display buffer.
 *
 *  ENTRY POINT: FreePhysBuf
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 276 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 0 ( reserved )
 *                     USHORT LDTSelector = selector to deallocate
 *             ULONG Function ( Call vector table entry = 276 )
 *
 *  EXIT-NORMAL: AX = 0
 *               An LDT selector to the PVB is deallocated
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: FreePhysToUVirt
 *
 ****************************************************************************/

USHORT EXPENTRY FreePhysBuf(PENVIRONMENT Environment,
                            PVDH_FREEPVB ParmBlock,
                            ULONG        Function )

{

  USHORT rc;

#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)
    return (ChainedFreePhysBuf ( VGA_ENV(Environment),
                                 ParmBlock,
                                 Function));
#endif
  if ( ( Function == FnFreePhysBuf )                && /* Valid function request */
     ( ParmBlock->Length >= sizeof( VDH_FREEPVB ) ) && /* Valid structure length */
      !ParmBlock->Flags )                              /* Valid flags            */

  {
    FreePhysToUVirt( ParmBlock->LDTSelector );
    rc = NO_ERROR;                                     /* Signal no error        */
  }

  else
    rc = ERROR_VIO_INVALID_PARMS;                      /* LDTSelector not passed */

  return( rc );
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: GetColorLookup
 *
 *  DESCRIPTIVE NAME: Get color lookup table
 *
 *  FUNCTION: GetColorLookup is called by BVS to return a specified
 *            portion of the current color lookup table settings
 *
 *  ENTRY POINT: GetColorLookup
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 263 )
 *
 *  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
 *                     CLUTDATA far *LookupTable ( 0x00 - 0xFF )
 *                                     UCHAR Red
 *                                     UCHAR Green
 *                                     UCHAR Blue
 *                     USHORT   FirstEntry
 *                     USHORT   NumEntries
 *             ULONG Function ( Call vector table entry = 263 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Portion of CLUT requested is returned
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: If hardware specified and hardware is readable, the
 *           environment buffer is updated, if passed.
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: AccessCLUT
 *
 ****************************************************************************/

USHORT EXPENTRY GetColorLookup(PENVIRONMENT Environment,
                               PVDH_CLUT    ParmBlock,
                               ULONG        Function)
{
  USHORT rc,EnvBufferPassed, i,j;

#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)
    return (ChainedGetColorLookup ( VGA_ENV(Environment),
                                    ParmBlock,
                                    Function));
#endif
  rc = ERROR_VIO_INVALID_PARMS;        /* Initialize to error               */
  EnvBufferPassed = SEG(Environment);  /* Non-zero = TRUE                   */

  if ((Function == FnGetColorLookupTable) && /* Valid function request      */
     (ParmBlock->Length >= sizeof(VDH_CLUT)) && /* Valid packet length      */
     (ParmBlock->Flags <= 1) &&        /* Valid flags                       */
     (ParmBlock->NumEntries) &&        /* Non-zero amount                   */
     (ParmBlock->FirstEntry <= 0xFF) && /* Valid first entry                */
     (ParmBlock->FirstEntry + ParmBlock->NumEntries <= 0xFF+1) &&
     EnvBufferPassed)
  {

    /*
    **  If requesting application is running in foreground,
    **    - Return hardware value and update environment.
    **    - Otherwise return environment buffer value
    */
    rc = NO_ERROR;                     /* Initialize no error               */

    /*
    **  Get CLUT values directly from the hardware. Allocate a temp segment.
    */

    Environment->LookupTable.ulRGBStart = (ULONG) ParmBlock->FirstEntry;
    Environment->LookupTable.ulRGBCount = (ULONG) ParmBlock->NumEntries;
    if (ParmBlock->Flags & UPDATE_HARDWARE)
    {
      BVHAccessCLUT(GET, &Environment->LookupTable);
    }
    /*
    **  Copy CLUT values from the env buffer into caller's data area.
    */
    for (i = ParmBlock->FirstEntry, j = 0; j < ParmBlock->NumEntries;
        i++, j++)
    {
      ParmBlock->LookupTable[j].Red = Environment->LookupTable.aRGB[i].bR;
      ParmBlock->LookupTable[j].Green = Environment->LookupTable.aRGB[i].bG;
      ParmBlock->LookupTable[j].Blue = Environment->LookupTable.aRGB[i].bB;
    }
  }

  return (rc);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SetColorLookup
 *
 *  DESCRIPTIVE NAME: Set color lookup table
 *
 *  FUNCTION: SetColorLookup is called by BVS to set a specified
 *            portion of the color lookup table settings
 *
 *  ENTRY POINT: SetColorLookup
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 264 )
 *
 *  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
 *                     CLUTDATA far *LookupTable ( 0x00 - 0xFF )
 *                                     UCHAR Red
 *                                     UCHAR Green
 *                                     UCHAR Blue
 *                     USHORT   FirstEntry
 *                     USHORT   NumEntries
 *             ULONG Function ( Call vector table entry = 264 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Portion of CLUT requested is set
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: AccessCLUT
 *
 ****************************************************************************/

USHORT EXPENTRY SetColorLookup(PENVIRONMENT Environment,
                               PVDH_CLUT ParmBlock,
                               ULONG Function)

{

  USHORT rc,i,j,EnvBufferPassed;

#ifdef CHAIN_VGA   /* @TSU00 */
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
    return (ChainedSetColorLookup ( VGA_ENV(Environment),
                                    ParmBlock,
                                    Function));
#endif
  rc = ERROR_VIO_INVALID_PARMS;        /* Initialize to error               */
  EnvBufferPassed = SEG(Environment);  /* Non-zero = TRUE                   */

  if ((Function == FnSetColorLookupTable) && /* Valid function request      */
     (ParmBlock->Length >= sizeof(VDH_CLUT)) && /* Valid packet length      */
     (ParmBlock->Flags <= 1) &&        /* Valid flags                       */
     (ParmBlock->NumEntries) &&        /* Non-zero amount                   */
     (ParmBlock->FirstEntry <= 0xFF) && /* Valid first entry                */
     (ParmBlock->FirstEntry + ParmBlock->NumEntries <= 0xFF+1) &&
     EnvBufferPassed)
  {

    /*
    **  Parameters are valid - Update environment buffer.
    **                       - Update hardware if in foreground
    */

    rc = NO_ERROR;                     /* Initialize no error               */

    /*
    **  Copy CLUT values from caller's parameter area to the env buffer
    */

    Environment->LookupTable.ulRGBStart = (ULONG) ParmBlock->FirstEntry;
    Environment->LookupTable.ulRGBCount = (ULONG) ParmBlock->NumEntries;
    for (i = ParmBlock->FirstEntry, j = 0; j < ParmBlock->NumEntries;
         i++, j++)
    {
      Environment->LookupTable.aRGB[i].bR = ParmBlock->LookupTable[j].Red;
      Environment->LookupTable.aRGB[i].bG = ParmBlock->LookupTable[j].Green;
      Environment->LookupTable.aRGB[i].bB = ParmBlock->LookupTable[j].Blue;
    }

    /*
    **  Set CLUT registers directly on the hardware
    */

    if (ParmBlock->Flags & UPDATE_HARDWARE)
    {
      BVHAccessCLUT(SET, &Environment->LookupTable);
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: GetPaletteReg
 *
 *  DESCRIPTIVE NAME: Get palette registers
 *
 *  FUNCTION: GetPaletteReg is called by BVS to return the specified
 *            portion of the palette registers.  If the request
 *            specifies hardware and the hardware is readable, the
 *            actual hardware setting will be read and returned.
 *            Otherwise the returned information will be taken from
 *            the environment buffer, if it has been passed.
 *
 *  ENTRY POINT: GetPaletteReg
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 273 )
 *
 *  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
 *                     FAR *PaletteBuffer
 *                     USHORT   FirstEntry
 *                     USHORT   NumEntries
 *             ULONG Function ( Call vector table entry = 273 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Requested palette registers are returned
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: If hardware specified and hardware is readable, the
 *           environment buffer is updated, if passed.
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: AccessHardware
 *
 ****************************************************************************/

USHORT EXPENTRY GetPaletteReg(PENVIRONMENT Environment,
                              PVDH_PALETTE ParmBlock,
                              ULONG Function)
{

  USHORT rc, ColorMode, VideoOn,j;
  PPALETTEDATA pPalette;
  SEL   Tmp;

#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)
    return (ChainedGetPaletteReg ( VGA_ENV(Environment),
                                   ParmBlock,
                                   Function));
#endif
  rc = ERROR_VIO_INVALID_PARMS;        /* Initialize to error               */

  if ((Function == FnGetPaletteRegisters) && /* Valid function request      */
     (ParmBlock->Length >= sizeof(VDH_PALETTE)) && /* Valid packet length   */
     (ParmBlock->Flags <= 1) &&        /* Valid flags                       */
     (SEG(Environment) || (ParmBlock->Flags&UPDATE_HARDWARE)) &&
      ParmBlock->PaletteBuffer.NumEntries && /* Non-zero amount         */
     (ParmBlock->PaletteBuffer.FirstEntry <= 0x0F) && /* Valid first entry  */
     (ParmBlock->PaletteBuffer.FirstEntry +
      ParmBlock->PaletteBuffer.NumEntries <= 0x0F+1))
  {
    /*
    ** A copy of palette register values is kept in the environment.
    ** The copy is refreshed whenever GetPalette with hardware flag
    ** is issued, SetPalette issued and during the SaveEnv.
    ** Assumption is that GetPaletteReg without the hardware flag will
    ** not be done until either of the above has happened. Otherwise,
    ** values returned will not correspond to the hardware state.
    */
    if (ParmBlock->Flags&UPDATE_HARDWARE)
    {
      if(!DosAllocSeg(sizeof(PALETTEDATA)+PALETTE_REGS,
                                 &Tmp,0))
      {
        rc = NO_ERROR;                   /* Initialize no error               */
        /*
        **  Call VIDEOPMI to obtain current mode palette values
        */
        pPalette = MAKEP(Tmp,0);
        if (SEG(Environment))
        {
          ColorMode = !(Environment->ModeData.fbType & MODE_FLAG_NO_CLR_BRST);
          VideoOn = Environment->VideoEnable;
        }
        else
        {
          ColorMode = HardwareColor();
          VideoOn = 1;
        }
        /*
        ** Obtain all of them, as we keep a full copy in our environment.
        */
        pPalette->ulPalCount = PALETTE_REGS;
        pPalette->ulPalStart = 0L;
        BVHAccessPalette(GET,pPalette);
        if (VideoOn)
          AccessVideoEnable(ColorMode, SET, &VideoOn);

        /*
        ** Copy palette values from internal buffer to the parameter block.
        ** Environment keeps just the palette data values, all 16 at all times.
        */

        for (j = 0;j < ParmBlock->PaletteBuffer.NumEntries;j++)
          (UCHAR) ParmBlock->PaletteBuffer.DataArea[j] =
            pPalette->bPaletteData[j+ParmBlock->PaletteBuffer.FirstEntry];
        if (SEG(Environment))
        {
          /*
          **  Copy palette values from internal buffer to the parameter block
          */
          for (j = 0; j < (USHORT) pPalette->ulPalCount;j++)
            Environment->bPaletteData[j] =
              pPalette->bPaletteData[j];
        }
        DosFreeSeg(Tmp);
      }
    }
    else
    {
      /*
      ** Return the environment palette values.
      */
      for (j = 0;j < ParmBlock->PaletteBuffer.NumEntries;j++)
        (UCHAR) ParmBlock->PaletteBuffer.DataArea[j] =
          Environment->bPaletteData[j+ParmBlock->PaletteBuffer.FirstEntry];
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SetPaletteReg
 *
 *  DESCRIPTIVE NAME: Set palette registers
 *
 *  FUNCTION: SetPaletteReg is called by BVS to set the specified
 *            portion of the palette registers.  If the request
 *            specifies hardware the hardware and the environment
 *            buffer, if passed, will be updated.  Otherwise just the
 *            environment buffer, if passed, will be updated.
 *
 *  ENTRY POINT: SetPaletteReg
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 274 )
 *
 *  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
 *                     FAR *PaletteBuffer
 *                     USHORT   FirstEntry
 *                     USHORT   NumEntries
 *             ULONG Function ( Call vector table entry = 274 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Requested palette registers are set
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: AccessHardware
 *
 ****************************************************************************/

USHORT EXPENTRY SetPaletteReg(PENVIRONMENT Environment,
                              PVDH_PALETTE ParmBlock,
                              ULONG Function)
{

  USHORT rc,j,ColorMode,VideoOn,EnvBufferPassed;
  PPALETTEDATA pPalette;
  SEL   Tmp;

#ifdef CHAIN_VGA   /* @TSU00 */
//  if (!(Environment->EnvFlags & ENVFLAG_PMIMODE))
  if (Environment->EnvFlags & ENVFLAG_VGAMODE)
    return (ChainedSetPaletteReg ( VGA_ENV(Environment),
                                   ParmBlock,
                                   Function));
#endif
  rc = ERROR_VIO_INVALID_PARMS;        /* Init to error                     */
  EnvBufferPassed = SEG(Environment);  /* Non-zero = TRUE                   */

  if ((Function == FnSetPaletteRegisters) && /* Valid function request      */
     (ParmBlock->Length >= sizeof(VDH_PALETTE)) && /* Valid packet length   */
     (ParmBlock->Flags <= 1) &&        /* Valid flags                       */
     (ParmBlock->PaletteBuffer.FirstEntry <= 0x0F) &&
     (EnvBufferPassed || (ParmBlock->Flags&UPDATE_HARDWARE)) &&
     (ParmBlock->PaletteBuffer.NumEntries) && /* Non-zero amount         */
     (ParmBlock->PaletteBuffer.FirstEntry +
     ParmBlock->PaletteBuffer.NumEntries <= 0x0F+1))
  {
    /*
    ** A copy of palette register values is kept in the environment.
    ** The copy is refreshed whenever GetPalette with hardware flag
    ** is issued, SetPalette issued and during the SaveEnv.
    */
    rc = NO_ERROR;                   /* Initialize no error               */

    /*
    **  Parameters are valid - Update environment buffer if it was passed
    **                       - Update hardware if in foreground
    */

    if (EnvBufferPassed)
    {

      /*
      ** Palette register are integral part of the hardware command list,
      ** but BVHPMI has no access to the hardware command list in the background, so it
      ** keeps a set of palette registers in the environment. If UPDATE_HARDWARE flag
      ** is set, ENVFLAG_BKGNDPALETTE flag is removed, denoting that hardware
      ** state and palette state are in sync and RestoreEnv has no need to set
      ** the palette state.
      */
      Environment->EnvFlags &= ENVFLAG_BKGNDPALETTE;
      /*
      **  Copy palette values from caller's parameter area to the env buffer
      */

      for (j = 0; j < ParmBlock->PaletteBuffer.NumEntries; j++)

        Environment->bPaletteData[j+ParmBlock->PaletteBuffer.FirstEntry] =
              (UCHAR) ParmBlock->PaletteBuffer.DataArea[j];

    }

    if (ParmBlock->Flags&UPDATE_HARDWARE)
    {

      Environment->EnvFlags &= ~ENVFLAG_BKGNDPALETTE;
      /*
      ** Allocate temporary internal buffer
      */
      if(!DosAllocSeg(sizeof(PALETTEDATA)+PALETTE_REGS,
                                 &Tmp,0))
      {

        pPalette = MAKEP(Tmp,0);
        if (EnvBufferPassed)
        {
          VideoOn = Environment->VideoEnable;
          /* ColorMode = Environment->ModeData.fbType & MODE_FLAG_GRAPHICS;    @V3.0JLO01 */
          ColorMode = Environment->ModeData.fbType & MODE_FLAG_NOT_MONO;    /* @V3.0JLO01 */
          /*
          ** Set them all, as we keep a full copy in our environment.
          */
          /* pPalette->ulPalCount = 0xF;                                       @V3.0JLO01 */
          pPalette->ulPalCount = PALETTE_REGS;                              /* @V3.0JLO01 */
          pPalette->ulPalStart = 0L;

          for (j = 0; j < PALETTE_REGS; j++)
            pPalette->bPaletteData[j] =
              Environment->bPaletteData[j];
        }
        else
        {
          ColorMode = HardwareColor();
          AccessVideoEnable(ColorMode, GET, &VideoOn);
          /*
          ** Set only those passed in.
          */
          pPalette->ulPalCount = (ULONG) ParmBlock->PaletteBuffer.NumEntries;
          pPalette->ulPalStart = (ULONG) ParmBlock->PaletteBuffer.FirstEntry;

          for (j = 0; j < ParmBlock->PaletteBuffer.NumEntries; j++)
            pPalette->bPaletteData[j] =
              (BYTE) ParmBlock->PaletteBuffer.DataArea[j];
        }

        BVHAccessPalette(SET,pPalette);
        if (VideoOn)
          AccessVideoEnable(ColorMode, SET, &VideoOn);
        DosFreeSeg(Tmp);
      }
    }
  }
  return (rc);
}
#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, "BVH: ");
    strcpy(s+6, DebugFn[Function-FnTextBufferUpdate].name);
    DPRINTF(s);
  }
  return ((*BVHEntryPoint[Function-FnTextBufferUpdate])(Environment,
     ParmBlock, Function));
}

#endif                                 /* DEBUG */
