/*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 = VDHSUBS.c
 *
 * DESCRIPTIVE NAME = Base video device handlers - Private routines
 *
 *
 * VERSION      V2.0
 *
 * DATE
 *
 * DESCRIPTION  Base video device handlers - Private routines
 *
 *              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    PhysToUVirt, FreePhysToUVirt, BitNum
 *              SaveRestorePVB, ExamineConfig, SaveRestoreHW,
 *              getBIOSfonts
 *
 * NOTES        NONE
 *
 * STRUCTURES   NONE
 *
 * EXTERNAL REFERENCES  DosDevIOCtl, DosDevConfig
 *                      AccessHardware, AccessRegister
 *
 * EXTERNAL FUNCTIONS
 *
 *              NONE
 *
*/

/*
**  Include files
*/

#define  INCL_BASE                     /* ALL of OS/2 Base                  */
#define  INCL_DOSDEVICES               /* Device specific, ring 2 support   */
#define  INCL_OS2STD                   /* Needed for NULL definition in     */
                                       /* OS2STD.H                          */
#include <os2.h>
#include <memory.h>                    /*                               @T42*/
#include "vdhctl.h"                    /* Conditional compilation control   */
#include "vdh.h"                       /* Type definitions                  */

/*
**  Externally defined global variables
*/

extern VIDEOMODE Modes[];              /* Supported modes                   */
extern FONTBUFFER Fonts[];             /* Supported fonts                   */
extern MEMORYMAPS MemoryMaps[];        /* Memory map info for each mode     */
extern short HugeShift;                /* Huge shift value                  */
extern USHORT ConfigFlag;
extern ULONG PartialSaveSize;          /* Room required to save entire PVB
                                          in the popup mode                 */
extern UCHAR READABLE;                 /* Flag to determine if hardware is  */
                                       /* write-only                        */
extern USHORT VGA_PRESENT;             /* TRUE if VGA VDH has been          */
                                       /* installed                         */
extern VDHCONFIGINFO VGAConfigData;
extern USHORT(APIENTRY *ChainedCallVectorTable[MaxFn])();/*             @T24*/
extern VIDEOHARDWARE VideoHardware;    /* installed video hardware          */
extern ENVIRONMENT Env1;               /* Popup environment address         */
                                       /*                         @T42,@T42F*/
extern ENVIRONMENT Env2;               /* Harderr environment address       */
                                       /*                         @T42,@T42F*/
extern USHORT OEMFlags;                /* @MS27 */
USHORT PASCAL near GetBIOSfonts(void); /* get BIOS character font table     */
extern CLUTDATA far SumCLUT;           /*                               @BB1*/
extern CLUTDATA far *LCLUT;            /*                               @BB1*/

/*
**  Parameters to ring 2 routines
*/


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

/*
**  Internally defined global variables
*/

extern USHORT *hScreenDD;              /* Handle to screen device driver    */
                                       /* @SM04398                          */

/*****************************************************************************
 *
 *  SUBROUTINE NAME: PhysToUVirt
 *
 *  DESCRIPTIVE NAME: Allocate an LDT sel:off to physical memory
 *
 *  FUNCTION: PhysToUVirt is called by routines who need access to
 *            either the physical display buffer, or the ROM font.
 *            This routine calls the screen device driver (SCREEN$)
 *            via DosDevIOCtl who, in turn, issues a
 *            DevHlp_PhysToUVirt call.
 *
 *  ENTRY POINT: PhysToUVirt
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR *PhysicalAddress ( Physical address )
 *             FAR *LDTAddress      ( Place to return LDT sel:off )
 *             USHORT Length        ( Size of physical memory area )
 *
 *  EXIT-NORMAL: AX = 0
 *               LDT sel:off is returned to caller
 *
 *  EXIT-ERROR: AX = DosDevIOCtl error
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: DosDevIOCtl
 *
 ****************************************************************************/

USHORT near PhysToUVirt(PhysicalAddress,LDTAddress,Length)    /* @B15, @T30 */

  FarAddress PhysicalAddress;
  FarAddress far *LDTAddress;          /*                               @T30*/
  USHORT Length;

{
  USHORT rc;                           /*                               @T30*/
  USHORT rc2,ActionTaken;              /* @SM04339 */
  FarAddress ParmBlock;                /*                               @T30*/
  struct

  {
    FarAddress PhysicalAddress;
    short Length;
  }

  ParmList;

  ParmList.PhysicalAddress.FullAddress = PhysicalAddress.FullAddress;
  ParmList.Length = Length;

  if (!(rc = DosDevIOCtl((PVOID)&ParmBlock, (PVOID)&ParmList,
             0x75, 0x3, *hScreenDD)))  /*                          @T30,@T52*/
    *LDTAddress = ParmBlock;           /*                               @T30*/


/*
*/


  if (rc == ERROR_INVALID_HANDLE)
{                                    /* reopen SCREEN$                    */
    rc2 = DosOpen(SCREENDD_NAME,
                  (PHFILE)hScreenDD,   /* @SM04339 */
                  (PUSHORT)&ActionTaken,
                  NO_SIZE,
                  NO_ATTRIBUTES,
                  OPEN_IF_EXISTS,      /* @SM04339 */
                  NO_INHERIT+DENY_NONE+READ_WRITE,
                  RESERVED_LONG);      /* @SM04339 */

    if (!rc2)
    {

      if (!(rc = DosDevIOCtl((PVOID)&ParmBlock, (PVOID)&ParmList, /*@SM04339*/
           0x75, 0x3, *hScreenDD)))    /* @SM04339 */

        *LDTAddress = ParmBlock;       /* @SM04339 */
    }                                  /* endif                             */

  }                                    /* endif                             */
  return (rc);

}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: FreePhysToUVirt
 *
 *  DESCRIPTIVE NAME: Deallocate an LDT selector to physical memory
 *
 *  FUNCTION: FreePhysToUVirt is called by routines who are done
 *            accessing the memory allocated by PhysToUVirt.  This is
 *            done by calling the screen device driver (SCREEN$) via
 *            DosDevIOCtl who, in turn, issues a DevHlp_PhysToUVirt.
 *
 *  ENTRY POINT: FreePhysToUVirt
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             USHORT LDTSelector  ( LDT selector to be deallocated )
 *
 *  EXIT-NORMAL: LDT selector is deallocated
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: DosDevIOCtl
 *
 ****************************************************************************/

void near FreePhysToUVirt(LDTSelector) /*                               @B15*/

  USHORT LDTSelector;

{
  DosDevIOCtl((PVOID)NULL,
              (PVOID)&LDTSelector,
              0x71,
              0x3,
              *hScreenDD);             /*                               @T52*/
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SaveRestorePVB
 *
 *  DESCRIPTIVE NAME: Save or restore display buffer and font
 *
 *  FUNCTION: SaveRestorePVB is called by SaveEnv and RestoreEnv
 *            when either a partial or full display buffer save or
 *            restore is requested.  If graphics mode, buffer is
 *            saved/restored only if it is the 3xBox.
 *
 *  ENTRY POINT: SaveRestorePVB
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR *ParmBlock ( SaveEnv/RestoreEnv parameter block )
 *             USHORT Direction ( Either SAVE or RESTORE mode )
 *         (Referenced)
 *             Modes[] (global data - table of supported video modes )
 *             Fonts[] (global data - table of font areas )
 *             MemoryMaps[] (global data - table of memory map info )
 *
 *  EXIT-NORMAL: AX = 0
 *               Physical buffer and font area is saved or restored
 *               if text mode or if 3xBox save/restore.
 *
 *  EXIT-ERROR: AX = ERROR_VIO_MODE
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: PhysToUVirt, FreePhysToUVirt
 *              BitNum
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: Transfer
 *              SetMapMask
 *
 ****************************************************************************/

USHORT PASCAL near SaveRestorePVB(ParmBlock,Direction,SeqMapMask,Environment)
                                        /*                              @B15*/
  VDH_SAVEREST far *ParmBlock;
  USHORT Direction;
  UCHAR far *SeqMapMask;
  ENVIRONMENT far *Environment;

{

  USHORT rc,page,MapMask;              /*                               @T30*/
  UCHAR BitPlanes;

  FarAddress Source,Destination,Temp;  /*                               @T30*/
  REGDATA RegData;
  REGADDRESS RegAddress;
  USHORT BufSize;
  UCHAR TwoBufs_OnePlane;              /*                               @C25*/
  UCHAR Mode;
  UCHAR TempMode;                      /*                                @@A*/
  UCHAR MemMapMode;                    /*                               @T42*/
  USHORT Save_EnvFlags;                /*                                   */
  ENVIRONMENT far *TempEnv;            /*                                @@A*/
  ENVIRONMENT far *PopupEnv;           /*                              @T42F*/
  ENVIRONMENT far *HarderrEnv;         /*                              @T42F*/

  TwoBufs_OnePlane = MemMapMode = 0;   /*                          @T42,@C25*/

/*
**  Always save/restore the physical display buffer, even graphics mode
*/

  Save_EnvFlags = Environment->EnvFlags;         /*                         */
  Mode = TempMode = Environment->ModeIndex;/*                           @T42*/
  MapMask = 1;                         /* Initialize to Map 0           @T42*/
  BitPlanes = (UCHAR)MemoryMaps[Modes[Mode].MemMap].BitPlanes;/*        @T42*/
  Destination.FullAddress = MakeFarPTR(ParmBlock->PVBHugeSEL, 0);/*     @T42*/

  if (ParmBlock->Flags&SAVEREST_PARTPVB)
  {                                    /*                                @S4*/

  #if      VDHEGA        || VDHVGA     /* @MS00 */
    BitPlanes = 0;                     /*                               @T42*/

    if (((MemMapMode = Modes[Mode].MemMap) >= MemMap_ModeD) && /*       @T42*/
       (MemMapMode <= MemMap_Mode13))
    {                                  /*                               @T42*/
      BitPlanes = 1+2+4;               /*                               @T42*/
    }                                  /*                               @T42*/

  #endif

    TempMode = VideoHardware.popupMode;  /*                             @T42*/
    BufSize = MemoryMaps[Modes[TempMode].MemMap].PageLength;/*          @T42*/
  }

  else
  {                                    /*                                @S4*/

    if (Environment->ModeData.fbType&GRAPHICS)
    {                                  /*                           @S4,@T51*/
      BufSize = MemoryMaps[Modes[Mode].MemMap].PageLength;/*        @S4,@C25*/

      if (Modes[Mode].MemMap == MemMap_LoRes)/*                         @C25*/
        TwoBufs_OnePlane = 2;          /*                               @C25*/
    }

    else
    {                                  /*                                @S4*/
      BufSize = (USHORT)Environment->ModeData.BufferLength;/*            @S4*/
    }                                  /*                                @S4*/
  }                                    /*                                @S4*/

/*
**  Set mode for popups using a temporary environment
*/

  TempEnv = Environment;               /*                                @@A*/
  Source.FullAddress = MemoryMaps[Modes[Mode].MemMap].Start.FullAddress;

  if (Mode != TempMode)

  {                                    /*                                @@A*/
    PopupEnv = (ENVIRONMENT far *)&Env1;/*                             @T42F*/
    HarderrEnv = (ENVIRONMENT far *)&Env2;/*                           @T42F*/

    if (!PopupEnv->ModeDataOFF)
    {                                  /* Popup Env not in use?         @T42*/

      if (Direction == RESTORE)
      {                                /* Transparent restore?   @T43,@T42f */
        TempEnv = PopupEnv;            /*                         @T42,@T42F*/
        *TempEnv = *Environment;       /*                               @T43*/
      }                                /*                               @T43*/

    }                                  /*                               @T42*/

    if (HarderrEnv->ModeDataOFF)
    {                                  /* Use Harderr Env?        @T42,@T42F*/
      TempEnv = HarderrEnv;            /*                              @T42F*/
    }

    else
    {                                  /*                               @T42*/
      TempEnv = PopupEnv;              /*                          @@A,@T42F*/
    }                                  /*                               @T42*/

    if (Direction == SAVE)
    {                                  /*                               @T42*/
      *TempEnv = *Environment;         /*                                @@A*/
    }

    else
    {                                  /*                               @T42*/
      *Environment = *TempEnv;         /*                               @T42*/
    }                                  /*                               @T42*/

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

    if ((BitPlanes)                    /*                               @T42*/

    #if      VDHVGA
         || (Mode == ModeIndex_VGC2E)
    #endif

       )

    {
      BufSize = MemoryMaps[Modes[Mode].MemMap].PageLength;/*            @T42*/
    }                                  /*                               @T42*/

  #endif
  }                                    /*                                @@A*/

/*
**  Save/restore all bit planes ( if mode has more than one )
*/

  if (!(rc = PhysToUVirt(Source, &Temp, BufSize)))
  {                                    /*                               @T30*/
    Source = Temp;                     /*                               @T30*/

    if ((Environment->ModeData.attrib == WorldAttrCount) && /*           @P1*/
       !(Environment->ModeData.fbType&GRAPHICS))

    {                                  /*                                @P1*/
      rc = LVB3PVBTransfer(Environment, ParmBlock, Direction);/*         @P1*/
    }

    else
    {                                  /*                                @P1*/

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

    #if      VDHVGA

      if (Mode == ModeIndex_VGC2E)

      { /* Unlock extended VGA graphics regs */
        RegAddress.AddressPort = GraphAddressPort;
        RegAddress.DataPort = GraphDataPort;
        RegAddress.Flags = NONE;
        RegData.DataArea = (UCHAR far *)&page;
        RegData.FirstEntry = VGA_ENV_REG;
        RegData.NumEntries = 1;
        page = VGA_UNLOCK;
        AccessHardware(&RegAddress, BYTES, NONE, SET, &RegData);
        RegData.FirstEntry = 0x45;

        if (Mode == TempMode)
        {
          RegData.NumEntries = 2;

          for (page = 0x0800; page <= 0x7870; page += 0x1010)
          {
            AccessHardware(&RegAddress, BYTES, NONE, SET, &RegData);
            Source.part.Offset = (page == 0x7870)?32*1024:0;

            do
            {
              Source.part.Offset -= 1024;
              Transfer(&Source, &Destination, 640, Direction);
            }

            while (Source.part.Offset);
          }
        }

        else
        {

          for (page = 0x00; page <= 0x20; page += 0x20)
          {
            AccessHardware(&RegAddress, BYTES, NONE, SET, &RegData);
            Transfer(&Source, &Destination, 8*1024, Direction);
          }
        }
      }

      else
    #endif

/*
**  Address a bitplane (some modes use same memory for all bitplanes)
*/

           do
        {

          if (BitPlanes)
          {                            /* Modes D, E, F, 10, and 12         */

            while (!(BitPlanes&MapMask))
            {                          /* Get next active bit               */
              MapMask <<= 1;
            }

            SetMapMask(Direction == RESTORE?WriteFunction:BitNum(MapMask),
               MapMask);

            BitPlanes &= ~MapMask;     /* Reset the bit just processed      */

            if (Mode != TempMode)
            {                          /*                               @T42*/
              BufSize = 4000;          /*                               @T42*/

              if (MapMask == 4)
              {                        /*                               @T42*/
                BufSize = 8192;        /*                               @T42*/

                if (MemMapMode == MemMap_ModeD)
                {                      /*                               @T42*/
                  BufSize = 8000;      /*                               @T42*/
                }                      /*                               @T42*/
              }                        /*                               @T42*/
            }                          /*                               @T42*/
          }

          else

            if (TwoBufs_OnePlane)
            {                          /*                               @C25*/
              TwoBufs_OnePlane--;      /*                               @C25*/

              if (!TwoBufs_OnePlane)   /*                               @C25*/
                Source.FullAddress = MakeFarPTR(Source.part.Selector, 8192);/*
                                                                        @C25*/

              else                     /*                               @C25*/
                BufSize = 8000;        /*                               @C25*/
            }                          /*                               @C25*/

          Transfer(&Source, &Destination, BufSize, Direction);
        }

        while (BitPlanes || TwoBufs_OnePlane);/*                        @C25*/

/*
**  For graphics modes D, E, F, 10, and 12, that Sequencer Map Mask
**  register was altered in order to save/restore each of the
**  individually address-selected bit planes.  After each save/restore,
**  the Map Mask address-selected bit planes.  On each restore, the
**  Map Mask register is set to its original value.
**
**  Note:  This procedure is not necessary during a save because the
**         hardware state is saved before the display buffer is saved.
*/

      if ((MapMask != 1)           /* Bit planes were selected individually */
         && (Direction == RESTORE))
      {
        SaveRestoreHW(Environment, SET);/*                              @T47*/
      }

  #else

      do
      {                                /*                               @C25*/

        if (TwoBufs_OnePlane)
        {                              /*                               @C25*/
          TwoBufs_OnePlane--;          /*                               @C25*/

          if (!TwoBufs_OnePlane)       /*                               @C25*/
            Source.FullAddress = MakeFarPTR(Source.part.Selector, 8192);/*
                                                                        @C25*/

          else                         /*                               @C25*/
            BufSize = 8000;            /*                               @C25*/
        }                              /*                               @C25*/

        Transfer(&Source, &Destination, BufSize, Direction);/*          @C25*/
      }

      while (TwoBufs_OnePlane);        /*                               @C25*/

  #endif
    }                                  /*                                @P1*/

    FreePhysToUVirt(Temp.part.Selector);/*                              @T30*/
  }

  #if      FONT_SUPPORT                /* @MS00 */

/*
**  Save/Restore font buffer if in text mode
*/

  if (!rc && !(Modes[Mode].fbType&GRAPHICS) && /*                       @T53*/
      (Direction == RESTORE))

  {                                    /*                               @T70*/
    TempEnv->EnvFlags = Save_EnvFlags; /*                                   */
    rc = SetHWFont(TempEnv, TempEnv->ActiveFontPTR, /*   @@A @T42,@T53      */
                   (UCHAR far *)PHYSICAL_FONT_BUFFER);
  }

  #endif

/*
**  Restore mode after popup and deallocate the temporary environment
*/

  if (!rc && (Mode != TempMode))
  {                                    /* @@A, @T42F                        */

    if (Direction == RESTORE)
    {                                  /*                                @@A*/

      TempEnv->ModeDataOFF = 0;        /*                         @T42,@T42F*/
    }                                  /*                                @@A*/
  }                                    /*                                @@A*/
  return (rc?ERROR_VIO_MODE:0);
}

/***************************************************************************
 *
 * FUNCTION NAME =
 *
 * DESCRIPTION   = Return bit number which is set ( called by SaveRestorePVB )
 *
 * INPUT         = BitMask
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

USHORT PASCAL near BitNum(BitMask)     /*                               @B15*/

USHORT BitMask;

{
  USHORT i;


  for (i = 0; !(BitMask&1); i++)
    BitMask >>= 1;

  return (i);
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SaveRestoreHW
 *
 *  DESCRIPTIVE NAME: Save or restore hardware state
 *
 *  FUNCTION: SaveRestoreHW is called to save or restore the hardware
 *            state.
 *
 *  ENTRY POINT: SaveRestoreHW
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             ENVIRONMENT far *Environment
 *             USHORT Direction  ( GET(for SAVE) or SET(for RESTORE) )
 *
 *  EXIT-NORMAL: Hardware state is saved or restored to or from the
 *               environment buffer.
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: AccessHardware, AccessRegister, AccessCLUT
 *
 ****************************************************************************/

void PASCAL near SaveRestoreHW(Environment,Direction)/*                 @B15*/

ENVIRONMENT far *Environment;
USHORT Direction;

{

  REGDATA RegData;
  REGADDRESS RegAddress;
  USHORT ColorMode;
  UCHAR One = 0x01;
  USHORT VideoEnable;
  UCHAR TempChar;
  UCHAR TempMiscOut;                   /*                              @TB25*/
  int SumCLUT_found,i,j;               /*                               @BB1*/

  #if      VDHVGA                      /* @MS00 */

  ColorMode = (Direction == SET) ? (USHORT)(Environment->ModeData.fbType
     & NOT_MONO) : HardwareColor();       /* color/mono mode?                  */

  #else
  ColorMode = (USHORT)(Environment->ModeData.fbType & NOT_MONO); /* SET only   */

  if (Direction == GET)
    return ;

  #endif

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

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

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

    #if      VDHVGA                    /*                          @T56,@MS00*/

/*
**  IF RESTORE, SET MISC OUTPUT REG TO 25 MHZ CLOCK
*/

  if (Direction == SET)
  {
    RegAddress.DataPort = MiscOutputRegWrite;
    TempMiscOut = Environment->Hardware.MiscOutputReg;
    Environment->Hardware.MiscOutputReg &= 0xF3;
    AccessRegister(&RegAddress, Direction, &Environment->Hardware.
                   MiscOutputReg);
  }

    #endif

/*
**  Save/Restore the sequencer registers
*/

  RegAddress.AddressPort = SeqAddressPort;
  RegAddress.DataPort = SeqDataPort;
  RegAddress.ColorAdjust = NONE;
  RegAddress.Flags = Sequencers_CMD;
  RegData.DataArea = &Environment->Hardware.Sequencers.All
                               [RegData.FirstEntry = 0x00];
  RegData.NumEntries = 0x04+1;         /* All registers                     */
  AccessHardware(&RegAddress, BYTES, ColorMode, Direction, &RegData);

    #if      VDHEGA                    /*                          @T56,@MS00*/

/*
**  Save/Restore the miscellaneous output register
*/

    RegAddress.DataPort = Direction == GET ? MiscOutputRegRead:
    MiscOutputRegWrite;                /*                               @T56*/
    AccessRegister(&RegAddress, Direction,             /*               @T56*/
                   &Environment->Hardware.MiscOutputReg);
    #endif
  #endif

  #if      VDHCGA                      /* MS?? - BEGIN */

  if (OEMFlags&IDC_CGA)
  {
    RegAddress.DataPort = IDCExtendedModeReg;
    AccessRegister(&RegAddress, GET, &TempChar);

    if (Direction == GET)
    {
                /* Save just extended mode bit */
      Environment->Hardware.IDCExtendedMode = TempChar & 0x01;
    }

    else
    {           /* Direction == SET               */
                /* Restore just extended mode bit */
      TempChar &= ~0x01;
      TempChar |= Environment->Hardware.IDCExtendedMode;
      AccessRegister(&RegAddress, SET, &TempChar);
    }
  }
  #endif

  #if      VDHMPA                      /* @MS00 */

  RegAddress.DataPort = CRTCtlPort1;
  AccessRegister(&RegAddress, Direction, &One);

  #endif

/*
**  Save/Restore the CRT registers
*/

  RegAddress.AddressPort = CRTAddressPort;
  RegAddress.DataPort = CRTDataPort;
  RegAddress.ColorAdjust = ColorAdjustment;
  RegAddress.Flags = NONE;

  #if      VDHVGA                      /* @MS00 */

  if (Direction == SET)
  {
    RegData.DataArea = &Environment->Hardware.CRTCtlRegs.All
                      [RegData.FirstEntry = 0x11];
    RegData.DataArea[0] &= 0x0F;       /* Clear b4-b7 of vert retrace end   */
    RegData.NumEntries = 1;            /* vert retrace end                  */
    AccessHardware(&RegAddress, BYTES, ColorMode, SET, &RegData);
  }

  #endif

  RegData.DataArea = &Environment->Hardware.CRTCtlRegs.All[RegData.FirstEntry
     = 0x00];

  #if      VDHVGA                      /* @MS00 */

  if (Direction == SET)
    RegData.DataArea[0x11] |= 0x80;    /* Set b4-b7 of vert retrace end     */
  #endif

  #if      VDHMPA        || VDHCGA     /* @MS00 */
  RegData.NumEntries = 0x10;           /* CGA and MPA only have 16
                                          registers                    @TL10*/

  #else                                /*                              @TL10*/
  RegData.NumEntries = 0x18+1;         /* All registers                     */

  #endif

  AccessHardware(&RegAddress, BYTES, ColorMode, Direction, &RegData);

  #if      VDHCGA                      /* @MS00 */

  RegAddress.DataPort = CGAModeCtlReg;
  AccessRegister(&RegAddress, Direction,
                 &Environment->Hardware.CGAModeControl );

  RegAddress.DataPort = CGAColorSelReg;
  AccessRegister(&RegAddress, Direction,
                 &Environment->Hardware.CGAColorSelect );
  #endif

  #if      VDHMPA                      /* @MS00 */

  RegAddress.DataPort = CRTCtlPort1;
  AccessRegister(&RegAddress, Direction,
                 &Environment->Hardware.MPAModeControl );
  #endif

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

    #if      VDHVGA                    /*                          @T56,@MS00*/

/*
**  SAVE/RESTORE THE MISCELLANEOUS OUTPUT REGISTER
*/

    RegAddress.DataPort = Direction == GET ? MiscOutputRegRead:
    MiscOutputRegWrite;

  if (Direction == SET)                /*                              @TB25*/
    Environment->Hardware.MiscOutputReg = TempMiscOut;/*               @TB25*/

    AccessRegister(&RegAddress, Direction,
                   &Environment->Hardware.MiscOutputReg) ;
    #endif

/*
**  Save/Restore the attribute registers
*/

  RegAddress.AddressPort = AttAddressPort;
  RegAddress.DataPort = Direction == GET ? AttDataReadPort:
  AttDataWritePort;
  RegAddress.ColorAdjust = NONE;
  RegAddress.Flags = Attributes_CMD;
  RegData.DataArea = &Environment->Hardware.Attributes.All
                     [RegData.FirstEntry = 0x00];

  RegData.NumEntries = NUM_ATT_REGS;   /* All registers                     */
  AccessHardware(&RegAddress, BYTES, ColorMode, Direction, &RegData);

    #if      VDHEGA                    /* @MS00 */

/*
**  Restore the graphics position registers
*/

  RegAddress.DataPort = Graphics1PosReg;
  AccessRegister(&RegAddress, SET, &Environment->Hardware.Graphics1Position);
  RegAddress.DataPort = Graphics2PosReg;
  AccessRegister(&RegAddress, SET, &Environment->Hardware.Graphics2Position);

    #endif

/*
**  Save/Restore the graphics registers
*/

  RegAddress.AddressPort = GraphAddressPort;
  RegAddress.DataPort = GraphDataPort;
  RegAddress.ColorAdjust = NONE;
  RegAddress.Flags = NONE;
  RegData.DataArea = &Environment->Hardware.GraphicsRegs
                     [RegData.FirstEntry = 0x00];

  RegData.NumEntries = 0x08+1;         /* All registers                     */
  AccessHardware(&RegAddress, BYTES, ColorMode, Direction, &RegData);

    #if      VDHVGA

  if (OEMFlags&STARDUST_VGA)

  { /* Unlock extended registers */
    RegData.DataArea = &TempChar;
    RegData.FirstEntry = VGA_ENV_REG;
    RegData.NumEntries = 1;
    TempChar = VGA_UNLOCK;
    AccessHardware(&RegAddress, BYTES, NONE, SET, &RegData);

    /*
    ** Save/restore STARDUST extended graphics registers.
    */
    RegData.DataArea = Environment->Hardware.ExtVGARegs;
    RegData.FirstEntry = 0x40;
    RegData.NumEntries = 0x07;
    AccessHardware(&RegAddress, BYTES, ColorMode, Direction, &RegData);

    /*
    ** Save/restore state of STARDUST DAC (6 bit or 8 bit
    */
    RegAddress.DataPort = DACCmdReg;
    AccessRegister(&RegAddress, GET, &TempChar);

    if (Direction == GET)
    {
      /*
      ** Save just the DAC state b
      */
      Environment->Hardware.DACCmd = TempChar & 0x02;
    }

    else
    { /* Direction == SET               */
      /* Restore just the DAC state bit */
      TempChar &= ~0x02;
      TempChar |= Environment->Hardware.DACCmd;
      AccessRegister(&RegAddress, SET, &TempChar);
    }
  }
    #endif
  #endif

  #if      VDHVGA                          /* @MS00 */

/*
**  Save/Restore the color lookup table
*/

  RegData.DataArea = (UCHAR far *)&Environment->LookupTable
                     [RegData.FirstEntry = 0x00];
  RegData.NumEntries = 0xFF+1;         /* All registers                     */
  AccessCLUT(Direction, (CLUTDATA far *far *)&RegData);/* ring 2 callgate   */

/*
**  If the current CLUT is equivalent to SumCLUT set NO_CLR_BRST in fbtype
*/

  if ((Direction == SET)               /*                               @BB1*/
     && ((Environment->ModeData.fbType&NOT_MONO) == NOT_MONO))
  {                                    /*                               @BB1*/
    register irow = 0;


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

      irow++;

    /*
    ** If loop completed, assume black & whi
    */

    if (irow == 0xFF+1)
      Environment->ModeData.fbType |= NO_CLR_BRST;
  }                                    /*                               @BB1*/

  if (Direction == SET)
  {
    SetTextGrays(Environment);
  }

/*
**  Turn the video signal back on if Env flag is set@C21
*/

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

  Environment->Hardware.Sequencers.Regs.ClockingMode &= 0xDF;

/*
**  Interpret registers and update the mode data structure in the ENVB
*/

  #endif
}

#endif

/*****************************************************************************
 *
 *  SUBROUTINE NAME: ExamineConfig
 *
 *  DESCRIPTIVE NAME: Examine display adapter configuration
 *
 *  FUNCTION: ExamineConfig is called by DevInit in order to verify
 *            the presence of the appropriate display adapter.
 *            In addition, info is obtained for late use by
 *            RetConfigInfo.  Starting addresses for ROM fonts are
 *            obtained.
 *
 *  ENTRY POINT: ExamineConfig
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             NONE
 *         (Referenced)
 *             Modes[] (global data - table of supported video modes )
 *             Fonts[] (global data - table of font areas )
 *
 *  EXIT-NORMAL: AX = 0
 *
 *  EXIT-ERROR: AX = ERROR_VIO_BAD_ADAPTER or
 *                   DosDevConfig error
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: PhysToUVirt, FreePhysToUVirt
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: DosDevConfig, CharFontBegin, CharFontEnd
 *
 ****************************************************************************/

short PASCAL near ExamineConfig()      /*                               @B15*/

{
  USHORT ROMFontSEL,ROMFontLEN,ROMSrchLEN,rc,i;/*                        @S9*/
  EGABIOSINFO EGAInfo;                 /* EGA information from 40:86, 40:87 */
  FarAddress PhysAddress,PVB;

#if      VDH8514A                      /* @MS00 */

  union
  {

    USHORT Flags;

    struct
    {
      UCHAR Display;
      UCHAR Memory;
    }
    part;
  }

  A8514;
  VDH_CONFIG VGAParmBlock;

#endif

#if      VDHVGA                        /* Read/write hardware               */
                                        /* @MS00 */
  READABLE = TRUE;

#else
  READABLE = FALSE;
#endif
  rc = INIT_ERROR;                     /* Initially, assume error           */

  /*
  ** getvideoType fails only if something is seriously
  **       with the video system
  */

  if (getVideoType() != VDHERROR_NO_ADAPTER)
  {

/*
**  Display types:
**                 0 - 5151 mono             5 - IBM Japan 5550 mono
**                 1 - 5153 color            6 - IBM Japan 5550 color
**                 2 - 5154 enhanced         7 - IBM Japan 5570 color
**                 3 - 8503 mono             8 - IBM Japan 5570 full page
**                 4 - 8512/8513 color       9 - 8514 color
**                                          10 - PDP (Plasma Display Panel)
**                                          11 - 8507_8604 mono
**                                          12 - 8515 color
*/

#if      VDHVGA                        /* @MS00 */

    if (VideoHardware.fVideoType & VGA_BITS)
    {
      rc = NO_ERROR;                   /* at this point the installation    */
                                       /* will work                         */

/*
**  If the VGA doesn't have a display attatched to it, the VDH should fail
**  to install UNLESS an 8514/A is present and has a display.
*/

      if (VideoHardware.display == NoDisplay && !(VideoHardware.fVideoType
         &A8514_BITS))

        rc = INIT_ERROR;
    }

#endif

#if      VDHEGA                        /* @MS00 */

    if (VideoHardware.fVideoType&EGA_BITS)
      rc = NO_ERROR;                   /* allow installation to continue    */
#endif

#if      VDHCGA                        /* @MS00 */

/*
** If this VDH can install on the current hardware set up information
*/

    if (VideoHardware.fVideoType&CGA_BIT)
      rc = NO_ERROR;                   /* allow installation                */

#endif

#if      VDHMPA                        /* @MS00 */

/*
** if this VDH can install on the current hardware set up information
*/

    if (VideoHardware.fVideoType&MPA_BIT)
      rc = NO_ERROR;                   /* allow installation                */

#endif

#if      VDH8514A                      /* @MS00 */

/*
** if 8514 present record its configuration
*/

    if (VideoHardware.fVideoType&A8514_BITS)
    {
      rc = NO_ERROR;                   /* allow installation                */

/*
**  The presence of the VGA VDH is determined by a successful call to
**  RetConfigInfo in the call vector table
*/

      VGAParmBlock.Length = sizeof(VDH_CONFIG);
      VGAParmBlock.Flags = NONE;
      VGAParmBlock.ConfigDataPTR = (VDHCONFIGINFO far *)&VGAConfigData;
      VGAConfigData.cb = MinDLen_Config_PartSaveSz;/* Only need display     */
                                              /* type and partial save size */
      VGA_PRESENT = !ChainedVDHRetConfigInfo((ENVIRONMENT far *)NULL,
         (VDH_INITENV far *)&VGAParmBlock, FnReturnConfigInfo);
    }

#endif

    if (!rc)
    {                                  /* Error Check #3                    */

#if      ROMFONT_SUPPORT               /* @MS00 */

/*
** 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.  This is not done on
** MPA or CGA systems.
**
** 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 MPA and CGA do not support this interrupt so these cards will
** always use the pattern search.
**
** 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.
*/

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

      if (GetBIOSfonts() == NOBIOSFONTS)
      {                                /*                               @T36*/

      /*
      ** 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:
**            F0000 - CGA and MPA
**            C0000 - EGA and PS/2 Adapter
**            E0000 - VGA
*/

        for (ROMFontSEL = 0x0E, ROMFontLEN = 0xFFFF, ROMSrchLEN = 0xFFF0; /*
                                                                    @S9,@S12*/
           ROMFontSEL >= 0x0C;         /*                               @S12*/
           ROMFontSEL -= 2, ROMFontLEN -= 0x8000, ROMSrchLEN = 0x7FF0)

        {                              /*                            @S5,@S9*/
          PVB.FullAddress = MakeFarPTR(ROMFontSEL, 0);
          PhysToUVirt(PVB, &PVB, ROMFontLEN);/*                         @T30*/

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

          for (i = 0; i < ROMSrchLEN; i++)
          {                            /*                                @S9*/

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

            if (i < ROMSrchLEN)
            {                          /*                                @S9*/

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

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

                {
                  Fonts[FONT_8x8].PVB.part.Selector = ROMFontSEL;
                  Fonts[FONT_8x8].PVB.part.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[FONT_8x14].PVB.part.Selector &&
                      PVB.FullAddress[i+8] != (UCHAR)0x81)
                  {
                    Fonts[FONT_8x14].PVB.part.Selector = ROMFontSEL;
                    Fonts[FONT_8x14].PVB.part.Offset = i-16;
                  }

    #if      VDHVGA                    /* @MS00 */


/*
**  Locate 8x16 ROM font on VGA, and PS/2 adapter only
*/

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

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

          for (i = 0; i < ROMSrchLEN; i++)
          {                            /*                                @S9*/

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

            if (i < ROMSrchLEN)
            {                          /*                                @S9*/

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

                if (!Fonts[FONT_9x14].PVB.part.Selector  &&
                   (PVB.FullAddress[i+5] == (UCHAR)0x24) &&
                   (PVB.FullAddress[i+6] == (UCHAR)0x66))
                {
                  Fonts[FONT_9x14].PVB.part.Selector = ROMFontSEL;
                  Fonts[FONT_9x14].PVB.part.Offset = i;
                }

    #if      VDHVGA                    /* @MS00 */

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

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

          FreePhysToUVirt(PVB.part.Selector);/* Deallocate selector to ROM  */
                                       /* font area                     @T30*/
        }                              /* Search next ROM segment for       */
                                       /* fonts,                         @S5*/
      }                                /* use search code               @T36*/

  #else

      Fonts[FONT_8x8].PVB.part.Selector = 0x0F;/* Use BIOS default      @T64*/
      Fonts[FONT_8x8].PVB.part.Offset = 0x0FA6E;/*                      @T64
                                                                        @T64*/
  #endif

/*
**  If all fonts were not found, then
**  initialization fails
*/


      if ((!Fonts[FONT_8x8].PVB.part.Selector)

      /*
      ** 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      FONT_SUPPORT
           || (Fonts[FONT_8x8].PVB.part.Offset == 0xFA6E)
  #endif

         )
        rc = INIT_ERROR;               /* @MS22 - END */

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

      if (!Fonts[FONT_8x14].PVB.part.Selector || !Fonts[FONT_9x14].
         PVB.part.Selector)
        rc = INIT_ERROR;

  #endif

  #if      VDHVGA                      /* @MS00 */

      if (!Fonts[FONT_8x16].PVB.part.Selector || !Fonts[FONT_9x16].
         PVB.part.Selector)
        rc = INIT_ERROR;

  #endif
#endif

      if (!rc)
      {                                /* Error Check #5                    */

/*
**  Initialize values used in RetConfigInfo and GetMode
**--------------------------------------------------------------------------
**  All devices which support text modes can be powerup displays,
*/

#if      VDH8514A                      /*                         @S16,@MS00*/
ConfigFlag |= VGA_PRESENT?POWERUP:0;   /*                               @S16*/

#else                                  /*                               @S16*/

 #if      VDHMPA                       /* fix: Only 1 popup device          */
                                       /* @MS23 - BEGIN */
/*
*/

        if (VideoHardware.fVideoType == MPA_BIT)
  #endif
             ConfigFlag |= POWERUP;    /*                               @S16*/
#endif

/*
**  If power-up display, partial save size = 80x25x2 + maximum font length
**  If not power-up display, partial save size = 0 ( never a popup )
*/

#if      VDH8514A                      /* @MS00 */
        PartialSaveSize = VGA_PRESENT ? VGAConfigData.PartSaveSize : UNKNOWN;

#else

  #if      VDHVGA

        if (OEMFlags & STARDUST_VGA)
           PartialSaveSize = 16L * 1024L;

        else
  #endif
           PartialSaveSize = 80L * 25L * 2L    /* 80x25 text PVB               */

  #if      FONT_SUPPORT                        /* @MS00 */
            + 256L *                           /* Font length                  */

            (ULONG)((USHORT)Modes[VideoHardware.popupMode].vres / (USHORT)Modes
                [VideoHardware.popupMode].row)
  #endif
             ;
#endif
      }                                /* Error Check #5                    */
    }                                  /* Error Check #3                    */
  }                                    /* Error Check #1                    */

  return (rc);
}

#if      ROMFONT_SUPPORT               /*                          @T36,@MS00*/

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

/*****************************************************************************
 *
 * 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.
 *
 *  Note:    GetBiosFonts does not apply to MPA/CGA hardware
 *
 *  ENTRY POINT: GetBIOSfonts
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: None
 *
 *  EXIT: NOBIOSFONTS if not 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 (videoIoctl((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[FONT_8x14].PVB.FullAddress = (UCHAR far *)REALTO32BITADDR
                                     (fontTable[0] );

  Fonts[FONT_8x8].PVB.FullAddress  = (UCHAR far *)REALTO32BITADDR
                                     (fontTable[1]) ;

  Fonts[FONT_9x14].PVB.FullAddress = (UCHAR far *)REALTO32BITADDR
                                     (fontTable[3] );

    #if      VDHVGA                    /*                          @T37,@MS00*/

  Fonts[FONT_8x16].PVB.FullAddress = (UCHAR far *)REALTO32BITADDR
                                       (fontTable[4]);

  Fonts[FONT_9x16].PVB.FullAddress = (UCHAR far *)REALTO32BITADDR
                                     (fontTable[5]);

    #endif
  return  BIOSFONTSFOUND;

}

  #endif
#endif

#if      VDH8514A                      /* @MS00 */

/*****************************************************************************
 *
 *  SUBROUTINE NAME: LeaveNativeMode
 *
 *  DESCRIPTIVE NAME: 8514/A is forced out of Native Mode
 *
 *  FUNCTION: This routine is called to force the 8514/A out of Native
 *            Mode to allow VGA passthru.
 *
 *  ENTRY POINT: LeaveNativeMode
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: None
 *
 *  EXIT-NORMAL: 8514/A is taken out of Native Mode
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: None
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: AccessRegister
 *
 ****************************************************************************/

void PASCAL near LeaveNativeMode()     /*                               @B15*/

{

  UCHAR RegValue;
  REGADDRESS RegAddress;

  RegAddress.DataPort = 0x22E8;
  RegValue = 0x53;
  AccessRegister(&RegAddress, SET, (UCHAR far *)&RegValue);
  RegAddress.DataPort = 0x4AE8;
  RegValue = 0x02;
  AccessRegister(&RegAddress, SET, (UCHAR far *)&RegValue);
  RegAddress.DataPort = 0x02E8;
  RegValue = 0x0A;
  AccessRegister(&RegAddress, SET, (UCHAR far *)&RegValue);
  RegAddress.DataPort = 0x22E8;
  RegValue = 0x33;
  AccessRegister(&RegAddress, SET, (UCHAR far *)&RegValue);
  RegAddress.DataPort = 0x02EA;
  RegValue = 0xFF;
  AccessRegister(&RegAddress, SET, (UCHAR far *)&RegValue);
}

#endif

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

/*****************************************************************************
 *
 *  SUBROUTINE NAME: LVB3ToPVB
 *
 *  DESCRIPTIVE NAME: Restore the PVB from a World format LVB
 *
 *  FUNCTION: LVB3ToPVB is called by SaveRestorePVB to restore the PVB
 *            when the environment indicates the calling process is
 *            in a text mode using the world format id and attribute
 *            count.
 *
 *  ENTRY POINT: LVB3ToPVB
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR *ParmBlock ( SaveEnv/RestoreEnv parameter block )
 *             FAR *Environment
 *
 *  EXIT-NORMAL: AX = 0
 *               Physical buffer restored
 *
 *  EXIT-ERROR: AX = ERROR_VIO_MODE
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES:
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES:
 *
 ****************************************************************************/

USHORT EXPENTRY LVB3PVBTransfer(Environment,ParmBlock,Direction)/*       @P1*/

  ENVIRONMENT far *Environment;        /*                                @P1*/
  VDH_SAVEREST far *ParmBlock;         /*                                @P1*/
  USHORT Direction;                    /*                                @P1*/

{                                      /*                                @P1*/
  VDH_BUFUP BufParms;                  /*                                @P1*/
  char far *pch;                       /*                                @P1*/
  USHORT rc;                           /*                                @P1*/

  BufParms.Length = sizeof(BufParms);  /*                                @P1*/
  BufParms.Flags = BU_PVB_SEL_BIT;     /*                                @P1*/

  if (Direction == RESTORE)            /*                                @P1*/
    BufParms.Index = bu_WriteCellStr;  /*                                @P1*/

  else                                 /*                                @P1*/
    BufParms.Index = bu_ReadCellStr;   /*                                @P1*/

  BufParms.StartRow = 0;               /*                                @P1*/
  BufParms.StartCol = 0;               /*                                @P1*/
  BufParms.RepeatFactor = Environment->ModeData.col *             /*     @P1*/
                          Environment->ModeData.row *             /*     @P1*/
                         (Environment->ModeData.attrib+1);        /*     @P1*/

  BufParms.LogicalBufSel = ParmBlock->PVBHugeSEL;/*                      @P1*/
  pch = NULL;                          /*                                @P1*/
  *((unsigned *)&pch+1) = ParmBlock->PVBHugeSEL;/*                       @P1*/
  BufParms.AppDataAddr = pch;          /*                                @P1*/
  BufParms.AppCellAddr = NULL;         /*                                @P1*/
  rc = BufferUpdate(Environment, &BufParms, FnTextBufferUpdate);/*       @P1*/
  return (rc);                         /*                                @P1*/
}                                      /*                                @P1*/

#endif

#if      INTEXT_SUPPORT                /* @MS24 - BEGIN */

/*****************************************************************************
 *
 * FUNCTION NAME  = IntExtState(Op)
 *
 * DESCRIPTION    = Used to direct video output to either the internal or
 *                  external monitor for adapters that support dual monitors,
 *                  and for inquiring which one is currently selected.
 *
 *                  Call with Op == Internal_Monitor or External_Monitor to
 *                  select the monitor to receive video output.
 *
 *                  If Op == VST_EXTFLG, Internal_Monitor or External_Monitor
 *                  is returned depending on which one is currently active.
 *
 * INPUT:       Op
 *
 * OUTPUT:      None
 *
 * RETURNS:     Monitor status (Internal_Monitor or External_Monitor)
 *
 ****************************************************************************/

USHORT PASCAL near IntExtState(Op)

USHORT Op;

{
  REGADDRESS RegAddress;
  REGDATA RegData;
  UCHAR IntExtReg;
  UCHAR DataArea[2];

  RegAddress.Flags = NONE;
  RegData.DataArea = DataArea;
  RegData.NumEntries = 1;

  #if      VDHVGA

  if (OEMFlags & (PRISM_VGA | CRYSTAL_VGA))
  {
    RegAddress.AddressPort = GraphAddressPort;
    RegAddress.DataPort = GraphDataPort;

    /*
    ** Open access to extended VGA register
    */
    RegData.FirstEntry = VGA_ENV_REG;
    RegData.DataArea[0] = VGA_UNLOCK;
    AccessHardware(&RegAddress, BYTES, NONE, SET, &RegData);

    /*
    ** Read current monitor setting
    */
    RegData.FirstEntry = VGA_CONFIG_REG;
    AccessHardware(&RegAddress, BYTES, NONE, GET, &RegData);
    IntExtReg = DataArea[0];

    switch (Op)
    {
      case  External_Monitor :         /* Switch to CRT */
        IntExtReg |= LCD_EXTERNAL;
        AccessRegister(&RegAddress, SET, &IntExtReg);
        break;

      case  Internal_Monitor :         /* Switch to LCD */
        IntExtReg &= ~LCD_EXTERNAL;
        AccessRegister(&RegAddress, SET, &IntExtReg);
        break;

      case  VST_EXTINT :               /* Return active monitor */

        if (IntExtReg&LCD_EXTERNAL)
          Op = External_Monitor;

        else
          Op = Internal_Monitor;

        break;

    } /* Close access to extended VGA registers */

    RegData.FirstEntry = VGA_ENV_REG;
    RegData.DataArea[0] = VGA_LOCK;
    AccessHardware(&RegAddress, BYTES, NONE, SET, &RegData);
  }

  #endif

  return (Op);
}

#endif
                                                               /*@MS25 - BEGIN */

/*****************************************************************************
 * FUNCTION NAME = ReadCMOS(Index)
 *
 * DESCRIPTION   = This function is used to read a byte out of CMOS
 *                 configuration memory.
 *
 * INPUT     =  Index
 *
 * OUTPUT:      None
 *
 * RETURNS:     Value read from CMOS
 *
 ****************************************************************************/

UCHAR PASCAL near ReadCMOS(Index)

UCHAR Index;                         /* Index into CMOS */

{
  HFILE hDev;
  USHORT usAction;
  UCHAR CMOSRqst[2];
  UCHAR CMOSByte;

  CMOSRqst[0] = Index;
  CMOSRqst[1] = 1;                     /* Read 1 byte */
  CMOSByte = 0;                        /* default to 0 if error occurs */

  if (!DosOpen("CLOCK$", (PHFILE)&hDev, (PUSHORT)&usAction, NO_SIZE,
     NO_ATTRIBUTES, FILE_OPEN, OPEN_ACCESS_READONLY|OPEN_SHARE_DENYNONE,
     RESERVED_LONG))

  {
    DosDevIOCtl((PVOID)&CMOSByte,
                (PVOID)CMOSRqst,
                (USHORT)0x60,          /* function */
                (USHORT)13,            /* category */
                hDev);
    DosClose(hDev);
  }

  return (CMOSByte);

}                                      /* @MS25 - END */

