/*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 = VDHFONT.c
 *
 * DESCRIPTIVE NAME = Base video device handlers - Font support
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION   This source file contains VDH entry points which get/set
 *               the current font.
 *
 * FUNCTIONS     GetCurrentFont, SetCurrentFont, SetHWFont, FindFont
 *
 * NOTES
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES  SaveRegs, RestoreRegs
 *                      AccessHardware, AccessFont
 *
 * EXTERNAL FUNCTIONS
 *
*/


/*
**  Include files
*/

#define  INCL_BASE                     /* ALL of OS/2 Base                  */
#define  INCL_OS2STD                   /* Needed for NULL definition in     */
                                       /* OS2STD.H                          */
#define INCL_NOPMAPI                   /* @95837 */

#include <os2.h>
#include "vdhctl.h"                    /* Conditional compilation control   */
#include "vdh.h"                       /* Type definitions                  */

#if      FONT_SUPPORT                  /*                               @S26*/
                                       /* MS00                              */


/*
**  Externally defined global variables
*/

extern VIDEOMODE Modes[];              /* Supported modes                   */
extern FONTBUFFER Fonts[];             /* Supported fonts                   */
extern UCHAR READABLE;                 /* Flag to determine if hardware is
                                          write-only                        */
extern rcp_addr RomCP_tbl;             /* table for CP and ROM font info
                                                                        @C10*/
extern USHORT ROMCP_NUM;

/*****************************************************************************
 *
 *  SUBROUTINE NAME: GetCurrentFont
 *
 *  DESCRIPTIVE NAME: Get color lookup table
 *
 *  FUNCTION: GetCurrentFont is called by BVS to return the current
 *            active video font.
 *
 *  ENTRY POINT: GetCurrentFont
 *    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 GetCurrentFont(Environment,ParmBlock,Function)

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

{

  FarAddress FontBuffer1,FontBuffer2,VideoFontBuffer;

  USHORT rc,i,PelRows,FontSize,EnvBufferPassed,hres,vres,col,row,FONT_FOUND;
  ENVIRONMENT far *TempEnv;
  UCHAR TempChar;                      /*         @TB21FORSAVINGROMFONTINDEX*/
  SEL Selector;
  UCHAR Mode,far *SourcePtr,*BasePtr;
  USERFONT far *USERFont;
  ROMCP_TABLE *rcp_tbl_ptr;            /*                               @C10*/

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

  if (EnvBufferPassed)
  {

    if ((Function == FnGetFont) &&     /* Valid function request            */
       (ParmBlock->Length >= sizeof(VDH_FONT)) && /* Valid Length           */
       (ParmBlock->Flags <= 3))
    {                                  /* Valid flags                       */
      rc = ERROR_VIO_MODE;             /*                               @T11*/

      if (!(Environment->ModeData.fbType & GRAPHICS) || /* Text mode?   @T11*/
         (ParmBlock->Flags & GET_ROM_FONT))
      {                                /* Get ROM font?                 @T11*/
        rc = NO_ERROR;                 /* Parameters are OK                 */
        Mode = Environment->ModeIndex;

  #if      VDHVGA                      /* Get mode from hardware, if it is  */
                                       /* readable                          */

        if (ParmBlock->Flags == UPDATE_HARDWARE)
        {                              /* Not for Specified Font            */

          if (!(rc = DosAllocSeg(sizeof(ENVIRONMENT), (PSEL)&Selector, 0)))
          {
            TempEnv = (ENVIRONMENT far *)MakeFarPTR(Selector, 0);
            TempEnv->VideoEnable = 1;  /* Assume video ON               @T34*/
            SaveRestoreHW(TempEnv, GET);/* Read hardware into temporary     */
                                        /* ENVB                             */
            Mode = (UCHAR)GetModeIndex(TempEnv);/* Get mode index + 1       */

            if (!Mode--)
              rc = ERROR_VIO_MODE;

            else
              SetEnvMode(Mode, Environment, TempEnv, 0);/* Update ENVB  @T70*/
                                       /* end                          @TB21*/

            DosFreeSeg(Selector);      /* Deallocate the temporary ENVB     */

          }
        }
  #endif          /*      VDHVGA   @MS00                                    */

        PelRows = ParmBlock->PelRows;

        if (ParmBlock->Flags == UPDATE_HARDWARE)
        {                              /* Not for Specified Font            */
          PelRows = Environment->ModeData.vres/Environment->ModeData.row;
        }

        FontSize = 256*PelRows;

        if (!rc)
        {

          if ((ParmBlock->FontLength == NULL) && /* Return font size only   */
             (ParmBlock->FontBuffer == NULL))
          {                            /*                               @T11*/
            ParmBlock->FontLength = FontSize;
          }

          else
            if (ParmBlock->FontLength < FontSize)
            {
              rc = ERROR_VIO_INVALID_PARMS;/*                          @TB38*/
            }

            else
            {                          /* Return complete font information  */

              if (ParmBlock->Flags == UPDATE_HARDWARE)
              {                        /* Hardware font                     */
                ParmBlock->PelColumns = Modes[Mode].hres/Modes[Mode].col;
                ParmBlock->PelRows = PelRows;
                ParmBlock->FontLength = FontSize;/* in case too much        */
                                       /* specified                         */

                if (!(rc = PhysToUVirt(Fonts[0].PVB, &VideoFontBuffer,
                           Fonts[0].PVBLen)))
                {                      /*                               @T53*/

                  AccessFont(VideoFontBuffer.FullAddress,
                             ParmBlock->FontBuffer, ParmBlock->PelRows,
                             0, (UCHAR far *)NULL, GET,
                             (UCHAR)(Modes[Mode].fbType & NOT_MONO));

                  FreePhysToUVirt(VideoFontBuffer.part.Selector);

                }                      /*                               @T53*/

/*
**      PTM 2895  start of code changes
**  add code to find specific fonts - first check user fonts for a
**  row/column match, then current codepage then ROM fonts
*/

              }

              else
              {
                FONT_FOUND = FALSE;

/*
**  check UserFonts if they are Selectable for Row/Column match
*/

                if (Environment->UserFont == USER_FONT_SELECTABLE)
                {
                  USERFont = (USERFONT far *)&Environment->USERFonts;

                  for (i = 0; (FONT_FOUND == FALSE) &&
                      (i < Environment->NumUSERFonts); i++)
                  {

                    if ((USERFont->PelRows == ParmBlock->PelRows) &&
                       (USERFont->PelColumns == ParmBlock->PelColumns))
                    {
                      FONT_FOUND = U_FONT;
                      SourcePtr = (UCHAR far *)&USERFont->FontData;
                      BasePtr = NULL;
                    }

                    else
                      (ULONG)USERFont = (ULONG)(&USERFont->FontData) + (ULONG)
                         (USERFont->PelRows * 256);

                  }
                }

/*
** Userfont not found, check current CodePage if not ROM fonts
*/

                if ((FONT_FOUND == FALSE) && (Environment->CodePageID !=
                   ROM_FONT))
                {

/*                                                    @C10 START OF CHANGES */

                  rcp_tbl_ptr = RomCP_tbl.ptr;/* find codepage in ROMCP_TBL */

              /*  @B725179                                                  */

  #if      VDHEGA                      /* Make sure PelRows parm doesn't
                                          exceed 14 for EGA                 */

                  if ((Environment->CodePageID == rcp_tbl_ptr->CodePageID) &&
                     (ParmBlock->PelRows <= 14))
                  {
  #endif          /*  VDHEGA Make sure parms do not exceed 8x14 fonts       */

                    for (i = 0; i < ROMCP_NUM && !FONT_FOUND; i++)
                    {

                      if ((Environment->CodePageID == rcp_tbl_ptr->CodePageID)
                         && (rcp_tbl_ptr->PelRows == ParmBlock->PelRows)
                         && (rcp_tbl_ptr->PelColumns == ParmBlock->PelColumns))
                      {
                        FONT_FOUND = C_FONT;/* codepage font found          */
                        SourcePtr = rcp_tbl_ptr->FontPTR;/* check if        */
                                                         /* override font   */

                        if (rcp_tbl_ptr->PelColumns == 9)
                          BasePtr = rcp_tbl_ptr->BaseFontPTR;

/*                                                               @C10 END  */
                        else
                          BasePtr = NULL;
                      }

                      else
                        rcp_tbl_ptr++; /*                               @C10*/
                    }
                  }                    /* end to check for codepage         */

  #if      VDHEGA                      /* Make sure PelRows parm doesn't
                                          exceed 14 for EGA                 */
                }
  #endif                               /*  VDHEGA                           */

/*
** if codepage font not found or current codepage is ROM fonts
** try looking for a match in the ROM fonts
*/

                if (FONT_FOUND == FALSE)
                {

                  for (i = ROMFont8x8; i <= ROM_FONTS && !FONT_FOUND; i++)/*
                                                                        @C10*/
                  {

                    if ((Fonts[i].PelRows == ParmBlock->PelRows) && /*  @C10*/
                       (Fonts[i].PelColumns == ParmBlock->PelColumns))/*
                                                                        @C10*/
                    {
                      FONT_FOUND = R_FONT;/* ROM font found                 */

                      if (!(PhysToUVirt(Fonts[i].PVB, /*      @C10,@T30,@T53*/
                         &FontBuffer1, FontSize)))
                      {

                        SourcePtr = FontBuffer1.FullAddress;/* check if     */
                                                            /* override font*/

                        if (Fonts[i].PelColumns == 9)/*                 @C10*/
                        {
                          i = Fonts[i].Partner;/*                       @C10*/

                          if (!(PhysToUVirt(Fonts[i].PVB, /*  @C10,@T30,@T53*/
                             &FontBuffer2, FontSize)))
                          {
                            BasePtr = FontBuffer2.FullAddress;
                          }            /*                               @T53*/

                          else         /*                               @T53*/
                            FONT_FOUND = FALSE;/*                       @T53*/
                        }

                        else
                          BasePtr = NULL;
                      }                /*                               @T53*/

                      else             /*                               @T53*/
                        FONT_FOUND = FALSE;/*                           @T53*/
                    }
                  }
                }                      /* end to search thru ROM fonts      */

                if (FONT_FOUND)        /* get font in buffer                */
                {
                  AccessFont(SourcePtr, ParmBlock->FontBuffer,
                     ParmBlock->PelRows, ParmBlock->PelColumns, BasePtr,
                     GET_ROMCP, (UCHAR)(Modes[Mode].fbType & NOT_MONO));

                  if (FONT_FOUND == R_FONT)
                  {
                    FreePhysToUVirt(FontBuffer1.part.Selector);
                    FreePhysToUVirt(FontBuffer2.part.Selector);
                  }
                }

                else                   /* no font found, return error       */
                  rc = ERROR_VIO_FONT;

/*
**      PTM 2895  end of code changes
*/

              }
            }
        }
      }
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SetCurrentFont
 *
 *  DESCRIPTIVE NAME: Set color lookup table
 *
 *  FUNCTION: SetCurrentFont is called by BVS to load the specified
 *            video text font
 *
 *  ENTRY POINT: SetCurrentFont
 *    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 SetCurrentFont(Environment,ParmBlock,Function)

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

{
  FarAddress VideoFontBuffer;
  USHORT rc,rc2,i,FontLength,USERFONT_NOT_FOUND,EnvBufferPassed;
  ENVIRONMENT far *TempEnv;
  SEL Selector;
  UCHAR Mode;
  VIOMODEINFO ModeData;
  USERFONT far *USERFont;              /* Pointer to an entry in the USER   */
                                       /* font table                        */
  ULONG NewSize;

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

#if     VDHVGA
  if ((Function == FnSetFont) &&       /* Valid function request            */
     (EnvBufferPassed) &&
     (Environment->SVGAMode & MODE_SVGA_ENVFLAG) &&
     (ParmBlock->Flags & 4) &&
     (ParmBlock->Length >= sizeof(VDH_FONT)))
  {
    Environment->PelRows = ParmBlock->PelRows;
    Environment->PelColumns = ParmBlock->PelColumns;
    return(NO_ERROR);
  }
#endif
  if ((Function == FnSetFont) &&       /* Valid function request            */
     (ParmBlock->Length >= sizeof(VDH_FONT)) && /* Valid Length             */
     (ParmBlock->PelRows >= 1) &&      /* Valid rows                   @TB36*/
     (ParmBlock->PelRows <= MAX_FONT_SIZE) && /* Valid rows MS08            */
     (ParmBlock->PelColumns >= 1) &&   /* Valid cols                   @TB36*/
     (ParmBlock->PelColumns <= 9) &&   /* Valid cols                   @TB36*/
     (ParmBlock->Flags <= 1) &&        /* Valid flags                       */
     (EnvBufferPassed))
  {
    rc = ERROR_VIO_MODE;               /* Preset invalid mode               */

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

/*
**  Get current mode to determine if current mode is text, and also to
**  verify that this font is applicable to this mode.
*/

      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);


/*
**  If "foreground", get the mode directly from the hardware
*/

          TempEnv->VideoEnable = 1;    /* Assume video ON               @T34*/
          SaveRestoreHW(TempEnv, GET); /* Read hardware                     */
          Mode = (UCHAR)GetModeIndex(TempEnv);/* Get mode index + 1         */

          if (!Mode--)
            rc = ERROR_VIO_MODE;

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

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

      else

/*
**  If "background", get the mode from the environment buffer
*/

        Mode = Environment->ModeIndex;

      if (!rc)
      {

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

        else

          if ((Modes[Mode].vres/Environment->ModeData.row !=
             ParmBlock->PelRows) || (Modes[Mode].hres/Modes[Mode].col !=
             ParmBlock->PelColumns))


/*
**  The specified font is not compatible with the current mode:
**  Return an error but save the font for use later, in another mode
*/

            rc = ERROR_VIO_USER_FONT;

        if (!rc || rc == ERROR_VIO_USER_FONT)
        {


/*
**  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 = (USERFONT far *)&Environment->USERFonts;/* Begining of   */
                                                           /* USER font table */

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

            if ((USERFont->PelRows == ParmBlock->PelRows) &&
               (USERFont->PelColumns == 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->FontData) + (ULONG)
                                (USERFont->PelRows * 256);

          if (USERFONT_NOT_FOUND)
          {


/*
**  Add the USER font to the USER font table
*/

            NewSize = (ULONG)(OFFSET(USERFont->FontData) + FontLength);


/*
**  Let's limit, for now, the number of USER fonts that can be stored to the
**  amount that can fit, along with the environment buffer, in 1 64k segment
*/

            if (NewSize > 0xFFFFL || !(rc2 = DosReallocHuge(0,(USHORT)NewSize,
                SEG(Environment))))
            {
              USERFont->PelColumns = ParmBlock->PelColumns;
              USERFont->PelRows = ParmBlock->PelRows;
              ++Environment->NumUSERFonts;
            }

            else
            {

/*
**  For now, if the table gets filled up to 64k - size of environment buffer,
**  return an error.  In the future, allocate another huge segment, or
**  overwrite another entry in the table.
**
**  Also in the future, it would be nice to remove specified entry from the
**  table ( reshuffle the entries and shrink the table )
*/

              rc = rc2 ? rc2 : ERROR_NOT_ENOUGH_MEMORY;
            }
          }


/*
**  Put the new entry in the USER font table
*/

          if (!rc || rc == ERROR_VIO_USER_FONT)
          {

            for (i = 0; i < FontLength; i++)
              ((UCHAR far *)&USERFont->FontData)[i] = ParmBlock->FontBuffer[i];

            Environment->UserFont = USER_FONT_SELECTABLE;

            if (!rc)

              if (ParmBlock->Flags&UPDATE_HARDWARE)


/*
**  Load specified font
*/

                rc = SetHWFont(Environment, (UCHAR far *)&USERFont->FontData,
                     (UCHAR far *)PHYSICAL_FONT_BUFFER);/*             @T53*/

              else
                Environment->ActiveFontPTR = (UCHAR far *)&USERFont->FontData;
          }
        }
      }
    }
  }
  return (rc);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SetHWFont
 *
 *  DESCRIPTIVE NAME: Set the ROM, USER or CODE PAGE font
 *
 *  FUNCTION: SetHWFont is called to set the font to correspond with
 *            the current video mode.  If a USER font is available,
 *            it will be loaded.  Otherwise, if a code page is
 *            available, it will be loaded.  If neither a USER font or
 *            Code Page font is available, a ROM font will be loaded.
 *
 *  ENTRY POINT: SetHWFont
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR * Environment
 *             FAR * USERFontBuffer (explicit source ptr)
 *             FAR * DestinationBuffer (explicit target ptr)
 *         (Referenced)
 *             Modes[] (global data - table of supported video modes )
 *             Fonts[] (global data - table of ROM font areas )
 *
 *  EXIT-NORMAL: An appropriate font is loaded
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: PhysToUVirt, FreePhysToUVirt
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: AccessFont
 *
 ****************************************************************************/

USHORT PASCAL near SetHWFont(Environment,USERFontBuffer,DestinationBuffer)
                                                              /* @B15,@T53 */
  ENVIRONMENT far *Environment;
  UCHAR far *USERFontBuffer;
  UCHAR far *DestinationBuffer;

{

  USHORT CellCols,CellRows,ColorMode,VideoBufferSEL,CodePageIndex,Selector,
         Direction,i,rc;              /*                               @T53*/

  REGADDRESS RegAddress;
  REGDATA RegData;
  FarAddress ROMFontBuffer;
  UCHAR ByteData;
  UCHAR far *FontBuffer;
  UCHAR far *Destination;
  UCHAR far *BaseFontPTR;
  rcp_addr rcp_tbl;                    /*                               @C10*/

  rc = NO_ERROR;                       /*                               @T53*/

  if (!(Environment->ModeData.fbType&GRAPHICS))
  {                                    /* Text mode only                    */
#if     VDHVGA
    if ((Environment->SVGAMode & MODE_SVGA_ENVFLAG) &&                  /*            */
        Environment->PelRows &&
        Environment->PelColumns)
    {
      CellRows = Environment->PelRows;
      CellCols = Environment->PelColumns;
    }
    else
#endif
    {
    CellCols = Environment->ModeData.hres/Environment->ModeData.col;
    CellRows = Environment->ModeData.vres/Environment->ModeData.row;
    }


/*
**  Set up the Destination ptr for the font
*/

    if (DestinationBuffer)
    {
      Destination = DestinationBuffer; /* Use explicit target ptr, if       */
                                       /* specified                         */
    }

    else
    {
      rc = PhysToUVirt(Fonts[0].PVB, (FarAddress *)&Destination,
           Fonts[0]. PVBLen);          /*                          @T30,@T53*/
    }


/*
**  USERFontBuffer is Direction of Move, if 0:1.
*/

    if ((Direction = (USHORT)USERFontBuffer) == GET)
    {
      USERFontBuffer = NULL;
    }

    else
    {
      Direction = SET;
    }

    BaseFontPTR = (UCHAR far *)NULL;


/*
**  Set up the FontBuffer source ptr for the font
*/

    if (!rc && USERFontBuffer && (USERFontBuffer != (UCHAR far *)CP_FONT))
    {                                  /* C10,@T53                          */

      FontBuffer = USERFontBuffer;     /* Use explicit source ptr, if       */
                                       /* specified                         */

      Environment->ActiveFontPTR = USERFontBuffer;/*                    @C10*/

      if (SEG(Environment) == SEG(FontBuffer))
      {                                /*                               @S31*/
        CellRows = *(((USHORT *)FontBuffer)-1);/*                       @S31*/
      }                                /*                               @S31*/
    }

    else

      if (!rc)
      {                                /*                               @T53*/
                                       /* Use codepage font, if active      */

        if (Environment->ActiveFontPTR == (UCHAR far *)CP_FONT)
        {                              /*                               @C10*/
          rcp_tbl.ptr = RomCP_tbl.ptr; /*                               @C10*/
          rcp_tbl.p.Offset = Environment->ROMFontIndex *sizeof(ROMCP_TABLE);
                                       /*                               @C10*/
          FontBuffer = rcp_tbl.ptr->FontPTR;/*                          @C10*/
        }

        else
        {

          if (!(rc = PhysToUVirt(Fonts[Environment->ROMFontIndex].PVB,
             &ROMFontBuffer,Fonts[Environment->ROMFontIndex].PVBLen)))
          {
            FontBuffer = ROMFontBuffer.FullAddress;/* Use the ROM font as   */
                                                   /* default               */
          }                                        /*                   @T53*/
        }


/*
**  Set up the BaseFontPTR, if this font overrides some other font
*/

        if (!rc && CellCols == 9)
        {                              /*                               @T53*/

          if (Environment->ActiveFontPTR == (UCHAR far *)CP_FONT)/*     @C10*/
          {                            /*                               @C10*/
            CellRows = rcp_tbl.ptr->PelRows; /*   @MS10                     */

            if (rcp_tbl.ptr->PelColumns == 8)/*                         @C10*/
              CellCols = 8;            /*                               @C10*/

            else                       /*                               @C10*/
              BaseFontPTR = rcp_tbl.ptr->BaseFontPTR;/*                 @C10*/
          }

          else
          {                            /*                               @C10*/
            CellRows = Fonts[Environment->ROMFontIndex].PelRows; /*  @MS10  */

            if (Fonts[Environment->ROMFontIndex].PelColumns == 8)/*      @C2*/
              CellCols = 8;            /*                                @C2*/

            else                       /*                                @C2*/
            {                          /*                                @C2*/
              i = Fonts[Environment->ROMFontIndex].Partner;/*           @C10*/
              rc = PhysToUVirt(Fonts[i].PVB, (FarAddress *)&BaseFontPTR, Fonts
                 [i].PVBLen);          /*                          @T30,@T53*/
            }
          }                            /*                                @C2*/
        }
      }


/*
**  Move the font to its destination
*/

    if (!rc)
    {                                  /*                               @T53*/
      AccessFont(FontBuffer, Destination, CellRows, CellCols, BaseFontPTR,
         Direction, (UCHAR)(Environment->ModeData.fbType&NOT_MONO));
    }                                  /*                               @T53*/


/*
**  Get rid of the temporary selectors allocated by this routine
*/

    if (!DestinationBuffer)
    {
      FreePhysToUVirt((*(FarAddress *)&Destination).part.Selector);/* Free  */
                                      /*  the physical font selector        */
    }

    if (!USERFontBuffer)
    {                                  /*                               @C10*/
      FreePhysToUVirt(ROMFontBuffer.part.Selector);/* Free the base         */
                                       /* selector                          */

      if (BaseFontPTR)
      {
        FreePhysToUVirt((*(FarAddress *)&BaseFontPTR).part.Selector);
                                       /* Free the Base font selector   @T30*/
      }
    }

    if (!rc)
#if     VDHVGA
    if (!(Environment->SVGAMode & MODE_SVGA_ENVFLAG))         /*            */
#endif
      SetHWFontRegs(Environment, CellRows);
  }
  return (rc);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SetHWFontRegs
 *
 *  DESCRIPTIVE NAME: Set the h/w regs to match the corresponding font
 *
 *  FUNCTION: Call by SetHWFont to adjust appropriate h/w regs.
 *
 *  ENTRY POINT: SetHWFontRegs
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR * Environment
 *             USHORT CellRows (0 if not supplied)
 *
 *  EXIT-NORMAL: Appropriate regs are updated
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: AccessHardware
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: None
 *
 ****************************************************************************/

void PASCAL near SetHWFontRegs(Environment,CellRows)

  ENVIRONMENT far *Environment;
  USHORT CellRows;

{

  USHORT ColorMode;
  REGADDRESS RegAddress;
  REGDATA RegData;
  UCHAR ByteData;


  if (!CellRows)
    CellRows = Environment->ModeData.vres / Environment->ModeData.row;


/*
**  Adjust the registers for a number of rows different from the default
*/

  ColorMode = Environment->ModeData.fbType & NOT_MONO;
  RegAddress.AddressPort = CRTAddressPort;
  RegAddress.DataPort = CRTDataPort;
  RegAddress.ColorAdjust = ColorAdjustment;
  RegAddress.Flags = NONE;
  RegData.DataArea = (UCHAR far *)&ByteData;
  RegData.NumEntries = 1;


/*
**  Adjust the underline register
*/

  if (ColorMode == FALSE)
  {
    RegData.FirstEntry = 0x14;         /* Underline location only           */
    ByteData = (UCHAR)CellRows-1;
    AccessHardware(&RegAddress, BYTES, ColorMode, SET, &RegData);
  }

  RegData.FirstEntry = 0x09;           /* Maximum scan line only            */
  ByteData = ((UCHAR)CellRows-1);

  #if      VDHVGA                      /*    @MS00                          */


/*
**  Adjust the maximum scan line if CGA emulation
*/

  if (Environment->ModeData.vres == 200)
    ByteData |= (Environment->Hardware.CRTCtlRegs.All
                [RegData.FirstEntry]&0xE0 );

  #endif            /*    VDHVGA         @MS00                              */

  AccessHardware(&RegAddress, BYTES, ColorMode, SET, &RegData);
  RegData.FirstEntry = 0x12;           /* Vertical display enable end only  */
  ByteData = (UCHAR)(CellRows *Environment->ModeData.row);

  #if      VDHVGA                /*       @MS00                             */


/*
**  Adjust the vertical display enable end if CGA emulation
*/

  if (Environment->ModeData.vres == 200)/* Turn 200 lines to 400 lines      */
    ByteData <<= 1;

  #endif            /*     VDHVGA  @MS00                                    */

  if (!(Environment->EnvFlags & SAVEREST_VDM))            /*                */
  {
   ByteData--;
   AccessHardware(&RegAddress, BYTES, ColorMode, SET, &RegData);
  }

}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: FindFont
 *
 *  DESCRIPTIVE NAME: Determine if a font is available to support
 *                    the specified mode.
 *
 *  FUNCTION: Determine if either a ROM font or a USER font is
 *            available to support the specified mode.
 *
 *  ENTRY POINT: FindFont
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             USHORT ModeIndex  ( Index in mode table )
 *             USHORT Rows       ( Number of text rows desired )
 *         (Referenced)
 *             Modes[] ( table of supported video modes )
 *
 *  EXIT-NORMAL: AX = FontIndex if an appropriate font is available
 *               AX = 0 if an appropriate font is not available
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 ****************************************************************************/

UCHAR PASCAL near FindFont(ModeIndex,Rows,Environment)/*                @B15*/

  USHORT ModeIndex;
  USHORT Rows;
  ENVIRONMENT far *Environment;

{

  UCHAR i,FONT_AVAILABLE;
  USHORT PelColumns,PelRows, Vres;                              /*            */
  SHORT j;                             /*                               @C10*/
  USERFONT far *USERFont;              /* Pointer to an entry in the USER   */
                                       /* font table                        */
  ROMCP_TABLE *rcp_tbl_ptr;            /*                               @C10*/

  FONT_AVAILABLE = FALSE;
#if     VDHVGA
  if ((Environment->SVGAMode & MODE_SVGA_ENVFLAG) &&               /*            */
     (Environment->PelRows) && (Environment->PelColumns))
  {
    Vres =      Environment->ModeData.vres;
    PelRows =   Environment->PelRows;
    PelColumns =Environment->PelColumns;
  }
  else
#endif
  {
    Vres =      Modes[ModeIndex].vres;
    PelRows =   Vres/Rows;
    PelColumns =Modes[ModeIndex].hres/Modes[ModeIndex].col;
  }
  if (Environment->UserFont == USER_FONT_SELECTABLE)
  {
    USERFont = (USERFONT far *)&Environment->USERFonts;/* Begining of USER  */
                                                       /* font table        */

    for (j = 0; (FONT_AVAILABLE == FALSE)/* Start of             @S26CHANGES*/
         && (j < Environment->NumUSERFonts); j++)
    {

      if ((USERFont->PelColumns == PelColumns) &&
         ((USERFont->PelRows == PelRows) ||                   /*        @S31*/
         (Vres/USERFont->PelRows == Rows)))                   /*            */

      {                                /*                               @S31*/
        FONT_AVAILABLE = TRUE;         /* Valid Mode/Font combination found */
        Environment->ActiveFontPTR = (UCHAR far *)&USERFont->FontData;
      }

      else
      {
        (ULONG)USERFont = (ULONG)(&USERFont->FontData) + (ULONG)
           (USERFont->PelRows * 256);   /* Next font                         */
      }
    }                                  /* End of                 @S26CHANGES*/
  }

/*
** Check CodePage font table if CodePages available
*/

  if (!FONT_AVAILABLE && (Environment->CodePageID != ROM_FONT))
  {                                    /*                                @C7*/
    rcp_tbl_ptr = RomCP_tbl.ptr;       /*                               @C10*/

    for (j = 0; j < ROMCP_NUM && !FONT_AVAILABLE; j++)/*                @C10*/
    {                                  /*                               @C10*/

      if (Environment->CodePageID == rcp_tbl_ptr->CodePageID && /*      @C10*/
         (PelRows == rcp_tbl_ptr->PelRows) && /*                        @C10*/
         (PelColumns == rcp_tbl_ptr->PelColumns))/*                     @C10*/
      {                                /*                                @C7*/
        FONT_AVAILABLE = TRUE;         /*                                @C7*/
        Environment->ROMFontIndex = (UCHAR)j;/*                         @C10*/
        Environment->ActiveFontPTR = (UCHAR far *)CP_FONT;/*             @C7*/
      }                                /*                                @C7*/

      else
        rcp_tbl_ptr++;                 /*                               @C10*/

      if ((j == (ROMCP_NUM-1)) && !FONT_AVAILABLE && (PelColumns == 9))/*
                                                                        @C10*/
      {                                /*                               @C10*/
        PelColumns = 8;                /*                               @C10*/
        j = -1;                        /*                               @C10*/
        rcp_tbl_ptr = RomCP_tbl.ptr;   /*                               @C10*/
      }                                /*                               @C10*/
    }
  }                                    /*                                @C7*/

  if (!FONT_AVAILABLE)
  {

/*
** Check ROM font table for an appropriate mode
*/

    for (i = ROMFont8x8; i <= ROM_FONTS; i++)/*                          @C7*/
    {

      if ((PelColumns == Fonts[i].PelColumns) && (PelRows == Fonts[i].PelRows))
      {
        FONT_AVAILABLE = TRUE;
        Environment->ROMFontIndex = i;
        Environment->ActiveFontPTR = (UCHAR far *)ROM_FONT;
        break;
      }

      if ((i == ROM_FONTS) && (PelColumns == 9))/*                   @C2,@C7*/
      {                                /*                                @C2*/
        PelColumns = 8;                /*                                @C2*/
        i = ROMFont8x8-1;              /*                                @C2*/
      }                                /*                                @C2*/
    }
  }
  return (FONT_AVAILABLE);
}

#endif         /*        FONT_SUPPORT @MS00                                 */

#if      VDHCGA                        /* Start of unique CGA support,  @S26*/
                                       /*  @MS00                            */
extern UCHAR CGAFont;                  /* CGA 8x8 font table                */

/*****************************************************************************
 *
 *  SUBROUTINE NAME: GetCurrentFont
 *
 *  DESCRIPTIVE NAME: Get color lookup table
 *
 *  FUNCTION: GetCurrentFont is called by BVS to return the current
 *            active video font.
 *
 *  ENTRY POINT: GetCurrentFont
 *    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 GetCurrentFont(Environment,ParmBlock,Function)

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

{

  USHORT rc;
  USHORT FontSize = 0x0800;
  UCHAR register far *SourcePtr;
  UCHAR register far *DestPtr;

  rc = ERROR_VIO_INVALID_PARMS;

  if ((Function == FnGetFont) &&       /* Valid function request            */
     (ParmBlock->Length >= sizeof(VDH_FONT)) && /* Valid Length             */
     (ParmBlock->Flags <= 3))
  {                                    /* Valid flags                       */
    rc = ERROR_VIO_FONT;

    if ((ParmBlock->Flags&GET_ROM_FONT) && (ParmBlock->PelColumns == 8) &&
       (ParmBlock->PelRows == 8))
    {                                  /* Only 8x8 ROM font available       */
      rc = NO_ERROR;

      if ((ParmBlock->FontLength == NULL) && /* Return size only            */
         (ParmBlock->FontBuffer == NULL))
      {
        ParmBlock->FontLength = FontSize;
      }

      else

        if (ParmBlock->FontLength < FontSize)
        {
          rc = ERROR_VIO_INVALID_PARMS;/*                              @TB38*/
        }

        else
        {                              /* Return the actual font            */
          SourcePtr = &CGAFont;
          DestPtr = ParmBlock->FontBuffer;

          do
          {
            *DestPtr++ = *SourcePtr++;
          }

          while (--FontSize);
        }
    }
  }
  return (rc);
}

#endif           /*     VDHCGA    End of unique CGA support, @S26,MS00 */

#if      VDHMPA        || VDHCGA       /*                          @T68,MS00*/

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SetCurrentFont
 *
 *  DESCRIPTIVE NAME: Set color lookup table
 *
 *  FUNCTION: SetCurrentFont is called by BVS to load the specified
 *            video text font
 *
 *  ENTRY POINT: SetCurrentFont
 *    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-ERROR: AX = ERROR_VIO_FONT
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

USHORT EXPENTRY SetCurrentFont(Environment,ParmBlock,Function)/*        @T68*/

  ENVIRONMENT far *Environment;        /*                               @T68*/
  VDH_FONT far *ParmBlock;             /*                               @T68*/
  ULONG Function;                      /*                               @T68*/

{                                      /*                               @T68*/
  return (ERROR_VIO_FONT);             /*                               @T68*/
}                                      /*                               @T68*/

#endif                                 /* VDHMPA || VDHCGA   @T68,MS00      */

