/*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 = BVHFONT.C
 *
 * DESCRIPTIVE NAME = BASE VIDEO DEVICE HANDLER  - PRIVATES
 *
 *
 * VERSION      V2.0
 *
 * DATE
 *
 * DESCRIPTION  Super VGA specific routines to set/get fonts.
 *
 *              BASE VIDEO DEVICE HANDLER  - PRIVATES
 *
 *              THIS SOURCE FILE CONTAINS ROUTINES WHICH ARE NOT PUBLIC.
 *              THEY ARE CALLED BY VARIOUS VDH ROUTINES TO PERFORM I/O
 *              FUNCTIONS.
 *
 *              THESE ROUTINES EXECUTE AS RING 2 CONFORMING
 *
 * FUNCTIONS
 *
 * NOTES        NONE
 *
 * STRUCTURES   NONE
 *
 * EXTERNAL REFERENCES
 *
 *              NONE
 *
 * EXTERNAL FUNCTIONS
 *
 *              NONE
 *
*/

#define  INCL_DOSDEVICES               /* Device specific, ring 2 support   */
#include <cdib.h>                      /* CDIB defines                      */
#include "bvhtype.h"
#include <memory.h>
/*  undefine FONT_KLUGE                               
#define FONT_KLUGE                          9*X fonts replaced by 8*X fonts */
#pragma  intrinsic(memcpy)
/*****************************************************************************
 *
 * FUNCTION NAME = SearchFont()
 *
 * DESCRIPTION   = Search for an available font to match the given mode.
 *                 Search for best fit by.
 *                 If best fit leaves empty scan lines between the rows
 *                 greater than 1/2 the pelrows size of the font,
 *                 try double-scanning. If that doesn't produce a font
 *                 return the previously found font.
 *                 This function doesn't return actual font data, just
 *                 font dimensions and font pointer, thru FontData.
 *
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0  not found, 1 found
 * RETURN-ERROR  = ERROR
 *
 ***************************************************************************/

#define MAX_SCANLINES 64     //          

USHORT PASCAL NEAR SearchFont(PENVIRONMENT Environment,
                              PVIDEOMODE   pCurMode,
                              PVDHMODEINFO pReqMode)
{
  VDH_FONT      FontData =
  {
    14,2,NULL,0,0,0
  };
  USHORT        VerticalRes = pCurMode->vres;
  USHORT        FontFound = FALSE;
  PFONTDATA     TempFontData;

  Environment->EnvFlags &= ~ENVFLAG_DOUBLESCANMODE;
  if (VerticalRes <= pReqMode->row)
     return FontFound;

  FontData.PelRows    = VerticalRes / pReqMode->row;

  /*           
   * If the scan lines for a character is greater than 64 (32 scan lines
   * with double scan), we cannot handle it in CRT indexed 9.
   * It is because that register can have 32 scan lines (5-bits) at most.
   */
  if (FontData.PelRows > MAX_SCANLINES)
     return FontFound;

  FontData.PelColumns = pCurMode->hres / pReqMode->col;

  /*
   *           
   * Change the font to 16x8 instead of 16x9 on laptop for 80 x 25 mode.
   */
  if ((CurrentDisplay == PlasmaDisplay) &&
      (pReqMode->col == 80) &&
      (pReqMode->row == 25))
     FontData.PelColumns = 8;

  FontData.FontBuffer = NULL;
  FontData.FontLength = 0;
  for (;FontData.PelColumns && !FontFound;FontData.PelColumns--)
  {

    FontData.PelRows    = VerticalRes / pReqMode->row;

    for(;FontData.PelRows && !FontFound;FontData.PelRows--)
    {

       /*
       ** Query if this font is available. If TRUE,
       ** Environment->pFontData will be set.
       */
       if (FindFont(Environment,&FontData))
       {
          /*
          ** If empty scan lines between the rows are greater than
          ** 1/2 of the font size, try double scanning. If double
          ** scan doesn't produce a font, go for the spaced one.
          */
//          if (((VerticalRes / pReqMode->row) - FontData.PelRows) >            
//              (FontData.PelRows >> 1))                                        
          if ((((VerticalRes / pReqMode->row) - FontData.PelRows) > //          
               (FontData.PelRows >> 1)) &&                          //          
              (!(Environment->EnvFlags & ENVFLAG_DOUBLESCANMODE)))  //          
          {
             Environment->EnvFlags |= ENVFLAG_DOUBLESCANMODE;
             TempFontData = Environment->pFontData;
             VerticalRes >>= 1;
             /*
             ** Start the search again. Add 1 since we
             ** are entering the same loop and PelRows
             ** will be decremented by 1.
             */
             FontData.PelRows = VerticalRes / pReqMode->row + 1;
          }
          else
          {
             /*
             ** We have the font, but breaking out of this loop would still
             ** decrement the PelColumns in the outer loop, so in order to preserve
             ** the correct dimensions, increment the PelColumns.
             */
             FontData.PelColumns++;
             FontFound = TRUE;
             break;
          }
       }
    }
  }
  if (!FontFound)
  {
    if (Environment->EnvFlags & ENVFLAG_DOUBLESCANMODE)
    {
      /*
      ** Double scanning didn't find a better fit.
      ** Reset the error code from the last font search,
      ** and the fontdata.
      */
      FontFound = TRUE;
      Environment->EnvFlags &= ~ENVFLAG_DOUBLESCANMODE;
      Environment->pFontData = TempFontData;
    }
  }
  return FontFound;
}
/*****************************************************************************
 *
 * FUNCTION NAME = SetHWFont()
 *
 * DESCRIPTION   = Load the hardware font.
 *
 * INPUT         = Environment, CurrentMode, FontData, DoubleScan
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0
 * RETURN-ERROR  = ERROR_VIO_FONT
 *
 ***************************************************************************/
USHORT PASCAL NEAR SetHWFont(PENVIRONMENT Environment)
{
  USHORT rc = ERROR_VIO_FONT;
  USHORT ColorMode;
  USHORT TempData, RegsLocked, VertDispEnd, ScanRow;
  REGADDRESS RegAddress;
  REGDATA RegData;

  /*
  ** copy the font to the video buffer
  */
  if (BVHAccessFont(SET,Environment->pFontData))
    return rc;

  Environment->ModeData.vres = pModes[Environment->ModeIndex].vres;
  if (Environment->EnvFlags & ENVFLAG_DOUBLESCANMODE)
     Environment->ModeData.vres >>= 1;

  ColorMode = Environment->ModeData.fbType & MODE_FLAG_NOT_MONO;
  RegAddress.AddressPort = CRTMONOADDRPORT;
  RegAddress.DataPort    = CRTMONODATAPORT;
  RegAddress.ColorAdjust = COLORADJUSTMENT;
  RegAddress.Flags       = NONE;
  RegData.NumEntries   = 1;

  /*
  ** Set number of scan lines per character row in CRT 9
  */
  RegData.FirstEntry   = 0x09;
  RegData.DataArea     = (PBYTE)&TempData;
  AccessHardware( &RegAddress, BYTES, ColorMode, GET, &RegData );
  TempData &= 0xe0;
  ScanRow = Environment->ModeData.vres / Environment->ModeData.row;
  TempData |= ScanRow - 1;
  if (Environment->EnvFlags & ENVFLAG_DOUBLESCANMODE)
    TempData |= 0x80;
  AccessHardware( &RegAddress, BYTES, ColorMode, SET, &RegData );

  /*
  ** Ensure registers 0-7 are unprotected.
  */
  RegData.FirstEntry = 0x11;
  AccessHardware( &RegAddress, BYTES, ColorMode, GET, &RegData );
  if ((RegsLocked = TempData) & 0x80)
  {
    TempData ^= 0x80;
    AccessHardware( &RegAddress, BYTES, ColorMode, SET, &RegData );
  }

  /*
  ** Set Vertical Display End
  */
  VertDispEnd  = (Environment->ModeData.row * ScanRow);
  if (Environment->EnvFlags & ENVFLAG_DOUBLESCANMODE)
    VertDispEnd <<= 1;

  TempData = VertDispEnd - 1;
  RegData.FirstEntry = 0x12;
  AccessHardware( &RegAddress, BYTES, ColorMode, SET, &RegData );

  /*
  ** Set Vertical Display End overflow (bit 8,9 of display end are
  ** in bits 1 and 6.
  */
  RegData.FirstEntry = 0x07;
  AccessHardware( &RegAddress, BYTES, ColorMode, GET, &RegData );
  TempData &= 0xBD;                    //reset bits 1 and 6
  if (VertDispEnd & 0x100)
    TempData |= 0x2;                  //bit 8 is set. Set bit 1
  if (VertDispEnd & 0x200)
    TempData |= 0x40;                 //bit 9 is set. Set bit 6
  AccessHardware( &RegAddress, BYTES, ColorMode, SET, &RegData );

  /*
  ** Relock CRTs if necessary
  */
  if (RegsLocked)
  {
    TempData = RegsLocked;
    RegData.FirstEntry = 0x11;
    AccessHardware( &RegAddress, BYTES, ColorMode, SET, &RegData );
  }

  return NO_ERROR;
}
/*****************************************************************************
 *
 * FUNCTION NAME = FindFont()
 *
 * DESCRIPTION   = Search thru all available fonts to find font which
 *                 matches the FontData. If font found, Environment
 *                 pFontData pointer set to the selected font.
 *
 * INPUT         = Environment, CurrentMode, FontData, DoubleScan
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 ***************************************************************************/
USHORT FindFont(PENVIRONMENT Environment,PVDH_FONT FontData)
{

  USHORT PelColumns,PelRows;
  USHORT j;
  PFONTDATA USERFont;                  /* Pointer to an entry in the USER   */
                                       /* font table                        */
  USHORT FontFound = FALSE;

  PelRows =   FontData->PelRows;
  PelColumns =FontData->PelColumns;

  if (Environment->UserFont == USER_FONT_SELECTABLE)
  {
    USERFont = MAKEP(Environment->USERFontSel,0);  /* Begining of USER  */
                                                   /* font table        */
    for (j = 0; (FontFound == FALSE)
         && (j < Environment->NumUSERFonts); j++)
    {

      if (((USHORT) USERFont->ulFontWidth == PelColumns) &&
          ((USHORT) USERFont->ulFontHeight == PelRows))
      {
        FontFound = TRUE;
        Environment->pFontData = USERFont;
      }
      else
      {                                                /* Next font */
        (ULONG)USERFont += (ULONG) sizeof(FONTDATA) + (ULONG)
                           ((USHORT) USERFont->ulFontHeight*
                            (USHORT) USERFont->ulCharCount)-1L;
      }
    }
  }

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

  if (!FontFound && (Environment->CodePageID != ROM_FONT))
  {
    if (FindCPFont(Environment,
                   PelRows,
                   PelColumns,
                   Environment->CodePageID))
      FontFound = TRUE;

  }

  if (!FontFound)
  {

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

    for (j = ROMFont8x8; j <= ROM_FONTS; j++)
    {
      if ((Fonts[j].PVB.p.Selector) &&       /* if font exists */
         ((PelColumns == (USHORT) Fonts[j].PVB.ptr->ulFontWidth) &&
          (PelRows == (USHORT) Fonts[j].PVB.ptr->ulFontHeight)))
      {
        FontFound = TRUE;
        Environment->pFontData = Fonts[j].PVB.ptr;
        break;
      }

    }
  }
  return (FontFound);
}

/***************************************************************************
 *
 * FUNCTION NAME = GetCodePage
 *
 * DESCRIPTION   = Copies all prepared CodePage fonts to a getable seg.
 *
 * INPUT         =  NONE
 * OUTPUT        =  NONE
 *
 * RETURN-NORMAL =  0 if OK, DosError otherwise
 * RETURN-ERROR  =  NONE
 *
 **************************************************************************/

USHORT PASCAL NEAR GetCodePage(VOID)

{

  union faraddr
  {
    struct part p;
    struct CDIB *CDIBptr;
    struct CDIB_codepage_section *cp_ptr;
    struct CDIB_device_section *screen_ptr;
    struct CDIB_cp_id_section *cp_id_ptr;
    PSZ str_ptr;
  }Addr,fontfn;

  union faraddr2
  {
    struct part p;
    FONTHDR *font_ptr;
    FONTFILEHDR *ff_ptr;
  }hdr_info;

  union faraddr3
  {
    struct part p;
    ULONG *ofs_ptr;
  }next_font;

  USHORT rc,CP_cnt,font_num,i,CP_id,j,base_needed,rows,cols;
  HFILE font_handle;
  ULONG distance,RomCP_tbl_len,scratch;
  ROMCP_TABLE *rtbl_ptr,*btbl_ptr;

  /*
  ** get access to the CDIB segment
  */

  rc = DosGetShrSeg("\\SHAREMEM\\DOS\\CDIB",
                    (PSEL)&Addr.p.Selector);

  if (!rc)
  {
    Addr.p.Offset = 0;                 /* setup ptr to codepage section     */

    /*           
     * Initailize the selectors for codepage font table.
     */
    ROMCP_NUM = 0;
    RomCP_tbl.ptr = NULL;
    CodePage.ptr = NULL;

    /*
    ** get ptr to screen device section
    */

    fontfn.p.Selector = Addr.p.Selector;
    fontfn.p.Offset = (USHORT)Addr.CDIBptr->CDIB_screen_ptr;

    /*
    ** get ptr to codepage section and get number of codepages
    */

    Addr.p.Offset = (USHORT)Addr.CDIBptr->CDIB_codepage_ptr;
    CP_cnt = Addr.cp_ptr->CDIB_cp_number_codepages;

    /*
    ** if there are prepared codepages AND a ptr to the screen device
    ** section AND a ptr to the font filename (does assign at same time)
    */

    if (CP_cnt && fontfn.p.Offset && (fontfn.p.Offset = (USHORT)
       fontfn.screen_ptr->CDIB_dev_filename_ptr))
    {
      font_handle = 0;
      hdr_info.p.Selector = 0;
      hdr_info.p.Offset = 0;

      /*
      ** open font file, allocate room for font info. and read
      ** font file hdr
      */

      if (!(rc = DosOpen(fontfn.str_ptr, &font_handle,
           (PUSHORT)&scratch,
           (ULONG)0, 0, 1, 0x20, (ULONG)0)) &&
           !(rc = DosAllocSeg(sizeof(FONTHDR),
           (PSEL)&(hdr_info.p.Selector), 0)) &&
           !(rc = DosChgFilePtr (font_handle, (ULONG)0, 0, &scratch)) &&
           !(rc = DosRead(font_handle, (PVOID)hdr_info.ff_ptr,
           sizeof(FONTFILEHDR), (PUSHORT)&scratch)))
      {
        font_num = hdr_info.ff_ptr->ffh_numfonts;/* # of fonts in file      */
        next_font.p.Offset = 0;
        next_font.p.Selector = 0;

        /*
        ** get offset to table of file offsets to fonts and read it
        */

        distance = (ULONG)(hdr_info.ff_ptr->ffh_ptroffset);

        if (!(rc = DosAllocSeg(font_num *4, (PSEL)&(next_font.p.Selector), 0))
           && !(rc = DosChgFilePtr(font_handle, distance, 0, &scratch)) &&
           !(rc = DosRead(font_handle, (PVOID)next_font.ofs_ptr, font_num * 4,
           (PUSHORT)&scratch)))
        {
          RomCP_tbl_len = 1;

          /*
          ** get ptr to the first prepared codepage section
          */

          Addr.p.Offset += 2*sizeof(unsigned);

          for (i = 0; i < CP_cnt; i++) /* loop thru all CPs                 */
          {
            CP_id = Addr.cp_id_ptr->CDIB_cp_id;/* get CP id                 */

            for (j = 0; j < font_num; j++)/* loop thru fonts                */
            {

              /*
              ** read in font header
              */

              if (!(rc = DosChgFilePtr(font_handle,
                 *(next_font.ofs_ptr), 0, &scratch)) &&
                 !(rc = DosRead(font_handle,
                 (PVOID) hdr_info.font_ptr, sizeof(FONTHDR),
                 (PUSHORT)&scratch)))
              {
                /*
                ** if codepage we're looking for
                */

                if (CP_id == hdr_info.font_ptr->fh_cpid)
                {

                  /*
                  ** if table ptr already exists then reallocate for
                  ** next font
                  */

                  if (RomCP_tbl.ptr)
                  {
                    rc = DosReallocSeg(sizeof(ROMCP_TABLE)*++ROMCP_NUM,
                                       (SEL)RomCP_tbl.p.Selector);

                    rc = DosReallocSeg((USHORT)(RomCP_tbl_len +
                                       hdr_info.font_ptr->fh_datalen+sizeof(FONTDATA)),
                                       (SEL)CodePage.p.Selector);
                  }


                  else
                  {

                    /*
                    ** need to allocate table and buffer with fonts for
                    ** the first time
                    */

                    RomCP_tbl.p.Offset = 0;/* table                         */
                    RomCP_tbl.p.Selector = 0;

                    rc = DosAllocSeg(sizeof(ROMCP_TABLE),
                                     (PSEL)&(RomCP_tbl.p.Selector),
                                     SEG_GETTABLE);

                    CodePage.p.Offset = 0;/* font buffer                    */
                    CodePage.p.Selector = 0;

                    rc = DosAllocSeg(hdr_info.font_ptr->fh_datalen+sizeof(FONTDATA),
                                     (PSEL)&(CodePage.p.Selector),
                                     SEG_GETTABLE);

                    base_needed = 0;
                    ++ROMCP_NUM;
                  }

                  if (!rc)             /* fill in table info                */
                  {
                    RomCP_tbl_len += hdr_info.font_ptr->fh_datalen + sizeof(FONTDATA);


                    RomCP_tbl.ptr->CodePageID = CP_id;
                    RomCP_tbl.ptr->BaseFontPTR = NULL;
                    RomCP_tbl.ptr->FontPTR = CodePage.ptr;
                    CodePage.ptr->ulFontHeight = (ULONG) hdr_info.font_ptr->fh_cellrows;
                    CodePage.ptr->ulFontWidth = (ULONG) hdr_info.font_ptr->fh_cellcols;
                    CodePage.ptr->ulCharCount = 256;
                    /*
                    ** if override font, save base rows and cols
                    */

                    if (RomCP_tbl.ptr->FontPTR->ulFontWidth == 9)
                    {
                      RomCP_tbl.ptr->BaseRows = hdr_info.font_ptr->fh_baserows;
                      RomCP_tbl.ptr->BaseColumns =
                             hdr_info.font_ptr->fh_basecols;
                      base_needed++;
                    }

                    RomCP_tbl.ptr++;

                    /*
                    ** get offset from current file position to font data
                    ** and read it into font buffer
                    */

                    distance = *next_font.ofs_ptr+
                       hdr_info.font_ptr->fh_dataoffset;

                    if (!(rc = DosChgFilePtr(font_handle, distance, 0,
                          &scratch)))
                    {
                      rc = DosRead(font_handle,
                                   (PVOID)&CodePage.ptr->bFontData[0],
                                   (USHORT)hdr_info.font_ptr->fh_datalen,
                                   (PUSHORT)&scratch);

                      /*
                       * Set the character after the font buffer as 0.
                       * It is very important for supplemental font since
                       * 0 signals the end of supplemental font.
                       */
                      CodePage.ptr->
                           bFontData[hdr_info.font_ptr->fh_datalen] = 0;
                      CodePage.p.Offset += hdr_info.font_ptr->fh_datalen+sizeof(FONTDATA);
                    }
                  }
                }
              }

              if (rc)                  /* if error, set cntrs to exit loop  */
              {                        /* and free table and buffer segs    */
                i = CP_cnt;
                j = font_num;

                ROMCP_NUM = 0;

                if (RomCP_tbl.p.Selector)
                {
                  DosFreeSeg(RomCP_tbl.p.Selector);

                  if (CodePage.p.Selector)
                    DosFreeSeg(CodePage.p.Selector);
                }
              }

              else
              {
                next_font.ofs_ptr++;   /* go to offset for next font        */
                hdr_info.p.Offset = 0; /* reset ptr                         */
              }
            }

            next_font.p.Offset = 0;    /* back to beg of fonts              */
            Addr.cp_id_ptr++;          /* go to next cp_id_section          */
          }

          /*
          ** if codepages read in w/o error, then setup pointers to
          ** base font for override fonts
          */

          if (!rc)
          {

            if (ROMCP_NUM)             /* have CP fonts in table            */
            {
              CodePageSupport = TRUE;
              RomCP_tbl.p.Offset = 0;  /* reset ptrs to beginning           */
              /* CodePage.p.Offset = 0;            CodePage.p.Offset is needed
                                           for appending the 9xX FONTDATA.  */


              /*
              ** search thru table for override fonts and if so, search
              ** thru table again to find the matching base font
              */
              for (rtbl_ptr = RomCP_tbl.ptr; base_needed; rtbl_ptr++)
              {

                if (rtbl_ptr->FontPTR->ulFontWidth == 9)
                {
                  CP_id = rtbl_ptr->CodePageID;
                  rows = (USHORT) rtbl_ptr->BaseRows;
                  cols = (USHORT) rtbl_ptr->BaseColumns;
                  btbl_ptr = RomCP_tbl.ptr;

                  for (j = 0; j < ROMCP_NUM; j++)
                  {

                    if ((btbl_ptr->CodePageID == CP_id) &&
                       ((USHORT) btbl_ptr->FontPTR->ulFontWidth == cols) &&
                       ((USHORT) btbl_ptr->FontPTR->ulFontHeight == rows))
                    {
                       /*  ********* start of            *********
                        * The constructed 9xX font will be appended to the
                        * end of the existing CodePage segment.
                        */
                       USHORT len_seg;

                       len_seg = 256 * rows + sizeof(FONTDATA);
                       rc = DosReallocSeg ( (USHORT)(RomCP_tbl_len + len_seg),
                                              (SEL)CodePage.p.Selector );

                       CodePage.ptr->ulCharCount = 256;
                       /* SENJA
                       CodePage.ptr->ulFontWidth = cols;
                       CodePage.ptr->ulFontHeight = rows;
                       */
                       CodePage.ptr->ulFontWidth = rtbl_ptr->FontPTR->ulFontWidth;
                       CodePage.ptr->ulFontHeight = rtbl_ptr->FontPTR->ulFontHeight;

                       {  /* overlaying 9xX font. */
                          USHORT  Index = 0, Dst;

                          memcpy ( CodePage.ptr->bFontData,
                                   btbl_ptr->FontPTR->bFontData,
                                   256 * rows );
                          while ( rtbl_ptr->FontPTR->bFontData[Index] != 0 )
                          {
                             Dst = (USHORT)rtbl_ptr->FontPTR->bFontData[Index++]
                                                                       * rows;
                             memcpy ( CodePage.ptr->bFontData + Dst,
                                      rtbl_ptr->FontPTR->bFontData + Index,
                                      rows );
                             Index += rows;
                          } /* endwhile */
                       } /* end of overlaying. */

                      rtbl_ptr->FontPTR = CodePage.ptr;
                      rtbl_ptr->BaseFontPTR = btbl_ptr->FontPTR;
                      RomCP_tbl_len += len_seg;
                      CodePage.p.Offset += len_seg;
                              /*     end of                 */

                      j = ROMCP_NUM;
                      base_needed--;
                    }

                    else
                      btbl_ptr++;
                  }

                  /*
                  ** if no base found, can't use font so 0 out
                  */

                  if (!rtbl_ptr->BaseFontPTR)
                  {
                    rtbl_ptr->FontPTR->ulFontWidth = 0;
                    rtbl_ptr->FontPTR->ulFontHeight = 0;
                  }
                }
              }
            }

            else                       /* no codepages return error         */
              rc = ERROR_VIO_BAD_CP;
          }                            /* codepages read in ok              */
        }                              /* if font offsets read              */
      }                                /* if no errors from Dos calls       */

      if (font_handle)                 /* free handles and allocated        */
                                       /* selectors                         */
      {
        DosClose(font_handle);

        if (hdr_info.p.Selector)
        {
          DosFreeSeg(hdr_info.p.Selector);

          if (next_font.p.Selector)
            DosFreeSeg(next_font.p.Selector);
        }
      }
    }                                  /* if CP_cnt                         */
  }                                    /* if !rc from DosGetShrSeg          */
  return rc;
}

/***************************************************************************
 *
 * FUNCTION NAME = GetROMFonts
 *
 * DESCRIPTION   = Copies all ROM fonts into an allocated named segment.
 *
 * INPUT         =  NONE
 * OUTPUT        =  NONE
 *
 * RETURN-NORMAL =  0
 * RETURN-ERROR  =  DOSError
 * REMARKS:
 *
 * The OS/2 loader calls the BIOS interrupt 10h function 1130h to build
 * a table of 32 bit values each of which points a corresponding font
 * address supported by the current video cards.
 *
 * If BIOS interrupt 10 function 1130h is not supported the video ROM
 * will be scanned to see if the font address can be found.  The scan-
 * ning looks for various character bit maps and their relative
 * position to do this.
 *
 * The function GetBIOSFonts fetches the table built by the loader and
 * copies its contents to the Fonts[] data a structure, if the table
 * is not available NOBIOSFONTS is returned and the pattern search
 * code is used.
 * Once the font ROM pointers found, fonts are copied into a global
 * segment in order to conform to FONTDATA format.
 **************************************************************************/
USHORT PASCAL NEAR GetROMFonts(VOID)
{
  USHORT rc = NO_ERROR;
  USHORT ROMFontSEL,ROMFontLEN,ROMSrchLEN,i;
  FARADDRESS PVB;


  /*           
   * Initailize the selectors for rom font table.
   */
  for (i = ROMFont8x8; i <= ROM_FONTS; i++)
      Fonts[i].PVB.ptr = NULL;

  if (GetBIOSFonts() == NOBIOSFONTS)
  {

    /*
    ** BIOS fonts were not returned by BIOS int 10 function 1130h
    ** so font pattern search must be used.
    **  Search through ROM to find 8x8, 8x14, 8x16, 9x14, and 9x16 fonts
    **  ROM fonts are located at physical addresses:
    **            C0000 - EGA and PS/2 Adapter
    **            E0000 - VGA
    */

    for (ROMFontSEL = 0x0E, ROMFontLEN = 0xFFFF, ROMSrchLEN = 0xFFF0;
         ROMFontSEL >= 0x0C;
         ROMFontSEL -= 2, ROMFontLEN -= 0x8000, ROMSrchLEN = 0x7FF0)
    {
      PVB.FullAddress = MAKEFARPTR(ROMFontSEL, 0);
      PhysToUVirt(PVB, &PVB, ROMFontLEN);

      /*
      **  Locate 8x8 ROM font on CGA, EGA, VGA, and PS/2 adapter
      */

      for (i = 0; i < ROMSrchLEN; i++)
      {

        while ((i < ROMSrchLEN) && (PVB.FullAddress[i] != (UCHAR)0x7E))
          i++;

        if (i < ROMSrchLEN)
        {

          if ((PVB.FullAddress[i+1] == (UCHAR)0x81) &&
              (PVB.FullAddress[i+2] == (UCHAR)0xA5) &&
              (PVB.FullAddress[i+3] == (UCHAR)0x81))
          {

            if (!Fonts[ROMFont8x8].PVB.p.Selector &&
                PVB.FullAddress[i+4] == (UCHAR)0xBD)

            {
              Fonts[ROMFont8x8].PVB.p.Selector = ROMFontSEL;
              Fonts[ROMFont8x8].PVB.p.Offset = i-8;
            }
            /*
            **  Locate 8x14 ROM font on EGA, VGA, and PS/2 adapter only
            */

            if ((PVB.FullAddress[i+4] == (UCHAR)0x81) &&
                (PVB.FullAddress[i+5] == (UCHAR)0xBD) &&
                (PVB.FullAddress[i+6] == (UCHAR)0x99) &&
                (PVB.FullAddress[i+7] == (UCHAR)0x81))
            {

              if (!Fonts[ROMFont8x14].PVB.p.Selector &&
                  PVB.FullAddress[i+8] != (UCHAR)0x81)
              {
                Fonts[ROMFont8x14].PVB.p.Selector = ROMFontSEL;
                Fonts[ROMFont8x14].PVB.p.Offset = i-16;
              }
              /*
              **  Locate 8x16 ROM font on VGA, and PS/2 adapter only
              */

              if (!Fonts[ROMFont8x16].PVB.p.Selector &&
                  PVB.FullAddress[i+8] == (UCHAR)0x81)
              {
                Fonts[ROMFont8x16].PVB.p.Selector = ROMFontSEL;
                Fonts[ROMFont8x16].PVB.p.Offset = i-18;
              }
            }
          }
        }
      }                            /* Locate 8x8, 8x14, 8x16            */

      /*
      **  Locate 9x14 ROM font on EGA, VGA, and PS/2 adapter only
      */

      for (i = 0; i < ROMSrchLEN; i++)
      {

        while ((i < ROMSrchLEN) && (PVB.FullAddress[i] != (UCHAR)0x1D))
          i++;

        if (i < ROMSrchLEN)
        {

          if ((PVB.FullAddress[i+1] == (UCHAR)0x00) &&
              (PVB.FullAddress[i+2] == (UCHAR)0x00) &&
              (PVB.FullAddress[i+3] == (UCHAR)0x00) &&
              (PVB.FullAddress[i+4] == (UCHAR)0x00))
          {
             /*  _asm int 3; */
            if (!Fonts[ROMFont9x14].PVB.p.Selector  &&
                (PVB.FullAddress[i+5] == (UCHAR)0x24) &&
                (PVB.FullAddress[i+6] == (UCHAR)0x66))
            {
              Fonts[ROMFont9x14].PVB.p.Selector = ROMFontSEL;
              Fonts[ROMFont9x14].PVB.p.Offset = i;
            }
            /*
            **  Locate 9x16 ROM font on VGA, and PS/2 adapter only
            */

            if (!Fonts[ROMFont9x16].PVB.p.Selector  &&
               (PVB.FullAddress[i+5] == (UCHAR)0x00) &&
               (PVB.FullAddress[i+6] == (UCHAR)0x24))
            {
              Fonts[ROMFont9x16].PVB.p.Selector = ROMFontSEL;
              Fonts[ROMFont9x16].PVB.p.Offset = i;
            }
          }
        }
      }                            /* Locate 9x14, 9x16                 */

      FreePhysToUVirt(PVB.Part.Selector);/* Deallocate selector to ROM font */
    }                              /* Search next ROM segment for fonts */
  }

  /*
  **  If all fonts were not found, then
  **  initialization fails
  **  If the offset is FA6E, it is probably a system ROM image
  **  also 8 * 256 bytes starting here crosses a 64k physical
  **  boundry so it would run off the end of the ROM
  **  so this is a partial font and can not be used
  */
  if ((!Fonts[ROMFont8x8].PVB.p.Selector) ||
       (Fonts[ROMFont8x8].PVB.p.Offset == 0xFA6E))
  {
     /*           
      * set the selectors to NULL since the ROM fonts are invalid.
      */
     for (i = ROMFont8x8; i <= ROM_FONTS; i++)
         Fonts[i].PVB.ptr = NULL;

     rc = INIT_ERROR;
  }

  /*
  ** Old BVH failed if any of the expected ROM fonts were
  ** missing. New BVH fails only if none are found.
  */
  if (!Fonts[ROMFont8x14].PVB.p.Selector &&
      !Fonts[ROMFont9x14].PVB.p.Selector &&
      !Fonts[ROMFont8x16].PVB.p.Selector &&
      !Fonts[ROMFont9x16].PVB.p.Selector)
     rc = INIT_ERROR;
   if (!rc)
     rc = CopyGlobalFontTable(Fonts);
   return rc;
}
/*****************************************************************************
 *
 * SUBROUTINE NAME: GetBIOSFonts
 *
 * DESCRIPTIVE NAME: Copy the OEMHLP table with BIOS fonts to a
 *                   local table
 *
 * FUNCTION: The OS/2 Loader (OS2LDR) calls the BIOS INT 10h
 *           function 1130h to build a table of 32 bit values
 *           boot time.  Each table entry point to a corresponding
 *           font address supported by the current video card.
 *           The address are returned as segment:offset pairs which
 *           this function converts to a 32 bit address.
 *
 *  ENTRY POINT: GetBIOSFonts
 *    LINKAGE:   CALL NEAR
 *
 *  INPUT: None
 *
 *  EXIT: NOBIOSFONTS if no Bios fonts found, else BIOSFONTSFOUND
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: None
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: DosOpen, DosDevIOCtl, DosClose
 *              sends a request packet to the OEMHLP$ device driver
 *
 ****************************************************************************/
USHORT PASCAL NEAR GetBIOSFonts(VOID)
{

  /*
  **  fontTable is filled with ROM font addresses obtained from
  **  OEMHLP$.  It contains the following information:
  **
  **            [0] font8x14    - ROM 8x14 font
  **            [1] font8x8Low  - ROM 8x8  font, charaters 0-7fh
  **            [2] font8x8High - ROM 8x8  font, charaters 80h-ffh
  **            [3] font9x14    - ROM 9x14 font
  **            [4] font8x16    - ROM 8x16 font
  **            [5] font9x16    - ROM 9x16 font
  */

  static ULONG fontTable[] = { 0L,0L,0L,0L,0L,0L,-1L } ;

  USHORT ifont;                        /* fontTable index                   */


  if (OEMHLPIoctl((UCHAR *)fontTable, NULL, OEMHLP_FUNCTION_FONTS))/* filled */
                                       /* font addresses                    */
    return  NOBIOSFONTS;

    /*
    **  Scan though fontTable until either a non-zero font address
    **  found or the end of fontTable is reached
    */

  for (ifont = 0; fontTable[ifont] != -1L; ++ifont)

    if (fontTable[ifont])
      break;

  if (fontTable[ifont] == -1L)         /* unable to find ROM fonts?         */
    return  NOBIOSFONTS;

  /*
  **  Convert the required ROM font segment:offsets into 32 bit
  **  addresses and copy them to the VDH Fonts array.
  **  Note:  The 2nd 8x8 font address is not used by OS/2
  */

  Fonts[ROMFont8x14].PVB.ptr = (PFONTDATA) REALTO32BITADDR
                                     (fontTable[0] );

  Fonts[ROMFont8x8].PVB.ptr  = (PFONTDATA) REALTO32BITADDR
                                     (fontTable[1]) ;

  Fonts[ROMFont9x14].PVB.ptr = (PFONTDATA) REALTO32BITADDR
                                     (fontTable[3] );

  Fonts[ROMFont8x16].PVB.ptr = (PFONTDATA) REALTO32BITADDR
                                       (fontTable[4]);

  Fonts[ROMFont9x16].PVB.ptr = (PFONTDATA) REALTO32BITADDR
                                     (fontTable[5]);
  return  BIOSFONTSFOUND;

}

/*****************************************************************************
 *
 * SUBROUTINE NAME:  CopyGlobalFontTable
 *
 * DESCRIPTIVE NAME: Copy the ROM fonts into a global segment.
 *
 * FUNCTION: ROM fonts are resident in ROM area and contain raw font data.
 *           VIDEOPMI fontdata needs a contiguous font data which is
 *           preceeded by the count and dimensions (FONTDATA).
 *           To facilitate this, we will copy the data into a shared
 *           selector. All fonts have to fit into one 64K data segm.
 *           Fonts[x].ptr are row font data pointers at the entrance,
 *           and modified to become global FONTDATA pointers at exit.
 *
 *  ENTRY POINT: CopyGlobalFontTable
 *    LINKAGE:   CALL NEAR
 *
 *  INPUT: None
 *
 *  EXIT: 0 if OK.
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: None
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: DosAllocSeg
 *
 ****************************************************************************/
USHORT PASCAL NEAR CopyGlobalFontTable(FONTBUFFER *Fonts)
{
  USHORT j, rc = NO_ERROR;
  cp_addr  TempFont = {0};
  ULONG TotalSize= 0L;
  FARADDRESS PVB;

  /*           
   * Copy font from ROM font only if it is not supplemental font or
   * the base font of the supplemental font does exist.
   */
//            
// If a supplemental font exists and its base font doesn't,
// set the Fonts[x].PVB to NULL. Otherwise, it will trap in FindFont()
// since Fonts[x].PVB is not zero. FindFont will try to access to the font.
//
//  for (j = ROMFont8x8; j <= ROM_FONTS; j++)
//    if ((Fonts[j].PVB.p.Selector)   &&     /* if font exists */
//        ((Fonts[j].Partner == NoBaseFont) ||
//         (Fonts[Fonts[j].Partner].PVB.p.Selector)))
//      TotalSize += (ULONG) Fonts[j].PVBLen + sizeof(FONTDATA);

  for (j = ROMFont8x8; j <= ROM_FONTS; j++)
     if (Fonts[j].PVB.p.Selector)       /* if font exists */
     {
        /*
         * Allocate memory for it.
         */
        if ((Fonts[j].Partner == NoBaseFont) ||
            (Fonts[Fonts[j].Partner].PVB.p.Selector))
           TotalSize += (ULONG) Fonts[j].PVBLen + sizeof(FONTDATA);
        else
        /*
         * This font is a supplemental font and its base font doesn't exist.
         */
           Fonts[j].PVB.ptr = NULL;
     }

  if (TotalSize > 0xFFFF)
    return(INIT_ERROR);
  if (!(rc=DosAllocSeg((USHORT) TotalSize,
                       &TempFont.p.Selector,
                       SEG_GETTABLE)))
  for (j = ROMFont8x8; j <= ROM_FONTS; j++)
  {
    /*           
     * Copy font from ROM font only if it is not supplemental font or
     * the base font of the supplemental font does exist.
     */
    if ((Fonts[j].PVB.p.Selector)   &&     /* if font exists */
        ((Fonts[j].Partner == NoBaseFont) ||
         (Fonts[Fonts[j].Partner].PVB.p.Selector)))
    {
      TempFont.ptr->ulCharCount = 256;
      switch(j)
      {
        case ROMFont8x8 :
              TempFont.ptr->ulFontWidth = 8;
              TempFont.ptr->ulFontHeight = 8;
              break;
        case ROMFont8x14:
              TempFont.ptr->ulFontWidth = 8;
              TempFont.ptr->ulFontHeight = 14;
              break;
        case ROMFont9x14:
              TempFont.ptr->ulFontWidth = 9;
              TempFont.ptr->ulFontHeight = 14;
              break;
        case ROMFont8x16:
              TempFont.ptr->ulFontWidth = 8;
              TempFont.ptr->ulFontHeight =16;
              break;
        case ROMFont9x16:
              TempFont.ptr->ulFontWidth = 9;
              TempFont.ptr->ulFontHeight =16;
              break;
      }
                                                /* Allocate selector to ROM fonts  */
      PVB.FullAddress = MAKEFARPTR(Fonts[j].PVB.p.Selector,Fonts[j].PVB.p.Offset);
      PhysToUVirt(PVB, &PVB, Fonts[j].PVBLen);
      Fonts[j].PVB.p.Selector = TempFont.p.Selector;
      Fonts[j].PVB.p.Offset = TempFont.p.Offset;

      if ( Fonts[j].Partner == NoBaseFont )
         memcpy(TempFont.ptr->bFontData, PVB.FullAddress, Fonts[j].PVBLen);
      else /* 9*X Supplemental font, needs overlaying. */
      {
        USHORT  Index = 0, Dst;

        memcpy(Fonts[j].PVB.ptr->bFontData,
                Fonts[Fonts[j].Partner].PVB.ptr->bFontData,
                Fonts[Fonts[j].Partner].PVBLen );
        while ( PVB.FullAddress[Index] != 0 )
        {
           Dst = (USHORT)PVB.FullAddress[Index++] *
                   (USHORT)TempFont.ptr->ulFontHeight;

           memcpy ( Fonts[j].PVB.ptr->bFontData + Dst,
                   PVB.FullAddress + Index,
                   (USHORT)TempFont.ptr->ulFontHeight );

           Index += (USHORT)TempFont.ptr->ulFontHeight;
        } /* endwhile */

      } /* endif */

      FreePhysToUVirt(PVB.Part.Selector);    /* Deallocate selector to ROM fonts */
      TempFont.p.Offset += Fonts[j].PVBLen + sizeof(FONTDATA);  /* V2.2TSU01 */
    }

  }

  return(rc);
}
/*****************************************************************************
 *
 * SUBROUTINE NAME:  GetAccessToFonts
 *
 * DESCRIPTIVE NAME: Obtain access to shared font selectors for each new process.
 *
 * FUNCTION: ROM fonts and CODEPAGE fonts are in shared allocated data segments.
 *
 *  ENTRY POINT: GetAccessToFonts
 *    LINKAGE:   CALL NEAR
 *
 *  INPUT: None
 *
 *  EXIT:
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: None
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: DosGetSeg
 *
 ****************************************************************************/
USHORT PASCAL NEAR GetAccessToFonts(VOID)
{
   USHORT rc, rc1;

   /*           
    * Get the shared segments of ROMFont and CodePage font.
    * If either one of them succeeds, get the shared segment of
    * ROMCP_tbl.
    * Please notice that even Fonts[ROMFont8x8].PVB.p.Selector == 0,
    * DosGetSeg() will still returns 0 (successful).
    */
   rc  = DosGetSeg(Fonts[ROMFont8x8].PVB.p.Selector);
   rc1 = DosGetSeg(CodePage.p.Selector);

   if (!rc || !rc1)
      rc = DosGetSeg(RomCP_tbl.p.Selector);

   return rc;

}
/*****************************************************************************
 *
 * SUBROUTINE NAME:  SetupEnvCodePage
 *
 * DESCRIPTIVE NAME: Setup the code page for the new environment.
 *
 * FUNCTION:
 *          First, assign the ROM font 8 x 8 as the font.
 *          If code page is supported, then
 *             get the current code page idnetifier,
 *             search the ROM code page table.
 *             If found, replace the the environment font w/
 *             the current code page.
 *
 *  ENTRY POINT:     SetupEnvCodePage
 *    LINKAGE:   CALL NEAR
 *
 *  INPUT: Evironment
 *
 *  EXIT:
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: None
 *
 *  EXTERNAL REFERENCES:
 *
 ****************************************************************************/
VOID PASCAL NEAR SetupEnvCodePage(PENVIRONMENT Environment)
{
  USHORT i, usCurrentCodePage, usLength;
  ROMCP_TABLE *rcp_tbl_ptr;

  /*
  ** Initialize the environment to the first font, either
  ** ROM font or CodePage font.
  */
  Environment->pFontData = Fonts[ROMFont8x8].PVB.ptr;

  /*
  **  Initialize active code page to system first prepared
  **  if the codepage is in our table
  */

  Environment->CodePageID = ROM_FONT;

  if (CodePageSupport)
  {
    /*
     * get the current code page identifier
     */
                     /* length of the CodePageList in bytes. In this case, */
    DosGetCp (0x2,   /* only the first one (current code page) is returned */
              &usCurrentCodePage,    /* current code page                  */
              &usLength);   /* length of the returned data                 */
    rcp_tbl_ptr = RomCP_tbl.ptr;

    for ( i=0; i<ROMCP_NUM; i++, rcp_tbl_ptr++ )

       if ( usCurrentCodePage == rcp_tbl_ptr->CodePageID )
       {
          Environment->CodePageID = usCurrentCodePage;
          i = ROMCP_NUM;
          Environment->pFontData = rcp_tbl_ptr->FontPTR;
       }
  }
}

/*****************************************************************************
 *
 * FUNCTION NAME = FindCPFont()
 *
 * DESCRIPTION   = Search thru all available code page fonts to find
 *                 font which matches the specified cell dimensions
 *                 and code page. If font found, Environment
 *                 pFontData pointer set to the selected font.
 *
 * INPUT         = Environment, PelRows, PelColumns, CodePageID
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE/FALSE
 * RETURN-ERROR  =
 *
 ***************************************************************************/
USHORT FindCPFont(PENVIRONMENT Environment,
                  USHORT PelRows,
                  USHORT PelColumns,
                  USHORT CodePageID)
{
  ROMCP_TABLE *rcp_tbl_ptr = RomCP_tbl.ptr;
  USHORT j, FontFound = FALSE;

  for (j = 0; j < ROMCP_NUM && !FontFound; j++)
  {

    if (CodePageID == rcp_tbl_ptr->CodePageID &&
       (PelRows == (USHORT) ((rcp_tbl_ptr->FontPTR)->ulFontHeight)) &&
       (PelColumns == (USHORT) ((rcp_tbl_ptr->FontPTR)->ulFontWidth)))
    {
      FontFound = TRUE;
      Environment->pFontData = rcp_tbl_ptr->FontPTR;
    }

    else
      rcp_tbl_ptr++;

  }
  return FontFound;
}
