/*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 = VDHMODE.c
 *
 * DESCRIPTIVE NAME = Base video device handlers - Mode, CLUT, Palette  
 *
 *
 * VERSION      V2.0
 *
 * DATE         
 *
 * DESCRIPTION  This source file contains VDH entry points
 *              which get/set the video mode.
 *
 *              NOTE: These routines execute as ring 2 conforming
 *
 * FUNCTIONS    GetMode,         SetMode                             
 *              SetHWMode, SetEnvMode, GetModeIndex                  
 *
 * NOTES        NONE
 *
 * STRUCTURES   NONE
 *
 * EXTERNAL REFERENCES
 *
 *              NONE
 *
 * EXTERNAL FUNCTIONS  SaveRegs, RestoreRegs        
 *                     AccessHardware, AccessCLUT   
 *                     PhysToUVirt, FreePhysToUVirt 
 *
*/

/*
**  Include files                                                             
*/

#define  INCL_BASE                     /* ALL of OS/2 Base                  */
#define  INCL_OS2STD                   /* Needed for NULL definition in     */
                                       /* OS2STD.H                          */
#include <os2.h>
#include "vdhctl.h"                    /* Conditional compilation control   */
#include "vdh.h"                       /* Type definitions                  */
 
/*
**  Externally defined global variables                                       
*/

extern VIDEOMODE Modes[];              /* Supported modes                   */
extern MEMORYMAPS MemoryMaps[];        /* Memory map info for each mode     */
extern UCHAR READABLE;
extern ULONG PartialSaveSize;          /* Room required to save entire PVB  
                                          in the popup mode                 */
extern USHORT VGA_PRESENT;             /* TRUE if VGA VDH has been          */
                                       /* installed                         */
extern USHORT(APIENTRY *ChainedCallVectorTable[MaxFn])();/*             @T24*/
extern VIDEOHARDWARE VideoHardware;    /*                               @T39*/
extern USHORT OEMFlags;                /* @MS27 */
extern USHORT SVGAPresent;             /* @drw */

/*
**  Parameters to ring 2 routines                                             
*/

extern CLUTDATA far ColorCLUT;
extern CLUTDATA far MonoCLUT;
extern CLUTDATA far SumCLUT;
extern CLUTDATA far ColorCLUTLow;      /* @MS13 */
extern CLUTDATA far ColorCLUT256;      /* @MS13 */
extern CLUTDATA far SumCLUTLow;        /* @MS13 */
extern CLUTDATA far SumCLUT256;        /* @MS13 */
extern USHORT far ColorCLUTCount;      /* @MS13 */
extern USHORT far ColorCLUTLowCount;   /* @MS13 */
extern USHORT far ColorCLUT256Count;   /* @MS13 */
extern USHORT far MonoCLUTCount;       /* @MS13 */
extern USHORT far SumCLUTCount;        /* @MS13 */
extern USHORT far SumCLUTLowCount;     /* @MS13 */
extern USHORT far SumCLUT256Count;     /* @MS13 */
extern CLUTDATA far *LCLUT;            /* @BB9, @S40F*/

/*****************************************************************************
 *                                                                          
 *  SUBROUTINE NAME: GetMode                                                
 *                                                                          
 *  DESCRIPTIVE NAME: Get current video mode setting                        
 *                                                                          
 *  FUNCTION: GetMode is called by BVS to get the current mode setting.     
 *            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: GetMode                                                    
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 271 )       
 *                                                                          
 *  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                    
 *                     VIOMODEINFO FAR *ModeDataPTR                         
 *             ULONG Function ( Call vector table entry = 271 )             
 *         (Referenced)                                                     
 *             Modes[] (global data - table of supported video modes )      
 *                                                                          
 *  EXIT-NORMAL: AX = 0                                                     
 *               Current mode setting is returned                           
 *                                                                          
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS                                
 *                                                                          
 *  EFFECTS: If hardware specified and hardware is readable, the            
 *           environment buffer is updated, if passed.                      
 *           If the length of ModeData does not exactly fit a               
 *           parameter, the length is adjusted and returned.                
 *                                                                          
 *  INTERNAL REFERENCES:                                                    
 *    ROUTINES: NONE                                                        
 *                                                                          
 *  EXTERNAL REFERENCES:                                                    
 *    ROUTINES: SaveRestoreHW, SetEnvMode                                   
 *                                                                          
 ****************************************************************************/


USHORT EXPENTRY GetMode(Environment,ParmBlock,Function)

  ENVIRONMENT far *Environment;
  VDH_MODE    far *ParmBlock;
  ULONG           Function;

{
  USHORT rc,ModeIndex,EnvBufferPassed;
  UCHAR i,MapMask,RegValue;
  USHORT NumBitplanes;
  REGDATA RegData;
  REGADDRESS RegAddress;
  ENVIRONMENT far *TempEnv;
  SEL Selector;
  UCHAR TempChar;                      /*                              @TB21*/
  VIDEOMODE far *pCurMode;             /* Reduce level of indirection,   @S8*/
  VIOMODEINFO far *pReqMode;           /* Reduce level of indirection,   @S8*/
  unsigned register ReqModeLen;        /* Eliminate segment loading,     @S8*/
  int SumCLUT_found,ii,j;              /*                               @BB9*/

  rc = ERROR_VIO_INVALID_PARMS;        /* Initialize to error               */
  EnvBufferPassed = SEG(Environment);  /* Non-zero = TRUE                   */
 
  if ((Function == FnGetMode) &&       /* Valid function request            */
     (ParmBlock->Length >= sizeof(VDH_MODE)) && /* Valid packet length      */
     (ParmBlock->Flags <= 1) &&        /* Valid flags                       */
     (EnvBufferPassed || (ParmBlock->Flags&UPDATE_HARDWARE)))
  {

    rc = NO_ERROR;                     /* Initialize no error               */
    ReqModeLen = (pReqMode = ParmBlock->ModeDataPTR)->cb;/*              @S8*/
 
    if (ReqModeLen > sizeof(VIOMODEINFO))
    {                                  /*                               @S25*/
      ReqModeLen = MinDLen_Mode_Vres;  /*                               @S25*/
    }                                  /*                               @S25*/
 
    if (ReqModeLen < Mode_Return_Length)/*                               @@A*/
      rc = ERROR_VIO_INVALID_LENGTH;   /*                                @@A*/
 
    else
 
      if (ReqModeLen == Mode_Return_Length)/*                            @@A*/

        ReqModeLen = sizeof(VIOMODEINFO);/*                              @@A*/
 
      else
      {                                /*                                @@A*/

        /*
        **  If requesting application is running in foreground,                    
        **    - Return hardware value if hardware can be read                      
        **    - Otherwise return environment buffer value                          
        **    ( report error if write-only hardware and no env buffer passed )
        **  If requesting application is running in background,                    
        **    - Return environment buffer value                                    
        **     ( report error if environment buffer was not passed )               
        */
                                                                           

        if ((ParmBlock->Flags&UPDATE_HARDWARE) && READABLE)
        {

#if      VDHVGA                        /* Read/write hardware               */
                                       /* @MS00 */

          /*
          **  Allocate temporary storage to temporary environment buffer                
          */

          if (!(rc = DosAllocSeg(sizeof(ENVIRONMENT), (PSEL)&Selector, 0)))
          {
            TempEnv = (ENVIRONMENT far *)MakeFarPTR(Selector, 0);

            /*
            **  Read all registers directly from the hardware                             
            */

            TempEnv->VideoEnable = 1;  /* Assume video ON               @T34*/
            SaveRestoreHW(TempEnv, GET);
            ModeIndex = GetModeIndex(TempEnv);/* Get mode index + 1         */
 
            if (!ModeIndex--)
              rc = ERROR_VIO_MODE;     /* Somebody corrupted the registers  */
 
            if (!rc && EnvBufferPassed)

              /*
              **  Update environment buffer with current mode setting                       
              */

              SetEnvMode((UCHAR)ModeIndex, Environment, TempEnv, 0);/*  @T70*/

            /*
            **  Deallocate temporary storage to temporary environment buffer              
            */

            DosFreeSeg(Selector);
          } 
#endif             /*     VDHVGA @MS00 */
        } 
 
        else
        {

          /*
          **  Requesting application is running in the "background"                     
          */

          if (EnvBufferPassed)

            /*
            **  Retrieve mode setting from environment buffer                             
            */

            ModeIndex = Environment->ModeIndex;
 
          else
            rc = ERROR_VIO_INVALID_PARMS;/* Not FG OR write-only, no env    */
                                         /* buffer                          */
        } 

#if      VDH8514A                        /* @MS00 */

        /*
        **  If the current mode in the environment buffer is an 8514/A native         
        **  mode, return the appropriate information.  Otherwise call GetMode         
        **  in VDHVGA.DLL                                                             
        **                                                                            
        */

        if (!Environment->NATIVE_MODE)
          rc = ChainedVDHGetMode((ENVIRONMENT far *)&Environment->VGAEnvironment,
                                  ParmBlock, Function);         /* not      */
                                                                /* native   */
 
        else

          /* Native mode - return the mode data                             */

#endif    
 
          if (!rc)
          {
            pCurMode = (VIDEOMODE far *)&Modes[ModeIndex].cb;/*          @S8*/

            /*
            **  Mode type:
            **  xxxxxxxb b = 0 Monochrome,  b = 1 Other
            **  xxxxxxbx b = 0 Text,        b = 1 Graphics
            **  xxxxxbxx b = 0 Color burst, b = 1 Color burst disabled
            **  xxxxbxxx b = 0 Normal mode, b = 1 Advanced function ( native )
            */

            pReqMode->fbType = pCurMode->fbType;
 
            if (EnvBufferPassed && !(ParmBlock->Flags&UPDATE_HARDWARE))
            {

#if      VDHVGA                        /* Read/write hardware               */
                                       /* @MS00 */
 
              if ((Environment->ModeData.fbType&NOT_MONO) /* @MS13 */
                 && !(Environment->ModeData.fbType&GRAPHICS))
              {                        /* @MS13 */
                /*
                ** We are looking for any monochrome CLUT, not a particular
                ** one. Thecharacteristic of a monochrome palette is the same
                ** intensity for red, green, and blue in each row.
                */
                register irow = 0;     /* @MS13 */
 

                while ((irow < 0xFF+1) /* @MS13 */
                   && (Environment->LookupTable[irow].Red ==   /* @MS13 */
                      Environment->LookupTable[irow].Green)    /* @MS13 */
                   && (Environment->LookupTable[irow].Red ==   /* @MS13 */
                      Environment->LookupTable[irow].Blue)     /* @MS13 */
                   )
                  irow++;                                      /* @MS13 */

                /*
                **  If loop completed, assume black & white
                */
                if (irow == 0xFF+1)
                  Environment->ModeData.fbType |= NO_CLR_BRST; /* @MS13 */
              }                                                /* @MS13 */
#endif    
              pReqMode->fbType = Environment->ModeData.fbType;
            } 
 
            if (ReqModeLen < MinDLen_Mode_Color)
              ReqModeLen = MinDLen_Mode_Type;
 
            else
            {

              /*
              **  Color ( power of 2 )                                                      
              */

              pReqMode->color = pCurMode->color;
 
              if (ReqModeLen < MinDLen_Mode_Column)
                ReqModeLen = MinDLen_Mode_Color;
 
              else
              {

                /*
                **  Number of text columns: 40 or 80                                          
                */

                pReqMode->col = pCurMode->col;
 
                if (ReqModeLen < MinDLen_Mode_Row)
                  ReqModeLen = MinDLen_Mode_Column;
 
                else
                {

                  /*
                  **  Number of text rows                                                       
                  */

                  pReqMode->row = pCurMode->row;
 
                  if (EnvBufferPassed && !(ParmBlock->Flags&UPDATE_HARDWARE))
                    pReqMode->row = Environment->ModeData.row;
 
                  if (ReqModeLen < MinDLen_Mode_Hres)
                    ReqModeLen = MinDLen_Mode_Row;
 
                  else
                  {

                    /*
                    **  Horizontal resolution                                                     
                    */

                    pReqMode->hres = pCurMode->hres;
 
                    if (ReqModeLen < MinDLen_Mode_Vres)
                      ReqModeLen = MinDLen_Mode_Hres;
 
                    else
                    {

                      /*
                      **  Vertical resolution                                                       
                      */

                      pReqMode->vres = pCurMode->vres;
 
                      if (ReqModeLen < MinDLen_Mode_FormatID)
                        ReqModeLen = MinDLen_Mode_Vres;
 
                      else
                      {

                        /*
                        **  Attribute format ID                                                       
                        */

                        if (EnvBufferPassed)/*                           @P1*/
                          pReqMode->fmt_ID = Environment->ModeData.fmt_ID;
 
                        else           /*                                @P1*/
                          pReqMode->fmt_ID = pCurMode->fmt_ID;
 
                        if (ReqModeLen < MinDLen_Mode_Attrib)
                          ReqModeLen = MinDLen_Mode_FormatID;
 
                        else
                        {

                          /*
                          **  Attribute                                                                 
                          */

                          if (EnvBufferPassed)/*                         @P1*/
                            pReqMode->attrib = Environment->ModeData.attrib;
 
                          else         /*                                @P1*/
                            pReqMode->attrib = pCurMode->attrib;
 
                          if (ReqModeLen < MinDLen_Mode_BufStart)
                            ReqModeLen = MinDLen_Mode_Attrib;
 
                          else
                          {

                            /*
                            **  Physical display buffer start address                                     
                            */

#if      VDH8514A                      /* @MS00 */
                            pReqMode->BufferAddress = UNKNOWN;

#else
                            pReqMode->BufferAddress = MemoryMaps
                               [pCurMode->MemMap].Start.FullAddress;
#endif    
 
                            if (ReqModeLen < MinDLen_Mode_BufLen)
                              ReqModeLen = MinDLen_Mode_BufStart;
 
                            else
                            {

                              /*
                              **  Physical display buffer length                                            
                              */

#if      VDH8514A                      /* @MS00 */
                              pReqMode->BufferLength = UNKNOWN;

#else
                              pReqMode->BufferLength = pReqMode->fbType
                                 &GRAPHICS?MemoryMaps[pCurMode->MemMap].
                                 TotalSize:2*pReqMode->col *pReqMode->row;
 
                              if (pCurMode->MemMap == MemMap_LoRes)
                                pReqMode->BufferLength = 16000;/*      @@TB9*/
#endif    
 
                              if (ReqModeLen < MinDLen_Mode_FullBufSz)
                                ReqModeLen = MinDLen_Mode_BufLen;
 
                              else
                              {

                                /*
                                **  Full physical display buffer size                                         
                                */

                                pReqMode->FullBufferSize = 
                                   pReqMode->BufferLength;

                                /*
                                **  Add size of font buffer only if text mode
                                */
 
                                if (!(pCurMode->fbType&GRAPHICS))
                                  pReqMode->FullBufferSize = 
                                     pReqMode->BufferLength+ 
                                     (ULONG)256*(ULONG)
                                           (Environment->ModeData.vres/
                                           Environment->ModeData.row);
 
                                if (pReqMode->attrib == WorldAttrCount)
                                  pReqMode->FullBufferSize *= WorldAttrMult;
 
                                if (ReqModeLen < MinDLen_Mode_PartBufSz)
                                  ReqModeLen = MinDLen_Mode_FullBufSz;
 
                                else
                                {

                                  /*
                                  **  Full physical display buffer size of
                                  **  popup mode
                                  */

                                  pReqMode->PartialBufferSize = 
                                     PartialSaveSize;
 
                                  if (pReqMode->attrib == WorldAttrCount)
                                    pReqMode->PartialBufferSize *= 
                                       WorldAttrMult;
 
                                  if (ReqModeLen < MinDLen_Mode_ExtData)
                                    ReqModeLen = MinDLen_Mode_PartBufSz;
 
                                  else
                                  {

                                    /*
                                    **  Pointer to extended mode data area
                                    */

                                    pReqMode->ExtDataArea = (UCHAR far *)NULL;
                                    ReqModeLen = MinDLen_Mode_ExtData;
                                  } 
                                }      /* else get PartialBufferSize        */
                              }        /* else get FullBufferSize           */
                            }          /* else get BufferLength             */
                          }            /* else get BufferAddress            */
                        }              /* else get Attribute                */
                      }                /* else get Format ID                */
                    }                  /* else get Vres                     */
                  }                    /* else get Hres                     */
                }                      /* else get rows                     */
              }                        /* else get columns                  */
            }                          /* else get color                    */
          }                            /* if !rc                            */
      }                                /* else good mode length          @@A*/
  }                                    /* if good parameters                */
 
  if (!rc)
  {                                    /*                                @S8*/
    pReqMode->cb = ReqModeLen;         /*                                @S8*/
  }                                    /*                                @S8*/


  return (rc);
} 

/*****************************************************************************
 *                                                                          
 *  SUBROUTINE NAME: SetMode                                                
 *                                                                          
 *  DESCRIPTIVE NAME: Set video mode                                        
 *                                                                          
 *  FUNCTION: SetMode is called by BVS to set the video mode.               
 *            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: SetMode                                                    
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 272 )       
 *                                                                          
 *  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                    
 *                     VIOMODEINFO FAR *ModeDataPTR                         
 *             ULONG Function ( Call vector table entry = 272 )             
 *         (Referenced)                                                     
 *             Modes[] (global data - table of supported video modes )      
 *                                                                          
 *  EXIT-NORMAL: AX = 0                                                     
 *               Video mode is set                                          
 *                                                                          
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS                                
 *                                                                          
 *  INTERNAL REFERENCES:                                                    
 *    ROUTINES: NONE                                                        
 *                                                                          
 *  EXTERNAL REFERENCES:                                                    
 *    ROUTINES: SetHWMode                                                   
 *                                                                          
 ****************************************************************************/


USHORT EXPENTRY SetMode(Environment,ParmBlock,Function)

  ENVIRONMENT far *Environment;
  VDH_MODE    far *ParmBlock;
  ULONG           Function;

{
  USHORT rc,i,tempflags,MODE_FOUND,EnvBufferPassed;
  UCHAR FONT_AVAILABLE;                /*                              @@TB1*/
  VIDEOMODE far *pCurMode;             /* Reduce level of indirection,   @S8*/
  VIOMODEINFO far *pReqMode;           /* Reduce level of indirection,   @S8*/
  unsigned register ReqModeLen;        /* Eliminate segment loading,     @S8*/
  USHORT ChainedXGAMode132 = (ParmBlock->Flags & 0x4000);       /*            */
  ParmBlock->Flags &= ~0x4000;                                  /*            */

  FONT_AVAILABLE = TRUE;               /*                              @@TB1*/
  rc = ERROR_VIO_INVALID_PARMS;        /* Initialize to error               */
  EnvBufferPassed = SEG(Environment);  /* Non-zero = TRUE                   */
 
  if ((Function == FnSetMode) &&       /* Valid function request            */
     (ParmBlock->Flags <= 0x07) &&     /* Valid flags                       */
     (EnvBufferPassed || (ParmBlock->Flags&UPDATE_HARDWARE)))
  {
    ReqModeLen = (pReqMode = ParmBlock->ModeDataPTR)->cb;/*              @S8*/
    rc = ERROR_VIO_INVALID_LENGTH;     /*             @@TB1INITIALIZETOERROR*/
 
    if ((ParmBlock->Length >= sizeof(VDH_MODE)) && /* @@TB1VALIDPACKETLENGTH*/
       (ReqModeLen >= MinDLen_Mode_Type))          /* @@TB1VALIDMODELENGTH  */
    {

      /*
      **  Find the mode based upon matching specified parameters with entry in      
      **  the table of supported modes.  If a partial parameter list is             
      **  provided, use the highest resolution mode that matches the provided       
      **  parameters.                                                               
      */
                                                                            
      rc = ERROR_VIO_MODE;             /* Initialize to error               */
      tempflags = ParmBlock->Flags;
 
      if (pReqMode->fbType&NO_CLR_BRST)
      {
        tempflags |= NO_CLR_BRST;      /* Indicate B/W Mode                 */
      } 

#if      1                      /* @drw **************** added SVGA support */
                                /* Flags bit 2 is 'no validation' flag      */
                                /* must have SVGAPresent                    */
                                /* must have an environment to update       */
                                /* must be text mode                        */
                                /* must have at least up to 'row' data      */
 
      if (SVGAPresent && EnvBufferPassed && (ParmBlock->Flags&0x04) && 
      (ReqModeLen >= MinDLen_Mode_Row) && !(pReqMode->fbType&GRAPHICS))
      {
        Environment->ModeIndex = 0;
#if     VDHVGA
        Environment->SVGAMode |= MODE_SVGA_ENVFLAG;    /*            */
#endif
        Environment->ModeData.cb = ReqModeLen;
        Environment->ModeData.fbType = pReqMode->fbType;
 
        if (ReqModeLen >= MinDLen_Mode_Color)
          Environment->ModeData.color = pReqMode->color;
 
        if (ReqModeLen >= MinDLen_Mode_Column)
          Environment->ModeData.col = pReqMode->col;
 
        if (ReqModeLen >= MinDLen_Mode_Row)
          Environment->ModeData.row = pReqMode->row;
 
        if (ReqModeLen >= MinDLen_Mode_Hres)
          Environment->ModeData.hres = pReqMode->hres;
 
        if (ReqModeLen >= MinDLen_Mode_Vres)
          Environment->ModeData.vres = pReqMode->vres;
 
        if (ReqModeLen >= MinDLen_Mode_FormatID)
          Environment->ModeData.fmt_ID = pReqMode->fmt_ID;

        Environment->ModeData.BufferAddress = (UCHAR FAR *)0x0b8000L;
        Environment->ModeData.BufferLength = 2*pReqMode->col *pReqMode->row;
        Environment->ModeData.ExtDataArea = NULL;
        Environment->ScrollRect.Right = pReqMode->col-1;
        Environment->ScrollRect.Bottom = pReqMode->row-1;
        return (NO_ERROR);
      }                   
#if     VDHVGA
      else
        Environment->SVGAMode &= ~MODE_SVGA_ENVFLAG;            /*           */
#endif
#endif                           /* @drw **************** end SVGA support  */
 
      for (i = 0, MODE_FOUND = FALSE; (i < NUM_MODES) && !MODE_FOUND; i++)
      {                                /* @MS12 */
        pCurMode = (VIDEOMODE far *)&Modes[i].cb;/*                      @S8*/

        /*
        **  Verify that the mode is valid by finding it in the mode table             
        */

#if      VDHCGA                        /* @MS00 */
        /*
        ** Ignore Color Burst on DSM                               
        */
 
        if ((pCurMode->fbType == pReqMode->fbType)                 /* @MS14 */
        || ((OEMFlags&DSM_MONITOR)                                 /* @MS14 */
        && (pCurMode->fbType == (pReqMode->fbType&~NO_CLR_BRST)))) /* @MS14 */

#else                                                              /* @MS00 */
 
          if (pCurMode->fbType == (pReqMode->fbType&~NO_CLR_BRST)) /* @MS14 */
#endif    

             /*
             **  Type matches - If color specified, check for match. Otherwise
             **               default color, col, row, hres, vres to this mode
             */

             if (ReqModeLen < MinDLen_Mode_Color)
                MODE_FOUND = TRUE;       /* Found a matching mode           */
 
            else
 
              if (pReqMode->color == pCurMode->color)

                /*
                **  Color matches - If col specified, check for match. 
                **      Otherwiswe default col, row, hres, vres to this mode
                */

                if (ReqModeLen < MinDLen_Mode_Column)
                  MODE_FOUND = TRUE;   /* Found a matching mode             */
 
                else
 
                  if ((pReqMode->col == pCurMode->col) || (pReqMode->fbType
                     &GRAPHICS))

                    /*
                    **  col matches - If row specified, check for match. 
                    **      Otherwise default row, hres and vres to this mode
                    */      

                    if (ReqModeLen < MinDLen_Mode_Hres)
                      MODE_FOUND = TRUE;/* Found a matching mode            */
 
                    else
 
                      if (pReqMode->hres == pCurMode->hres)

                        /*
                        **  hres matches - If vres specified, check for match.
                        **                 Otherwise default vres to this mode
                        */

                        if (ReqModeLen < MinDLen_Mode_Vres)
                          MODE_FOUND = TRUE;/* Found a matching mode        */
 
                        else
 
                          if (pReqMode->vres == pCurMode->vres)
                            MODE_FOUND = TRUE;/* Found a matching mode      */

/*
** If the everything matches so far, call findfont if the rows don't match  
** and not graphics mode.  If no font found, set a temporary error code.    
** If no font found and buffer not large enough, reset !MODE_FOUND true.    
*/

        goto search_part1;

search_part2:                          /* MS?? - END */
 
        if (MODE_FOUND && (ReqModeLen >= MinDLen_Mode_Row))
          if (pReqMode->row > 0)
          {                            /*                               @B22*/
 
            if (!(pReqMode->fbType&GRAPHICS) && (pReqMode->row != 
               pCurMode->row))
            {

#if      FONT_SUPPORT                  /* @MS00 */
              FONT_AVAILABLE = FindFont(i, pReqMode->row, Environment);
 
              if (!FONT_AVAILABLE || (0x2000 < (pReqMode->row *pReqMode->col)))
#endif    
                   MODE_FOUND = FALSE;
            } 
 
            else
              FONT_AVAILABLE = TRUE;
          }                            /*                               @B22*/
 
          else
            MODE_FOUND = FALSE;        /*                               @B22*/
            goto search_end;

search_part1:

#if      VDHVGA                        /* @MS00 */
 
        if (MODE_FOUND)
        {                              /*                               @S39*/

          /*
          **  Make sure PDP does not exist for modes not valid with PDP
          */

          /*          ** The logic of this terrible if statement should be:
          ** If (current mode not supported on plasma display and
          **     display is plasma) or 
          ** if (mode has 132 columns and either
          **     ((IBM_132 mode index used on non-IBM hardware) or
          **     (OEM_132 index used on non-oem hardware)) true or
          ** if (if CGA or MPA mode conflict with VGA)
          **    reset mode found to false.                                      
          */
          if (((pCurMode->Flags&NOT_PLASMA)/*                           @S39*/
             && (VideoHardware.display == PlasmaDisplay)) ||           /*@T39,@S39*/

             (
              (pCurMode->col == 132) &&                         /*@B726706 */ 
              ((
                (i < ModeIndex_OEM_132) &&                      /*@B726706 */
                (!(Environment->Comp_Reg = VideoHardware.Reg_132) ||  /*           */
                ((Environment->XGA_PRESENT) && !(ChainedXGAMode132))) /*           */
               ) || 
               (
                (i >= ModeIndex_OEM_132) && 
                !(OEMFlags&OEM_132_COLUMNS)
               )                                                /*@B726706 */
             ))                                                 /*@B726706 */

             /*
             **  Make sure CGA does not conflict with this VGA mode 
             */

             || ((pCurMode->fbType&NOT_MONO)/*                          @S39*/
             && (VideoHardware.fVideoType&CGA_BIT))/*                   @S39*/

             /*
             **  Make sure MPA does not conflict with this VGA mode                      
             */

             || (!(pCurMode->fbType&NOT_MONO)/*                         @S39*/
             && (VideoHardware.fVideoType&MPA_BIT)))
          {                            /*                               @S39*/
            MODE_FOUND = FALSE;
          }                            /*                               @S39*/

        }                              /*                               @S39*/
#endif    

#if      VDHEGA                        /* @MS00 */


          /*
          **  EVEN THOUGH THE SPECIFIED MODE WAS FOUND IN THE MODE TABLE, MAKE          
          **  SURE THAT IT IS VALID WITH THE ATTATCHED MONITOR.  MAKE SURE              
          **  MONOCHROME MONITOR EXISTS FOR MONOCHROME MODES 7,F,10                     
          */

          if ((!(pReqMode->fbType&NOT_MONO) && 
          (VideoHardware.display != Mono5151)) ||                /* @T39  */

          /*
          **  Make sure monochrome monitor doesn't exist for color modes                
          */

          ((pReqMode->fbType&NOT_MONO) && 
          (VideoHardware.display == Mono5151)) ||                /* @T39  */
          ((pCurMode->Flags&EGA_GT_64K) &&                       /* @MS15 */
          (VideoHardware.memory <= 64L*1024L)) ||                /* @MS15 */

          /*
          **  Make sure normal color monitor doesn't exist for enhanced modes           
          */

          ((pCurMode->Flags&ENHANCED_MONITOR) && 
          (VideoHardware.display != EnColor5154))                /*  @T39*/
            )

            MODE_FOUND = FALSE;
#endif    

        /*
        **  Make sure disable color burst is not specified on non-applicable
        **  modes
        */

        if (MODE_FOUND && ((pReqMode->fbType&NO_CLR_BRST) && 
                          (pCurMode->Flags & IGNORE_CLR_BRST)))

           MODE_FOUND = FALSE;          /* END OF                       @T37*/

        /*
        **  Check for modes prohibited by OEM flags                                   
        */

#if      VDHCGA                        /* @MS19 - BEGIN */
 
        if (MODE_FOUND)
 
          if ((!(OEMFlags&IDC_CGA)
             && (pCurMode->Flags & IDC_PLASMA_ONLY))
             || ((pCurMode->Flags & VDU_DSM_ONLY)
             && (!(OEMFlags & VDU_CGA)
             || !(OEMFlags & DSM_MONITOR) )))

            MODE_FOUND = FALSE;

#endif    

#if      VDHVGA
 
        if (MODE_FOUND)
 
          if (((OEMFlags & STARLIGHT_VGA) && !(pCurMode->fbType & GRAPHICS) &&
             (pCurMode->col == 40) && (pCurMode->hres == 360)) || 
             ((i == ModeIndex_VGC2E) && !(OEMFlags & STARDUST_VGA)))
          {
            MODE_FOUND = FALSE;
          } 

#endif                                 /* VDHVGA */
        goto search_part2;

/* End of mode table search                                                 */

search_end:                            /* @MS19 - END */
        ;
      }                                /* End of For that searches the Mode */
                                       /* table                             */

      /*
      **  Verify that the format ID and Attribute count are default or@P1   
      **  ARE THE WORLD FORMAT (LVB FORMAT 70, 3 LVB ATTRIBUTES)            
      */

      if (MODE_FOUND)
      {                                /*                                @P1*/
 
        if (ReqModeLen >= MinDLen_Mode_FormatID)
        {                              /*                                @P1*/
 
          if ((pReqMode->fmt_ID != DefaultFormat) && /*                  @P1*/
             (pReqMode->fmt_ID != WorldFormat))
          {                            /*                                @P1*/
            MODE_FOUND = FALSE;        /*                                @P1*/
          }                            /*                                @P1*/
 
          else
          {                            /*                                @P1*/
 
            if (ReqModeLen >= MinDLen_Mode_Attrib)
            {                          /*                                @P1*/
 
              if (((pReqMode->attrib != DefaultAttrCount) && 
                 (pReqMode->attrib != WorldAttrCount) && 
                 (pReqMode->attrib != 0)) ||                       /*  @TB15*/
                 ((pReqMode->attrib != WorldAttrCount) && 
                 (pReqMode->fmt_ID == WorldFormat)))
              {
                MODE_FOUND = FALSE;    /*                                @P1*/
              }                        /*                                @P1*/
            }                          /*                                @P1*/
          }                            /*                                @P1*/
        }                              /*                                @P1*/
      }                                /*                                @P1*/

#if      VDH8514A                      /* @MS00 */

        /*
        **  If the specified mode is native to the 8514/A is an 8514/A native          
        **  mode, return the appropriate information.  Otherwise call GetMode          
        **  in VDHVGA.DLL                                                              
        */

        if (!MODE_FOUND)
        {
 
          if (VGA_PRESENT)
          {
            tempflags = Environment->NATIVE_MODE;/* Save AFMode flag    @T58*/
            i = (USHORT)Environment->ModeData.fbType;/* Save mode type  @T58*/
            Environment->ModeData.fbType &= ~NATIVE;/* Clear native bit     
                                                                        @T58*/
            Environment->NATIVE_MODE = FALSE;/* Must leave native mode      */
 
            if (ParmBlock->Flags&UPDATE_HARDWARE)
            {
              LeaveNativeMode();
            } 
 
            if ((rc = ChainedVDHSetMode(           /*                   @T58*/
               (ENVIRONMENT far *)&Environment->VGAEnvironment, 
               ParmBlock, Function)))
            {

              /* Reset back to AF mode if setmode fails on VGA              */

              Environment->NATIVE_MODE = tempflags;/* Restore native mode   */
                                                   /*                   @T58*/
              Environment->ModeData.fbType = (UCHAR)i;/* Restore mode type  
                                                                        @T58*/
 
              if ((ParmBlock->Flags&UPDATE_HARDWARE) && tempflags)
              {                        /*                               @T58*/
                SetHWMode(Environment->ModeIndex, ParmBlock->Flags, 
                   Environment);
              } 
            } 
          } 
        } 
 
        else
        {
          Environment->NATIVE_MODE = TRUE;/* Must set a Native mode         */

#else
 
          if (MODE_FOUND)
          {
#endif    

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

            if (EnvBufferPassed)
            {

              /*
              **  Put all of the caller's parameters into the 
              **  environment buffer Fill in missing
              **  parameters with defaults in the mode table                     
              */

              Environment->ModeIndex = (UCHAR)i-1;/* Remember actual mode   */
                                                  /* being set              */
              Environment->ModeData.cb = ReqModeLen;
              Environment->ModeData.fbType = pReqMode->fbType;
 
              if (ReqModeLen >= MinDLen_Mode_Color)
                Environment->ModeData.color = pReqMode->color;
 
              else
                Environment->ModeData.color = pCurMode->color;
 
              if (ReqModeLen >= MinDLen_Mode_Column)
                Environment->ModeData.col = pReqMode->col;
 
              else
                Environment->ModeData.col = pCurMode->col;
 
              if (ReqModeLen >= MinDLen_Mode_Row)
                Environment->ModeData.row = pReqMode->row;
 
              else
                Environment->ModeData.row = pCurMode->row;
 
              if (ReqModeLen >= MinDLen_Mode_Hres)
                Environment->ModeData.hres = pReqMode->hres;

              else
                Environment->ModeData.hres = pCurMode->hres;
 
              if (ReqModeLen >= MinDLen_Mode_Vres)
                Environment->ModeData.vres = pReqMode->vres;
 
              else
                Environment->ModeData.vres = pCurMode->vres;
 
              if (ReqModeLen >= MinDLen_Mode_FormatID)
                Environment->ModeData.fmt_ID = pReqMode->fmt_ID;
 
              else
                Environment->ModeData.fmt_ID = pCurMode->fmt_ID;

              /*
              ** always set World Attribute count if World Format
              ** was specified
              */

              if (Environment->ModeData.fmt_ID == WorldFormat)/*         @P1*/
                Environment->ModeData.attrib = WorldAttrCount;/*         @P1*/
 
              else
                Environment->ModeData.attrib = pCurMode->attrib;

              Environment->ModeData.BufferAddress = 
                 MemoryMaps [pCurMode->MemMap].Start.FullAddress;

              Environment->ModeData.BufferLength = 
                 Environment->ModeData.fbType & GRAPHICS
                 ? MemoryMaps[pCurMode->MemMap].TotalSize
                 : 2 * Environment->ModeData.col * Environment->ModeData.row;
 
              if (pCurMode->MemMap == MemMap_LoRes)
                Environment->ModeData.BufferLength = 16000;/*          @@TB9*/

              Environment->ModeData.ExtDataArea = (UCHAR far *)NULL;
            } 

#if      FONT_SUPPORT                  /* @MS00 */

            /*
            **  Setup the font to be loaded for text modes                                
            */

            if (!(pReqMode->fbType&GRAPHICS))
            {
 
              if (EnvBufferPassed)
              {
                FindFont(Environment->ModeIndex, Environment->ModeData.row, 
                   Environment);
              } 
 
              else
              {
                FindFont((UCHAR)i-1, Modes[(UCHAR)i-1].row, Environment);
              } 
            } 
#endif    

            /*
            **  If Flags = UPDATE_HARDWARE, SetHWMode will set the hardware               
            **  registers If environment buffer is passed, SetHWMode will                 
            **  shadow the registers                                                      
            */

            rc = SetHWMode((UCHAR)(i-1), tempflags, Environment);/*     @T53*/

          } 
 
          if (!FONT_AVAILABLE)         /*                              @@TB1*/
            rc = ERROR_VIO_FONT;       /* end check for invalid length      */
        }                              /*                              @@TB1*/
    }                                  /* end check for invalid parms  @@TB1*/
 
    if (rc == NO_ERROR)
    {                                  /*                                @P1*/
 
      if (EnvBufferPassed)
      {
        Environment->ScrollRect.Right = Environment->ModeData.col-1;/*   @P1*/
        Environment->ScrollRect.Bottom = Environment->ModeData.row-1;/*  @P1*/
 
        if (Environment->ModeData.fmt_ID == WorldFormat)/*               @P1*/
          Environment->AttrBufSize = 3;/*                                @P1*/
 
        else                           /*                                @P1*/
          Environment->AttrBufSize = 1;/*                                @P1*/
      }                                /*                                @P1*/
    }                                  /*                                @P1*/

    return (rc);
  } 

/*****************************************************************************
 *                                                                             
 *  SUBROUTINE NAME: SetHWMode                                                 
 *                                                                             
 *  DESCRIPTIVE NAME: Set the hardware mode                                    
 *                                                                             
 *  FUNCTION: SetHWMode is called to set the hardware to the supported         
 *            video mode. If Flags = UPDATE_HARDWARE, the registers            
 *            are set.  If environment buffer is passed, the registers         
 *            are shadowed.                                                    
 *                                                                             
 *  ENTRY POINT: SetHWMode                                                     
 *    LINKAGE:   CALL FAR                                                      
 *                                                                             
 *  INPUT: (Passed on stack)                                                   
 *             UCHAR Mode ( Index in table of supported modes )                
 *         (Referenced)                                                        
 *             Modes[] (global data - table of supported video modes )         
 *             Fonts[] (global data - table of ROM font areas )                
 *                                                                             
 *  EXIT-NORMAL: Video mode is set on hardware                                 
 *                                                                             
 *  EFFECTS: NONE                                                              
 *                                                                             
 *  INTERNAL REFERENCES:                                                       
 *    ROUTINES: SetDefaultCLUT, PhysToUVirt, FreePhysToUVirt                   
 *                                                                             
 *  EXTERNAL REFERENCES:                                                       
 *    ROUTINES: AccessHardware, AccessRegister                                 
 *                                                                             
 *****************************************************************************/


  USHORT PASCAL near SetHWMode(Mode, Flags, Environment)/*         @B15,@T53*/

  UCHAR Mode;
  USHORT Flags;
  ENVIRONMENT far *Environment;
  {

    USHORT EnvBufferPassed,Ind,ColorMode,VideoEnable,VideoOn,/*         @C21*/
           i,j,k,m,rc;                                       /*         @T53*/
    REGADDRESS RegAddress;
    REGDATA RegData;

#if      VDHVGA                        /* @MS00 */
    CLUTDATA far *CLUT;
    REGDATA  ClutParms;
    USHORT   CLUTCount;                /* @MS13 */
#endif    

    EnvBufferPassed = SEG(Environment);/* Non-zero = TRUE                   */
    ColorMode = Modes[Mode].fbType&NOT_MONO;/* Needed by AccessVideoEnable  */
                                            /* on non-VGA                   */

#if      !(VDH8514A)                   /* @MS00 */

/*
**  Turn the video signal off to reduce snow                                  
*/

    if (Flags&UPDATE_HARDWARE)
    {
 
      if (EnvBufferPassed)             /*                               @C21*/
        VideoOn = Environment->VideoEnable;/*                           @C21*/
 
      else                             /*                               @C21*/

#if      VDHVGA                      /*                         @C21,@MS00*/
  AccessVideoEnable(ColorMode, GET, &VideoOn);/*                        @C21*/

  #else                                /*                         @C21,@MS00*/
  VideoOn = 1;                         /*                               @C21*/

#endif    

      VideoEnable = 0;                 /* Turn video off                    */
      AccessVideoEnable(ColorMode, SET, &VideoEnable);/* ring 2 callgate    */
    } 
#endif    

/*
**  IF NOT GRAPHICS, SEARCH THRU MODE TABLE TO FIND CRTCTLREGS_CMD WITH CURSOR
**  START/END DATA AND CHANGE THEM TO BE THE 2ND TO LAST AND LAST PEL IN THE  
**  ROW          INDEX 0XB -> END   0XA -> START                              
*/

    if (!(Environment->ModeData.fbType&GRAPHICS))
    {                                                             /*    @C12*/
 
      for (i = 0; Modes[Mode].ModeRegs[i].Command != CRTCtlRegs_CMD || 
         Modes[Mode].ModeRegs[i].RegData.NumEntries < 0x0C; i++);
                                                                  /*    @C12*/
      m = Environment->ModeData.vres/Environment->ModeData.row;   /*    @C12*/
      Modes[Mode].ModeRegs[i].RegData.DataArea[0x0B] = (UCHAR)--m;/*    @C12*/
      Modes[Mode].ModeRegs[i].RegData.DataArea[0x0A] = (UCHAR)--m;/*    @C12*/

#if      !(VDHVGA      || VDH8514A)    /* set start line shadow for non-VGA 
                                                              @C24,B10,@MS00*/
Environment->EGAShadowTopScanLine = m; /*                               @C24*/
#endif    
    }                                  /*                           @C12,B10*/

#if      VDHCGA                        /* @MS16 - BEGIN */
 
      if (OEMFlags&IDC_CGA)
      {
        /*
        ** If setting 640x400 graphics mode, enable extended mode bit.
        ** For all other CGA modes, keep it clear.
        */

        Environment->Hardware.IDCExtendedMode = (Mode == ModeIndex_DMP40)
        ? 0x01 : 0x00;
 
        if (Flags&UPDATE_HARDWARE)
        {
          UCHAR byt;

          RegAddress.DataPort = IDCExtendedModeReg;
          AccessRegister(&RegAddress, GET, &byt);
          byt &= ~0x01;
          byt |= Environment->Hardware.IDCExtendedMode;
          AccessRegister(&RegAddress, SET, &byt);
        } 
      } 
#endif    

#if      VDHVGA
 
    if (OEMFlags&STARDUST_VGA)
    {
      /*
      ** Clear STARDUST's extended graphics register variables in
      ** environment. The corresponding hardware registers are
      ** automatically cleared when the sequencer registers are accessed
      */
 
      for (i = 0x00; i < 0x07; i++)
        Environment->Hardware.ExtVGARegs[i] = 0x00;

        /*
        ** Set 6-bit DAC mode 
        */
        Environment->Hardware.DACCmd &= 0x00;
 
      if (Flags&UPDATE_HARDWARE)
      {
        UCHAR byt;

        /*
        ** Set HW DAC if foreground 
        */
        RegAddress.DataPort = DACCmdReg;
        AccessRegister(&RegAddress, GET, &byt);
        byt &= ~0x02;
        AccessRegister(&RegAddress, SET, &byt);

        /*
        ** Unlock extended VGA graphics regs 
        */
        RegAddress.AddressPort = GraphAddressPort;
        RegAddress.DataPort = GraphDataPort;
        RegAddress.Flags = NONE;
        RegData.DataArea = &byt;
        RegData.FirstEntry = VGA_ENV_REG;
        RegData.NumEntries = 1;
        byt = VGA_UNLOCK;
        AccessHardware(&RegAddress, BYTES, NONE, SET, &RegData);
      } 
    } 
#endif
 
    for (i = 0,                        /* JumpCmd= FALSE,                 */
    Ind = Mode; Modes[Ind].ModeRegs[i].Command; i++)
    {                                  /* @MS17 */
 
      switch (Modes[Ind].ModeRegs[i].Command)
      {

#if      !(VDH8514A)                   /* @MS00 */

#if      VDHEGA        || VDHVGA     /* @MS00 */

/*
**  Set the attribute registers                                               
*/
        case  Attributes_CMD :
 
          if (Flags&UPDATE_HARDWARE)
          {
            RegAddress.AddressPort = AttAddressPort;
            RegAddress.DataPort = AttDataWritePort;
            RegAddress.ColorAdjust = NONE;
            RegAddress.Flags = Attributes_CMD;
          } 

/*
**  Enter Attribute registers into environment buffer                         
*/

          if (EnvBufferPassed)
 
            for (m = 0, 
                 k = Modes[Ind].ModeRegs[i].RegData.FirstEntry;
                 m < Modes[Ind].ModeRegs[i].RegData.NumEntries; 
                 k++, m++)

                Environment->Hardware.Attributes.All[k] = 
                Modes[Ind].ModeRegs[i].RegData.DataArea[k];

          break;

/*
**  Set the sequencer registers                                               
*/

        case  Sequencers_CMD :
 
          if (Flags&UPDATE_HARDWARE)
          {
            RegAddress.AddressPort = SeqAddressPort;
            RegAddress.DataPort = SeqDataPort;
            RegAddress.ColorAdjust = NONE;
            RegAddress.Flags = Sequencers_CMD;
          } 

/*
**  Enter Sequencer registers into environment buffer                         
*/

          if (EnvBufferPassed)
 
            for (m = 0, 
                 k = Modes[Ind].ModeRegs[i].RegData.FirstEntry;
                 m < Modes[Ind].ModeRegs[i].RegData.NumEntries; 
                 k++, m++)

              Environment->Hardware.Sequencers.All[k] = 
              Modes[Ind].ModeRegs[i].RegData.DataArea[k];

          break;

/*
**  Set the graphics registers                                                
*/

        case  Graphics_CMD :
 
          if (Flags&UPDATE_HARDWARE)
          {
            RegAddress.AddressPort = GraphAddressPort;
            RegAddress.DataPort = GraphDataPort;
            RegAddress.ColorAdjust = NONE;
            RegAddress.Flags = NONE;
          } 

/*
**  Enter Graphics registers into environment buffer                          
*/

          if (EnvBufferPassed)
 
            for (m = 0, 
                 k = Modes[Ind].ModeRegs[i].RegData.FirstEntry;
                 m < Modes[Ind].ModeRegs[i].RegData.NumEntries; 
                 k++, m++)

#if      VDHVGA
 
              if (k >= 0x40)
                     Environment->Hardware.ExtVGARegs[k-0x40] =
                       Modes[Ind].ModeRegs[i].RegData.DataArea[m];
 
              else
#endif
                     Environment->Hardware.GraphicsRegs[k] = 
                       Modes[Ind].ModeRegs[i].RegData.DataArea[k];
          break;
#endif    

/*
**  Set the CRT registers                                                     
*/

        case  CRTCtlRegs_CMD :
 
          if (Flags&UPDATE_HARDWARE)
          {

/*
**  If current cols = 132 then ensure proper register setup for 132 cols      
*/

#if      VDHVGA                      /*@D1085,@MS00                        */
 
            if (Modes[Mode].ModeRegs[i].RegData.DataArea[0x01] == 131)
            {                          /*@D1085                             */
 
//                        if (!SVGAPresent)
//                        {                        /* @drw */
 
                if (Environment->XGA_PRESENT == FALSE)  
                {                      /*@D1452                             */
                  SET132(Environment->Comp_Reg, 1);/*@D1085                 */
                }                      /* endif@D1452                       */
//                        }                        /* endif                             */
            }                          /* endif@D1085                       */
#endif    
            RegAddress.AddressPort = CRTAddressPort;
            RegAddress.DataPort = CRTDataPort;
            RegAddress.ColorAdjust = ColorAdjustment;
            RegAddress.Flags = NONE;
          } 

/*
**  Enter CRT registers into environment buffer                               
*/

          if (EnvBufferPassed)
 
            for (m = 0, 
                 k = Modes[Ind].ModeRegs[i].RegData.FirstEntry;
                 m < Modes[Ind].ModeRegs[i].RegData.NumEntries; 
                 k++, m++)

               Environment->Hardware.CRTCtlRegs.All[k] =
                 Modes[Ind].ModeRegs[i].RegData.DataArea[k];

          break;
#endif    

/*
**  Set the specified register                                                
**  (Port address is in 'FirstEntry' field of RegData                         
*/

        case  RegOutput_CMD :
 
          if (Flags&UPDATE_HARDWARE)
            RegAddress.DataPort = Modes[Ind].ModeRegs[i].RegData.FirstEntry;

#if      !(VDH8514A)                   /* @MS00 */
 
          if (EnvBufferPassed)
 
            switch (Modes[Ind].ModeRegs[i].RegData.FirstEntry)
            {

#if      VDHEGA        || VDHVGA     /* @MS00 */

              case  MiscOutputRegWrite:
                Environment->Hardware.MiscOutputReg = 
                *Modes[Ind].ModeRegs[i].RegData.DataArea;
                break;
#endif    

#if      VDHEGA                      /* @MS00 */

              case  Graphics1PosReg:
                Environment->Hardware.Graphics1Position = 
                *Modes[Ind].ModeRegs[i].RegData.DataArea;
                break;

              case  Graphics2PosReg :
                Environment->Hardware.Graphics2Position = 
                *Modes[Ind].ModeRegs[i].RegData.DataArea;
                break;

#endif                               /* VDHEGA */

#if      VDHCGA
              case  CGAModeCtlReg :
                Environment->Hardware.CGAModeControl = 
                *Modes[Ind].ModeRegs[i].RegData.DataArea;
                break;

              case  CGAColorSelReg :
                Environment->Hardware.CGAColorSelect = 
                *Modes[Ind].ModeRegs[i].RegData.DataArea;
                break;

#endif    

#if      VDHMPA                      /* @MS00 */

              case  CRTCtlPort1 :
                Environment->Hardware.MPAModeControl = 
                *Modes[Ind].ModeRegs[i].RegData.DataArea;
                break;

#endif    
            }                          /* End of inner Switch structure     */
#endif    
              break;

/*
**  Jump to a command under a different mode                                  
*/

      }                                /* End of outer Switch structure     */
 
      if (Flags&UPDATE_HARDWARE)
      {
        if (Modes[Ind].ModeRegs[i].Command == RegOutput_CMD)
        {
 
          if (Modes[Ind].ModeRegs[i].RegData.NumEntries == SETWORD)
          {                            /*                               @@B1*/
            AccessRegister(&RegAddress, SETWORD, 
            Modes[Ind].ModeRegs[i].RegData.DataArea);      /*           @@B1*/
          } 
 
          else
          {                            /*                               @@B1*/
            AccessRegister(&RegAddress, SET, 
            Modes[Ind].ModeRegs[i].RegData.DataArea);       /*          @@B1*/
          }                            /*                               @@B1*/

#if      !(VDH8514A)                   /* @MS00 */
        } 
 
        else
        {
          AccessHardware(&RegAddress, BYTES, ColorMode, SET, 
          &Modes[Ind].ModeRegs[i].RegData);

#if      VDHEGA        || VDHVGA     /* @MS00 */

/*
**  Setting attribute registers on a non-VGA turns video on again             
**  Turn the video off once again to reduce further snow                      
*/

          if (Modes[Ind].ModeRegs[i].Command == Attributes_CMD)
            AccessVideoEnable(ColorMode, SET, &VideoEnable);/* callgate     */
#endif    
#endif    
        } 
      } 
    } 

#if      VDHVGA                        /* @MS00 */
    CLUT = &MonoCLUT;                  /* Preset Mono CLUT as default for   */
                                       /* Mono modes                        */
    CLUTCount = MonoCLUTCount;         /* set size of this CLUT       @MS13 */
 
    if (Modes[Mode].fbType&NOT_MONO)
    {
      CLUT = &SumCLUT;                 /* Preset Summed CLUT as default for */
                                       /* Color modes @MS13                 */
      CLUTCount = SumCLUTCount;        /* set size of this CLUT      @MS13  */
 
      if (Modes[Mode].color == 8)
      {                                /* 256 color ?                @MS13  */
        CLUT = &SumCLUT256;            /* @MS13 */
        CLUTCount = SumCLUT256Count;   /* @MS13 */
      }                                /* @MS13 */
 
      else
 
        if (Modes[Mode].vres == 200)
        {                              /* low res ?                 @MS13  */
          CLUT = &SumCLUTLow;          /* @MS13 */
          CLUTCount = SumCLUTLowCount; /* @MS13 */
        }                              /* @MS13 */
 
      if ((!(VideoHardware.fVideoType&MONO_DISPLAYS))/* Not MONO displays   
                                                                   @T39,@T73*/
         && !(Flags&NO_CLR_BRST))
      {                                /* Not a B/W mode                    */
        CLUT = &ColorCLUT;             /* Use Color CLUT only for true      
                                          Color modes                       */
        CLUTCount = ColorCLUTCount;    /* set size of this CLUT     @MS13   */
 
        if (Modes[Mode].color == 8)
        {                              /* 256 color ?               @MS13   */
          CLUT = &ColorCLUT256;        /* @MS13 */
          CLUTCount = ColorCLUT256Count; /* @MS13 */
        }                              /* @MS13 */
 
        else
 
          if (Modes[Mode].vres == 200)
          {                            /* low res ?                  @MS13   */
            CLUT = &ColorCLUTLow;      /* @MS13 */
            CLUTCount = ColorCLUTLowCount; /* @MS13 */
          }                            /* @MS13 */
      } 
 
      else
      {                                /* set NO_CLR_BRST when using summed 
                                          color lookup table                */
 
        if (!(Environment->ModeData.fbType&GRAPHICS))
          Environment->ModeData.fbType |= NO_CLR_BRST;/*                @BB8*/
      } 
    } 
 
    if (Flags&UPDATE_HARDWARE)
    {
      ClutParms.DataArea = (UCHAR far *)CLUT;
      ClutParms.NumEntries = CLUTCount; /* @MS13 */
                                                                   /* @MS13 */
 
      for (i = 0; i < 0xFF+1; i += CLUTCount)
      {
        ClutParms.FirstEntry = i;
        AccessCLUT(SET, (CLUTDATA far *far *)&ClutParms);
      } 

      SetTextGrays(Environment);       /* @MS13 */
    } 

/*
**  Enter color lookup table into environment buffer                          
*/

    if (EnvBufferPassed)
    {
 
      for (i = 0x00; i < 0xFF+1; )
      {
 
        for (j = 0x00; j < 0x3F+1; i++, j++)
        {
          Environment->LookupTable[i] = CLUT[j];
        } 
      } 
    } 

#endif    

    rc = NO_ERROR;                     /*                               @T53*/

#if      FONT_SUPPORT                  /* @MS00 */

/*
**  Load the appropriate font                                                 
*/

    if (Flags&UPDATE_HARDWARE)
      rc = SetHWFont(Environment, Environment->ActiveFontPTR, 
           (UCHAR far *) PHYSICAL_FONT_BUFFER);        /*               @T53*/

#endif    

#if      !(VDH8514A)                   /* @MS00 */

/*
**  Turn the video signal back on                                             
*/

    if ((Flags&UPDATE_HARDWARE) && VideoOn)
    {                                  /*                               @C21*/
      VideoEnable = 1;                 /* Turn video on                     */
      AccessVideoEnable(ColorMode, SET, &VideoEnable);/* ring 2 callgate    */
    } 

#endif    

    return (rc);                       /*                               @T53*/
  } 

/*****************************************************************************
 *                                                                          
 *  SUBROUTINE NAME: SetEnvMode                                             
 *                                                                          
 *  DESCRIPTIVE NAME: Set the envrionment mode                              
 *                                                                          
 *  FUNCTION: SetEnvMode is called to update the environment buffer         
 *            with the current video mode.                                  
 *                                                                          
 *  ENTRY POINT: SetEnvMode                                                 
 *    LINKAGE:   CALL FAR                                                   
 *                                                                          
 *  INPUT: (Passed on stack)                                                
 *             UCHAR Mode ( Index in table of supported modes )             
 *             FAR * Environment ( far pointer to environment buffer )      
 *             FAR * HWEnvironment (pointer to hardware state buffer)       
 *         (Referenced)                                                     
 *             Modes[] (global data - table of supported video modes )      
 *                                                                          
 *  EXIT-NORMAL: Environment buffer is updated to reflect HW state          
 *                                                                          
 *  EFFECTS: NONE                                                           
 *                                                                          
 *  INTERNAL REFERENCES:                                                    
 *    ROUTINES: NONE                                                        
 *                                                                          
 *  EXTERNAL REFERENCES:                                                    
 *    ROUTINES: NONE                                                        
 *                                                                          
 ****************************************************************************/


  void PASCAL near SetEnvMode(Mode, Environment, HWEnvironment, GetMode)
                                                              
  UCHAR Mode;
  ENVIRONMENT far *Environment;
  ENVIRONMENT far *HWEnvironment;
  USHORT GetMode;                      /*                               @T70*/

  {
    int i;
    UCHAR far *Source;
    UCHAR far *Destination;
    VIDEOMODE far *pCurMode;           /* Reduce level of indirection,   @S8*/

#if      !(VDH8514A)                   /* @MS00 */

/*
**  Update environment buffer with current hardware state                     
*/

    if (HWEnvironment)
    {
      Source = (UCHAR far *)&HWEnvironment->Hardware;
      Destination = (UCHAR far *)&Environment->Hardware;
 
      for (i = 0; i < sizeof(HWREGS); i++)
      {
        Destination[i] = Source[i];
      } 
    } 

#endif    
 
    if (GetMode)
    {                                  /*                               @T70*/

      pCurMode = (VIDEOMODE far *)&Modes[Environment->ModeIndex = Mode].cb;
      Environment->ModeData.cb = pCurMode->cb;
      Environment->ModeData.fbType = pCurMode->fbType;
      Environment->ModeData.color = pCurMode->color;
      Environment->ModeData.col = pCurMode->col;
      Environment->ModeData.row = pCurMode->row;
      Environment->ModeData.hres = pCurMode->hres;
      Environment->ModeData.vres = pCurMode->vres;
      Environment->ModeData.fmt_ID = pCurMode->fmt_ID;
      Environment->ModeData.attrib = pCurMode->attrib;

      Environment->ModeData.BufferAddress = 
        MemoryMaps[pCurMode->MemMap].Start.FullAddress;

      Environment->ModeData.BufferLength = 
        MemoryMaps[pCurMode->MemMap].TotalSize;
 
      if (pCurMode->MemMap == MemMap_LoRes)  /*                        @@TB9*/
        Environment->ModeData.BufferLength = 16000;

      Environment->ModeData.FullBufferSize = 
         Environment->ModeData.BufferLength;

      Environment->ModeData.PartialBufferSize = (ULONG)4000;
      Environment->ModeData.ExtDataArea = (UCHAR far *)NULL;

#if      FONT_SUPPORT                  /* @MS00 */
 
      if (!(pCurMode->fbType&GRAPHICS))
      {
        Environment->ModeData.FullBufferSize += (ULONG)256*(ULONG)
           (Environment->ModeData.vres/Environment->ModeData.row);
      } 

      Environment->ROMFontIndex = pCurMode->ROMFontIndex;

#endif    
    }                                  /*                               @T70*/
  } 

#if      VDHVGA                        /* Read/write hardware               */
                                        /* @MS00 */

/*****************************************************************************
 *                                                                             
 *  SUBROUTINE NAME: GetModeIndex                                              
 *                                                                             
 *  DESCRIPTIVE NAME: Determine video mode from registers                      
 *                                                                             
 *  FUNCTION: GetModeIndex returns the index in the table of modes             
 *            that corresponds to the current hardware setting.                
 *                                                                             
 *  ENTRY POINT: GetModeIndex                                                  
 *    LINKAGE:   CALL FAR                                                      
 *                                                                             
 *  INPUT: (Passed on stack)                                                   
 *             FAR * Environment ( Registers that have been read )             
 *         (Referenced)                                                        
 *             Modes[] ( table of supported video modes )                      
 *                                                                             
 *  EXIT-NORMAL: AX = mode table index + 1                                     
 *                                                                             
 *  EXIT-ERROR:  AX = 0                                                        
 *                                                                             
 *  EFFECTS: NONE                                                              
 *                                                                             
 *  INTERNAL REFERENCES:                                                       
 *    ROUTINES: NONE                                                           
 *                                                                             
 *  EXTERNAL REFERENCES:                                                       
 *    ROUTINES: AccessCLUT                                                     
 *                                                                             
 ****************************************************************************/


  USHORT PASCAL near GetModeIndex(Environment)/*                        @B15*/

  ENVIRONMENT far *Environment;
  {
    USHORT i,MODE_FOUND;
    VIDEOMODE far *pCurMode;           /* Reduce level of indirection,   @S8*/
    FarAddress PhysAddress1;           /*                               @C29*/
    VIDEO_BIOS far *BiosData;          /*                               @C29*/

/*
**  An examination of just 4 registers is all that is needed to determine   
**  which of the supported mode is currently set.  If an unknown mode is    
**  set, an error is returned.  The registers examined are:                 
**                  - Miscellaneous Output Register                         
**                  - Attribute Mode Control Register                       
**                  - Attribute Color Plane Enable Register                 
**                  - Sequencer Clocking Mode Register                      
*/
                                                                            

    for (i = 0, MODE_FOUND = FALSE; (i < NUM_MODES) && !MODE_FOUND; i++)
    {                                  /* @MS12 */

      pCurMode = (VIDEOMODE far *)&Modes[i].cb;/*                        @S8*/
 
      if ((Environment->Hardware.MiscOutputReg == pCurMode->CompRegs[0]) && 
         ((Environment->Hardware.Attributes.Regs.ModeControl&~BLINK_BIT) == 
         (pCurMode->CompRegs[1]&~BLINK_BIT)) && 
         (Environment->Hardware.Attributes.Regs.ColorPlane == 
         pCurMode->CompRegs[2]) && 
         (Environment->Hardware.Sequencers.Regs.ClockingMode == 
         pCurMode->CompRegs[3]))

        MODE_FOUND = TRUE;
    } 

/*
**  If no mode is found, if Protect mode use modeindex from environment
**  ELSE GET MODE FROM BIOS DATA AREA                                     
*/

    if (!MODE_FOUND)
    {                                  /*                          @C29START*/
      i = Environment->ModeIndex;
      i++;
    }                                  /*                            @C29END*/
 
    if ((i == ModeIndex_VGC7p+1) &&    /*                               @T71*/
       (VideoHardware.fVideoType&VGM_BIT))
    {                                  /*                               @T71*/
      i++;                             /* Return mono mode index on a mono  
                                          plasma display                @T71*/
    }                                  /*                               @T71*/

    return (i);
  } 

#endif    


