/*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 = VDHMAIN.c
 *
 * DESCRIPTIVE NAME = Base video device handlers - Initialization,
 *                                                 Save/Restore &
 *                                                 Get/FreePhysBuf
 *
 *
 * VERSION      V2.0
 *
 * DATE
 *
 * DESCRIPTION  This source is compiled conditionally to produce 5
 *              distinct video device handlers ( dynalink libraries )
 *              for support of either MPA, CGA, EGA, VGA/PS2 adapter, or
 *              8514/A display adapters.  The video device handlers
 *              each consist of hardware dependent functions, which are
 *              invoked directly by the OS/2 base video subsystem.
 *
 *              To direct the compiler to build each video device handler,
 *              a unique symbol must be defined via the '-D' compile
 *              switch for each one.  These symbols are:
 *              -DVDHMPA for the MPA video device handler (VDHMPA.DLL)
 *              -DVDHCGA for the CGA video device handler (VDHCGA.DLL)
 *              -DVDHEGA for the EGA video device handler (VDHEGA.DLL)
 *              -DVDHVGA for the VGA and PS/2 adapter VDH (VDHVGA.DLL)
 *              -DVDH8514A for the BGA video device handler (VDH8514A.DLL)
 *
 * FUNCTIONS    DevEnable
 *              InitEnv, SaveEnv, RestoreEnv
 *              RetConfigInfo
 *              GetPhysBuf, FreePhysBuf
 *
 * NOTES        NONE
 *
 * STRUCTURES   NONE
 *
 * EXTERNAL REFERENCES
 *              DosOpen,  DosGetHugeShift
 *              DosAllocSeg, DosFreeSeg
 *              SaveRegs, RestoreRegs
 *              ExamineConfig, SetHWMode
 *              SaveRestorePVB, SaveRestoreHW
 *              PhysToUVirt, FreePhysToUVirt
 *
 * 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>

#if DEBUG
#define DEBUG_DATA              /* Put debug data in this module   */
#endif  /* DEBUG */

#include "vdhctl.h"             /* Conditional compilation control */
#include "vdh.h"                /* Type definitions                */
#include "vdhdata.h"            /* Global data                     */

#if VDHVGA                                                         /*@MS00 */

/*
**  Externally defined global variables
*/

extern CLUTDATA far ColorCLUT;
extern CLUTDATA far MonoCLUT;

extern USHORT SVGAPresent;                                           /*@drw */
extern USHORT PASCAL NEAR GetSVGAConfig(VOID);                       /*@drw */

#endif  /* VDHVGA                                                     @MS00 */

extern USHORT OEMFlags;         /* OEM specific features              @MS27 */

/*****************************************************************************
 *
 *  SUBROUTINE NAME: DevEnable
 *
 *  DESCRIPTIVE NAME: Initialize call vector table
 *
 *  FUNCTION: DevEnable is called via the Presentation Manager DDI
 *            interface.  The entry points of all VDH routines are
 *            appropriately entered into the call vector table.
 *            In addition, display adapter configuration is verified.
 *
 *  ENTRY POINT: DevEnable
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR * Parameter2  ( far pointer to parameter 2 packet )
 *                      FAR *Flags
 *                      FAR *CallVectorTable
 *             FAR * Parameter1  ( far pointer to parameter 1 packet )
 *                      ULONG EngineVersion ( Graphics engine ver. )
 *                      ULONG TableSize ( Length of call table )
 *             ULONG Subfunction ( Enable subfunction )
 *             FAR *CallVectorTable[] ( BVS's table of entry points )
 *         (Referenced)
 *             VDHEntryPoint[] (global data - table of entry points )
 *             HugeShift (global data - huge shift value)
 *             hScreenDD (global data - screen device driver handle)
 *
 *  EXIT-NORMAL: AX = 0
 *               Entries in VDHEntryPoint table are copied to
 *                  CallVectorTable
 *
 *  EXIT-ERROR: AX = ERROR_VIO_BAD_ADAPTER or
 *                   DosGetHugeShift error or
 *                   DosOpen error or
 *                   PMERR_DEV_FUNC_NOT_INSTALLED
 *
 *  EFFECTS: Huge shift value is saved in HugeShift
 *           Screen device driver handle is saved in hScreenDD
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: DosGetHugeShift, DosOpen, ExamineConfig
 *              SaveRegs, RestoreRegs
 *    DATA:     hScreenDD       (Global nonshared): handle to SCREEN$
 *              HugeShift       (Global shared): from DosGetHugeShift
 *              VDHEntryPoint[] (Global shared): table of entry points
 *
 ****************************************************************************/

USHORT EXPENTRY DevEnable( Parm2, Parm1, Subfunction )

DEV_PARM2 far *Parm2;
DEV_PARM1 far *Parm1;
ULONG Subfunction;

{
USHORT rc,
       j,
       One = 1,
       ActionTaken;
ULONG i;

#if DEBUG                                                          /* @MS07 */
         DEBUG_OUT = 1;                                            /* @MS07 */
        _DPRINTF((char far *)DEBUG_BVH_VERSION);                   /* @MS07 */
        _DPRINTF((char far *)"DEVENABLE\x0A\x0D");                 /* @MS07 */
#endif  /* DEBUG                                                      @MS07 */

rc = NO_ERROR;                          /* Initialize to successful */

if ((Subfunction != FnFillInitDevBlock) &&     /* @T15 */
    (Subfunction != FnFillLogicalDevBlock) )
{

      rc = PMERR_DEV_FUNC_NOT_INSTALLED;

}

else
{

/*
**  Get handle to SCREEN$ for later use of IOCtls cat 3, funcs 70 & 71
*/

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

        if (!(*hScreenDD))
        {            /* SCREEN$ not yet open, @S15*/ /*@T52*/

            rc = DosOpen( SCREENDD_NAME, (PHFILE)hScreenDD,             /*@T52*/
                (PUSHORT)&ActionTaken, NO_SIZE, NO_ATTRIBUTES, OPEN_IF_EXISTS,
                NO_INHERIT+DENY_NONE+READ_WRITE, RESERVED_LONG ); /*@T5,@T15,@S15*/

        }                               /*@S15*/
#endif  /* ! VDH8514A                   @S15,@MS00 */

    if (!rc && FIRST_INIT)
    {            /*@T21,@S15*/

        FIRST_INIT = FALSE;             /*@T15*/

/*
**  Get huge shift value for later use during save/rest of display buffer
*/

        if ( !(rc = DosGetHugeShift( (PUSHORT)&HugeShift )) )
        {

            HugeShift = One << HugeShift;

/*
**  Verify presence of adapter and record adapter configuration for
**  later use by RetConfigInfo and RetROMFontInfo
*/

#if VDH8514A                                                     /*@MS00 */

/*
**  We need the call vector to RetConfigInfo in the VGA VDH (if it's there)
**  ( This vector must be accessible prior to the call to ExamineConfig() )
*/

                (USHORT far *)ChainedCallVectorTable[FnChainedRetConfigInfo] =
                                 Parm2->CallVectorTable[FnReturnConfigInfo];

#endif  /* VDH8514A                                               @MS00 */

#if VDHVGA

            SVGAPresent = GetSVGAConfig();

#endif

            if ( !( rc = ExamineConfig() ) )
            {

/*
**  Copy all VDH entry points that are supported for this adapter
**  to BVS's call table for this adapter
*/

                for ( i = FnTextBufferUpdate, j = FnChainedBufUpdate;
                    (i <= LASTFUNCTION) && (i < Parm1->TableSize); i++, j++ )
                    { /* @D811 */

                    if ( VDHEntryPoint[j] != UNSUPPORTED_FUNCTION )
                    {

#if VDH8514A                                                  /*@MS00 */

/*
**  Save a copy of the call vector table for chaining
*/

                            (USHORT far *)ChainedCallVectorTable[j] =
                                Parm2->CallVectorTable[i];

#endif  /* VDH8514A                                                 @MS00 */

/*
**  Change the current entry in the call vector table
*/

#if DEBUG                                                           /*@MS07 */
                        Parm2->CallVectorTable[i] = (USHORT far *)DebugTrace;

#else                                                               /*@MS07 */
                        Parm2->CallVectorTable[i] = VDHEntryPoint[j];

#endif  /* DEBUG                                                    /*@MS07 */ */
                    }
                }

#if FONT_SUPPORT                                                    /*@MS00 */

                    GetCodePage();      /*@C10*/

#endif  /* FONT_SUPPORT                                              @MS00 */

            }
        }
    }

#if FONT_SUPPORT                        /* @C10,@MS00 */


        else                       /* get access to CodePage segments @C10 */
        {                          /* @C10 */

            if ( CodePage_Support )     /* @C10 */

                if ( !( rc = DosGetSeg ( (SEL) CodePage.p.Selector ) ) ) /* @C10 */
                    rc = DosGetSeg ( (SEL) RomCP_tbl.p.Selector ); /* @C10 */
        }                               /* @C10 */

#endif  /* FONT_SUPPORT                  @C10,@MS00  */

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

        if ( rc )
        {
            DosClose(*hScreenDD);       /* @T5 */ /*@T52*/
            *hScreenDD = 0;             /*@T55*/
        }

#endif  /* ! VDH8514A                   @S15,@MS00 */

}

return( rc );
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: InitEnv
 *
 *  DESCRIPTIVE NAME: Initialize environment
 *
 *  FUNCTION: InitEnv is called by BVS to initialize the video
 *            environment during the creation of a new session.  This
 *            includes initializing the adapter hardware and/or the
 *            environment buffer.
 *
 *  ENTRY POINT: InitEnv
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 257 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 0 - Environment buffer only
 *                                     1 - Hardware also
 *             ULONG Function ( Call vector table entry = 257 )
 *         (Referenced)
 *             Modes[] (global data - table of supported video modes )
 *
 *  EXIT-NORMAL: AX = 0
 *               Environment buffer is initialized
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: If requested, display adapter hardware is initialized to
 *           highest resolution mode supported.
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: SetHWMode, SetEnvMode
 *
 ****************************************************************************/

USHORT EXPENTRY InitEnv( Environment, ParmBlock, Function )

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

{

USHORT rc, i, j;

#if VDHVGA                       /*@D1452*/

HFILE dev_handle;                /*@D1452*/
SHORT ActionTaken;               /*@D1452*/
SHORT XGA_RC;                    /*@D1452*/

#endif                           /*@D1452*/

#if FONT_SUPPORT                                                 /* @C10,@MS00 */

  ROMCP_TABLE *rcp_tbl_ptr;                                           /* @C10 */

#endif  /* FONT_SUPPORT                                           @C10,@MS00 */

rc = ERROR_VIO_INVALID_PARMS;                          /* Initialize to error */

if ( ( Function == FnInitializeEnvironment )        && /* Valid function request */
     ( ParmBlock->Length >= sizeof( VDH_INITENV ) ) && /* Valid packet length */
     ( ParmBlock->Flags  <= VALID_INITENV_FLAG )    && /* Valid flags         */
     SEG( Environment ) )

{                            /* Environment passed  */

  rc = NO_ERROR;                                /* Initialize no error */

  Environment->EnvFlags = DEFAULT_ENVFLAGS;     /*@D198*/

  /*  ** Removing the DosError calls. If an application is registering
  ** their own handler, we would have enabled the exception handling on the
  ** first pop-up in that session, which is forcing the default action. We would
  ** need to query the state of DosError enable/disable in order to restore it.
  ** Until such an API becomes available, keep the state in tact. Nobody on
  ** the team can remember what was the reason for putting the DosError in.
  ** According to Dave Medina, while an exception for one process is being handled,
  ** all other exceptions are delayed.
  */

#if VDH8514A                                                            /*@MS00 */

/*
**  If VDHVGA.DLL has been successfully installed, call InitEnv in VDHVGA.DLL
**  Otherwise, initialize to an 8514/A graphics mode and hope for the best
*/

  Environment->NATIVE_MODE = TRUE;

  if ( VGA_PRESENT )
  {

    Environment->NATIVE_MODE = FALSE;
    if ( ParmBlock->Flags & UPDATE_HARDWARE )
       LeaveNativeMode();

    rc = ChainedVDHInitEnv( (ENVIRONMENT far *)&Environment->VGAEnvironment,
                             ParmBlock, Function );

  }

  else
  {                              /*@S10*/

#endif  /* VDH8514A                     @S10,@MS00*/

/*
**  Initialize 1st word in environment buf to point to VioSetMode structure
**  ( This offset is relative to the begining of the environment buffer )
*/

  Environment->ModeDataOFF = OFFSET( Environment->ModeData ) -
                             OFFSET( Environment->ModeDataOFF );

#if FONT_SUPPORT                                                    /*@MS00 */

/*
**  Initialize active fonts to ROM fonts only
*/

  Environment->ActiveFontPTR = (UCHAR far *)ROM_FONT;

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


  Environment->CodePageID = ROM_FONT;                                 /* @C10 */

  if (CodePage_Support)                                               /* @C10 */
  {                                                                   /* @C10 */
    DosGetCp( 0x2, (PUSHORT)&j, (PUSHORT)&i );                        /* @C10 */
    rcp_tbl_ptr = RomCP_tbl.ptr;                                      /* @C10 */

    for ( i=0; i<ROMCP_NUM; i++ )                                     /* @C10 */

       if ( j == rcp_tbl_ptr->CodePageID )
       {                          /* @C10 */
          Environment->CodePageID = j;                                /* @C10 */
          i = ROMCP_NUM;                                              /* @C10 */
       }                                                              /* @C10 */

       else                                                           /* @C10 */
          rcp_tbl_ptr++;                                              /* @C10 */
  }                                                                   /* @C10 */

/*
**  Initialize the USER font to NOT SELECTABLE ( Code page or ROM font only )
*/

  Environment->UserFont     = USER_FONT_NOT_SELECTABLE;
  Environment->NumUSERFonts = 0;           /* Number of USER fonts in storage */

#endif         /* FONT_SUPPORT                                          @MS00 */


/*
**  Initialize video mode to highest resolution 80x25 color text supported
*/

  SetEnvMode( VideoHardware.popupMode, /* Initialize mode data structure  @T39*/
              Environment, (ENVIRONMENT far *)NULL, 1 );                /*@T70*/

/*
**  Shadow cursor attribute outside of register shadow - register contains
**  one bit indicating hidden or visible.  Use this to retrieve exact non -1
**  cursor attribute ( cursor attribute: -1 = hidden, other = non-hidden )
*/

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

  Environment->CursorAttribute = 0;                             /* Not hidden */

/*
**  For VGA, the Screen Off bit (b5) of the Miscellaneous Output Register
**  is used to enable/disable the video signal.  For all other adapters, the
**  Attribute registers are used and a query references this shadow
*/

/*
**   @C21  Use Attribute regs for all including VGA
*/
  Environment->VideoEnable = 0;         /* Disabled, @S43*/

#endif  /* ! VDH8514A                   @S10,@MS00 */

#if VDHVGA
  /*
  **            Initialize SVDH related fields.
  */
  Environment->SVGAMode = 0;
  Environment->PelRows = 0;
  Environment->PelColumns = 0;
#endif
#if FONT_SUPPORT                                                  /*@C15,@MS00*/

  /*
  ** call FindFont to setup Env for the appropriate font
  */
  FindFont ( Environment->ModeIndex, Environment->ModeData.row,        /*@C15*/
             Environment );                                            /*@C15*/

#endif  /* FONT_SUPPORT */

/*
**  Initialize mode to highest resolution 80x25 color text
**  ( This includes the setting of the appropriate ROM font )
**  If foreground, SetHWMode will set the hardware. By passing the
**  environment, SetHWMode will shadow also shadow the registers.
*/

  if ( !(rc = SetHWMode( VideoHardware.popupMode,
         ParmBlock->Flags, Environment ) ) )
  {    /*@T39,@T53*/

/*
**  Initialize the scrollable text region of the screen.                @P1
**  Note that in all cases the entire screen is the scrollable region.  @P1
*/

     Environment->ScrollRect.Left = 0;                               /* @P1 */
     Environment->ScrollRect.Top = 0;                                /* @P1 */
     Environment->ScrollRect.Right = Environment->ModeData.col - 1;  /* @P1 */
     Environment->ScrollRect.Bottom = Environment->ModeData.row - 1; /* @P1 */
     Environment->AttrBufSize = 1;                                   /* @P1 */
     Environment->AttrBuf[0] = DefaultAttribute[0];                  /* @P1 */
     Environment->AttrBuf[1] = DefaultAttribute[1];                  /* @P1 */
     Environment->AttrBuf[2] = DefaultAttribute[2];                  /* @P1 */

  }                                                                 /* @T53 */

#if VDH8514A                            /*@S10,@MS00*/

  } /* VGA not present */               /*@S10*/

#endif

#if VDHVGA                                                            /*@D1085*/
                                                                      /*@D1085*/
  Environment->Comp_Reg = 0;                                          /*@D1085*/
                                                                      /*@D1085*/
#endif                                                                /*@D1085*/

  }

#if VDHVGA                                                          /*@D1452*/
                                                                    /*@D1452*/
/*
** Device driver detection: if DosOpen fails, it's not there
** and we need to wait until later
*/


   Environment->XGA_PRESENT = FALSE;                              /*@B720995*/

   if (!(DosOpen( "\\DEV\\$$AFVIO0",                                /*@D1452*/
         (PHFILE)&dev_handle,                                       /*@D1452*/
         (PUSHORT)&ActionTaken,                                     /*@D1452*/
         NO_SIZE,                                                   /*@D1452*/
         FILE_SYSTEM,                                               /*@D1452*/
         OPEN_ACTION_OPEN_IF_EXISTS,                                /*@D1452*/
              NO_INHERIT+                                          /*@D1452f*/
              OPEN_SHARE_DENYNONE+                                  /*@D1452*/
              OPEN_ACCESS_READWRITE,                                /*@D1452*/
         RESERVED_LONG )) )                                         /*@D1452*/

   {                                                                /*@D1452*/
      Environment->XGA_PRESENT = TRUE;                              /*@D1452*/
      VideoHardware.Reg_132 = TRUE;          /*@B729652 */
      DosClose(dev_handle);                                        /*@D1452f*/
   }                                                                /*@D1452*/
                                                                    /*@D1452*/
#endif                                                              /*@D1452*/

  /*  ** Removing the DosError calls. See comments above.                        
  */

return( rc );

}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: SaveEnv
 *
 *  DESCRIPTIVE NAME: Save environment
 *
 *  FUNCTION: SaveEnv is called by BVS prior to a screen switch
 *            in order to preserve the display adapter hardware state
 *            and/or the full or partial display buffer.
 *
 *  ENTRY POINT: SaveEnv
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 258 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 2 - Hardware state
 *                                     4 - Full display buffer
 *                                     8 - Partial display buffer
 *                     USHORT PVBHugeSEL = 1st huge selector for PVB
 *             ULONG Function ( Call vector table entry = 258 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Hardware state and/or display buffer is saved in
 *                 environment buffer
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: None                                               @T51
 *                                                              @T51
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: SaveRestorePVB, SaveRestoreHW                   @T51
 *
 ****************************************************************************/

USHORT EXPENTRY SaveEnv( Environment, ParmBlock, Function )

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

{

USHORT rc, EnvBufferPassed;
REGDATA RegData;
REGADDRESS RegAddress;
ULONG BufSize;

UCHAR TempAddrRegs[6];                                                  /*@C39*/
USHORT ColorMode;                                                       /*@C39*/

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

if ( ( Function == FnSaveEnvironment )                && /*Valid funct request*/
     ( ParmBlock->Length >= MinSLen_SaveRestoreEnv )  && /*Valid packet length*/
       ParmBlock->Flags                               && /*An option specified*/
    !( ParmBlock->Flags & ~VALID_SAVEREST_FLAG )      && /*No illegal options */
    !( ( ParmBlock->Flags & SAVEREST_FULLPVB )        &&
       ( ParmBlock->Flags & SAVEREST_PARTPVB ) )      && /*Not part and full  */
    !( ( ParmBlock->Length < sizeof( VDH_SAVEREST ) ) && /*PVB and no selector*/
       ( ParmBlock->Flags & (SAVEREST_FULLPVB+SAVEREST_PARTPVB) ) ) &&
     EnvBufferPassed )

{

  rc = NO_ERROR;                                       /* Initialize no error */

#if VDH8514A                                                     /*@MS00 */

/*
**  If the current mode is not an 8514/A native mode, call SaveEnv in
**  VDHVGA.DLL.  Otherwise, do nothing.
*/

  if ( VGA_PRESENT && !Environment->NATIVE_MODE )
    rc = ChainedVDHSaveEnv( (ENVIRONMENT far *)&Environment->VGAEnvironment,
                            ParmBlock, Function              );

#else

  if ( ParmBlock->Flags & SAVEREST_HARDWARE )
  {

/*
**  If hardware is not write-only, read it and copy to the env buffer
*/

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

    if ( ParmBlock->Flags & SAVEREST_VDM )
    {                            /*@C39*/
       Environment->EnvFlags |= SAVEREST_VDM;    /*              VDM  Popup   */
       ColorMode = HardwareColor();                                     /*@C39*/

       if ( ColorMode )                                                 /*@C39*/
         RegAddress.DataPort    = CRTColorAddrPort;                     /*@C39*/

       else                                                             /*@C39*/
         RegAddress.DataPort    = CRTAddressPort;                       /*@C39*/

       AccessRegister( &RegAddress, GET, &TempAddrRegs[0] );            /*@C39*/
       RegAddress.DataPort    = AttAddressPort;                         /*@C39*/
       AccessRegister( &RegAddress, GET, &TempAddrRegs[1] );            /*@C39*/
       RegAddress.DataPort    = SeqAddressPort;                         /*@C39*/
       AccessRegister( &RegAddress, GET, &TempAddrRegs[2] );            /*@C39*/
       RegAddress.DataPort    = GraphAddressPort;                       /*@C39*/
       AccessRegister( &RegAddress, GET, &TempAddrRegs[3] );            /*@C39*/
       RegAddress.DataPort    = DACAddrPortWrite;                       /*@C39*/
       AccessRegister( &RegAddress, GET, &TempAddrRegs[4] );            /*@C39*/
       RegAddress.DataPort    = DACAddrPortRead;                        /*@C39*/
       AccessRegister( &RegAddress, GET, &TempAddrRegs[5] );            /*@C39*/

    }                                                                   /*@C39*/

/*
**  Read registers into environment buffer
*/

    SaveRestoreHW( Environment, GET );

#else

/*
**  Cursor position is always readable
*/

   if ( !( ParmBlock->Flags & SAVEREST_VDM ) )
   {                        /*@C39*/

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

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

     RegData.NumEntries = 2;                         /* Just cursor position */

     AccessHardware( &RegAddress, BYTES,
                     (USHORT)(Environment->ModeData.fbType & NOT_MONO),
                     GET, &RegData );
   }                                                                    /*@C39*/

#endif

  }

/*
**  Save partial or full display buffer
*/

  if ( ParmBlock->Flags & (SAVEREST_FULLPVB+SAVEREST_PARTPVB) )
  {

     if (!rc || rc==ERROR_ACCESS_DENIED)
     {      /*STJ*/
        rc = SaveRestorePVB( ParmBlock, SAVE, (UCHAR far *)NULL, Environment );
     }
  }

  if ( ParmBlock->Flags & SAVEREST_VDM )
  {                             /*@C39*/

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

     if ( ColorMode )                                                  /*@C39*/
       RegAddress.DataPort    = CRTColorAddrPort;                      /*@C39*/

     else                                                              /*@C39*/
       RegAddress.DataPort    = CRTAddressPort;                        /*@C39*/

     AccessRegister( &RegAddress, SET, &TempAddrRegs[0] );             /*@C39*/
     RegAddress.DataPort    = AttAddressPort;                          /*@C39*/
     AccessRegister( &RegAddress, SET, &TempAddrRegs[1] );             /*@C39*/
     RegAddress.DataPort    = SeqAddressPort;                          /*@C39*/
     AccessRegister( &RegAddress, SET, &TempAddrRegs[2] );             /*@C39*/
     RegAddress.DataPort    = GraphAddressPort;                        /*@C39*/
     AccessRegister( &RegAddress, SET, &TempAddrRegs[3] );             /*@C39*/
     RegAddress.DataPort    = DACAddrPortWrite;                        /*@C39*/
     AccessRegister( &RegAddress, SET, &TempAddrRegs[4] );             /*@C39*/
     RegAddress.DataPort    = DACAddrPortRead;                         /*@C39*/
     AccessRegister( &RegAddress, SET, &TempAddrRegs[5] );             /*@C39*/

#else                                                                  /*@C39*/

     if ( !rc )                                                        /*@C39*/
        rc = NOT_READABLE_HARDWARE;                                    /*@C39*/

#endif

  }                                                                    /*@C39*/


#endif

  }
return( rc );
}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: RestoreEnv
 *
 *  DESCRIPTIVE NAME: Restore environment
 *
 *  FUNCTION: RestoreEnv is called by BVS following a screen switch
 *            in order to restore the display adapter hardware state
 *            and/or the full or partial display buffer.
 *
 *  ENTRY POINT: RestoreEnv
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 259 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 2 - Hardware state
 *                                     4 - Full display buffer
 *                                     8 - Partial display buffer
 *                     USHORT PVBHugeSEL = 1st huge selector for PVB
 *             ULONG Function ( Call vector table entry = 259 )
 *
 *  EXIT-NORMAL: AX = 0
 *               Hardware state and/or display buffer is restored
 *                 using info from environment buffer.
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: None                                               @T51
 *                                                              @T51
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: SaveRestorePVB, SaveRestoreHW
 *
 ****************************************************************************/

USHORT EXPENTRY RestoreEnv( Environment, ParmBlock, Function )

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

{

USHORT rc,
       VideoState,                                                      /*@C21*/
       VideoOn,                                                         /*@C21*/
       ColorMode,                                                       /*@C21*/
       EnvBufferPassed;

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

if ( ( Function == FnRestoreEnvironment )            && /* Valid funct request*/
     ( ParmBlock->Length >= MinSLen_SaveRestoreEnv ) && /* Valid packet length*/
       ParmBlock->Flags                              && /* An option specified*/
    !( ParmBlock->Flags & ~VALID_SAVEREST_FLAG )     && /* No illegal options */
    !( ( ParmBlock->Flags & SAVEREST_FULLPVB )       &&
       ( ParmBlock->Flags & SAVEREST_PARTPVB ) )     && /* Not part and full  */
    !( ( ParmBlock->Length < sizeof( VDH_SAVEREST )) && /* PVB and no selector*/
       ( ParmBlock->Flags & (SAVEREST_FULLPVB+SAVEREST_PARTPVB) ) ) &&
       EnvBufferPassed )
{

  rc = NO_ERROR;                                       /* Initialize no error */

#if VDH8514A                                                  /*@MS00 */

/*
**  If the mode being restored is not an 8514/A native mode, call RestoreEnv
**  in VDHVGA.DLL.  Otherwise, restore the native mode.
*/

  if ( VGA_PRESENT && !Environment->NATIVE_MODE )
  {
    LeaveNativeMode();
    rc = ChainedVDHRestoreEnv( (ENVIRONMENT far *)&Environment->VGAEnvironment,
                               ParmBlock, Function );
  }

#else

/*
**  Turn off the Video Signal                                             @C2
*/

  VideoState = Environment->VideoEnable;                                /*@C21*/
  Environment->VideoEnable = 0;                                         /*@C21*/

#if VDHVGA                                                         /*@C21,@MS00*/
     ColorMode = HardwareColor();        /* color/mono mode               @C21*/
#else                                                              /*@C21,@MS00*/
     ColorMode = Environment->ModeData.fbType & NOT_MONO;               /*@C21*/
#endif

  VideoOn = 0;                                                          /*@C21*/
  AccessVideoEnable( ColorMode, SET, &VideoOn );                        /*@C21*/

  if ( ParmBlock->Flags & SAVEREST_HARDWARE )

/*
**  Output environment buffer to registers
*/
    SaveRestoreHW( Environment, SET );

  if ( ParmBlock->Flags & ( SAVEREST_FULLPVB | SAVEREST_PARTPVB ) )

/*
**  Restore partial or full display buffer
*/

    rc = SaveRestorePVB( ParmBlock, RESTORE,

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

                         (UCHAR far *)&Environment->Hardware.Sequencers.Regs.MapMask,

#else

                         (UCHAR far *)NULL,

#endif

                         Environment );

/*
**  Turn the Video Signal ON if it was on previously                      @C2
*/

/*
**  If current cols = 132 then ensure proper register setup for 132 cols
**  on a restore.
*/

#if VDHVGA                                                        /*@D1085,@MS00*/
                                                                       /*@D1085*/
  if(Environment->ModeData.col == 132)
  {                               /*@D1085*/

    if ((SVGAPresent == IBM_ADAPTER) || !SVGAPresent)           /*            */
     if(Environment->XGA_PRESENT == FALSE)                      /*@D1452*/
       SET132(Environment->Comp_Reg,1);                         /*@D1085*/
  }

  else
  {                                                             /*@D1085*/

     if (Environment->Comp_Reg != 0)
     {                                 /*@D1085*/

        if ((SVGAPresent == IBM_ADAPTER) || !SVGAPresent)       /*            */
          if (Environment->XGA_PRESENT == FALSE)
            SET132(Environment->Comp_Reg,0);                    /*@D1085*/
     } /* endif */                                              /*@D1085*/
  } /* endif */                                                 /*@D1085*/
                                                                /*@D1085*/
#endif

  if ( VideoState )
  {                                                   /*@C21*/

     AccessVideoEnable( ColorMode, SET, &VideoState );                  /*@C21*/
     Environment->VideoEnable = 1;                                      /*@C21*/
  }                                                                     /*@C21*/

#endif

  }
return( rc );

}

/*****************************************************************************
 *
 *  SUBROUTINE NAME: RetConfigInfo
 *
 *  DESCRIPTIVE NAME: Return video adapter configuration information
 *
 *  FUNCTION: RetConfigInfo is called by BVS to identify the current
 *            display adapter.
 *
 *  ENTRY POINT: RetConfigInfo
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 260 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags  = 0 ( reserved )
 *                     FAR *ConfigData = VioGetConfig structure
 *             ULONG Function ( Call vector table entry = 260 )
 *         (Referenced)
 *
 *
 *  EXIT-NORMAL: AX = 0
 *               Configuration data is returned to caller
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: If the length of ConfigData does not exactly fit a
 *           parameter, the length is adjusted and returned.
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 ****************************************************************************/

USHORT EXPENTRY RetConfigInfo( Environment, ParmBlock, Function )

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

{

USHORT rc,workvar;

VDHCONFIGINFO far *pReqConfig;          /* Reduce level of indirection, @S8 */
unsigned register ReqConfigLen;         /* Eliminate segment loading, @S8 */

rc = ERROR_VIO_INVALID_PARMS;                         /* Initialize to error    */

if ( ( Function == FnReturnConfigInfo )            && /* Valid function request */
     ( ParmBlock->Length >= sizeof( VDH_CONFIG ) ) && /* Valid packet length    */
     ( !ParmBlock->Flags ) )
{                        /* Valid flags            */

  rc = NO_ERROR;                                       /* Initialize no error */

  ReqConfigLen = (pReqConfig = ParmBlock->ConfigDataPTR)->cb; /*@S8*/

  if ( ReqConfigLen > sizeof(VDHCONFIGINFO) )
  { /*@S25*/

     ReqConfigLen = MinDLen_Config_Memory;      /*@S25*/
  }                                             /*@S25*/

  if ( ( ReqConfigLen < MinDLen_Config_Adapter ) &&  /* @@A */
       ( ReqConfigLen != Config_Return_Length ) )    /* @@A */
     rc = ERROR_VIO_INVALID_LENGTH;                                  /* @@A */

/*
**  Structure length of 2 means set structure length and return
*/

  else if ( ReqConfigLen == Config_Return_Length )
    ReqConfigLen = sizeof( VDHCONFIGINFO );

  else
  {

/*
**  Adapter types:
**                 0 - MPA                   4 - IBM Japan G
**                 1 - CGA                   5 - IBM Japan H
**                 2 - EGA                   6 - IBM Japan ST
**                 3 - VGA or PS/2 adapter   7 - 8514/A
*/


#if VDHCGA                                                            /*@MS00 */

    pReqConfig->adapter  = TYPE_CGA;

#elif VDHEGA                                                          /*@MS00 */

    pReqConfig->adapter  = TYPE_EGA;

#elif VDHVGA                                                          /*@MS00 */

    pReqConfig->adapter  = TYPE_VGA;

#elif VDH8514A                                                        /*@MS00 */

    pReqConfig->adapter  = TYPE_8514A;

#elif VDHMPA                                                          /*@MS00 */

    pReqConfig->adapter  = TYPE_MPA;

#endif  /* VDHCGA                                                       @MS00 */

    if ( ReqConfigLen < MinDLen_Config_Display )
      ReqConfigLen = MinDLen_Config_Adapter;

    else
    {
/*
**  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
*/

      pReqConfig->display = VideoHardware.display;                      /*@T39*/

      if ( ReqConfigLen < MinDLen_Config_Memory )
        ReqConfigLen = MinDLen_Config_Display;

      else
      {
/*
**  Video memory size:
**    VGA or PS/2 adapter:  256k
**    EGA:                  64k, 128k, 192k, 256k
**    CGA:                  64k
**    MPA:                  4k
**    8514/A:               512k, 1MB
*/

        pReqConfig->cbMemory = VideoHardware.memory;                    /*@T39*/

        if ( ReqConfigLen < MinDLen_Config_ConfigNum )
          ReqConfigLen = MinDLen_Config_Memory;

        else
        {

/*
**  Configuration number: always return unknown
*/

          pReqConfig->Configuration = UNKNOWN;

          if ( ReqConfigLen < MinDLen_Config_Version )
            ReqConfigLen = MinDLen_Config_ConfigNum;

          else
          {

/*
**  Video device driver version number
*/

            pReqConfig->DeviceDriver = DeviceDriver;

            if ( ReqConfigLen < MinDLen_Config_Flag )
              ReqConfigLen = MinDLen_Config_Version;

            else
            {

/*
**  Configuration flag: xxxxxxxb  1 = Power-up display
*/

              pReqConfig->Flags = ConfigFlag;

              if ( ReqConfigLen < MinDLen_Config_HWBufLen )
                ReqConfigLen = MinDLen_Config_Flag;

              else
              {

/*
**  Size of hardware state buffer
*/

                pReqConfig->HWBufferSize = sizeof( ENVIRONMENT );

#if VDH8514A                                                         /* @MS00 */


/*
**  If the VDHVGA is there, allocate enough room to tack its environment
**  buffer onto the end of the VDH8514A environment buffer.
*/

                if ( VGA_PRESENT )
                  pReqConfig->HWBufferSize +=
                                                VGAConfigData.HWBufferSize;

#endif

                if ( ReqConfigLen < MinDLen_Config_FullSaveSz )
                  ReqConfigLen = MinDLen_Config_HWBufLen;

                else
                {

/*
**  Size of entire physical display buffer for the current mode (page 0 only)
*/

#if VDHVGA                                                            /*@MS00 */

        if (OEMFlags & STARDUST_VGA)
                  pReqConfig->FullSaveSize = 640L*480L;   /* VGC mode 2E */

        else
                  pReqConfig->FullSaveSize =  38400L * 4L;   /* VGA mode 12 */

#elif VDHEGA                                                         /*@MS00 */

                  pReqConfig->FullSaveSize =  28400L * 4L;   /* EGA mode 10 */

#elif VDHCGA                                                          /*@MS00 */

                  pReqConfig->FullSaveSize =   8000L * 2L; /* CGA modes 4,5,6 */

#elif VDHMPA                                                          /*@MS00 */

                  pReqConfig->FullSaveSize =   (ULONG)(80 * 25 * 2); /* MPA 7 */

#elif VDH8514A                                                        /*@MS00 */

                  pReqConfig->FullSaveSize =
                           VGA_PRESENT ? VGAConfigData.FullSaveSize : UNKNOWN;

#endif  /* VDHVGA                                                       @MS00 */

                  if ( ReqConfigLen < MinDLen_Config_PartSaveSz )
                    ReqConfigLen = MinDLen_Config_FullSaveSz;

                  else
                  {

/*
**  Size of entire physical display buffer for the popup mode (page 0 only)
*/

                    pReqConfig->PartSaveSize = PartialSaveSize;

                    if ( ReqConfigLen < MinDLen_Config_EMAdapter )
                      ReqConfigLen = MinDLen_Config_PartSaveSz;

                    else
                    {

/*
**  Emulated adapter type and offset its offset in ConfigData structure
*/

                      pReqConfig->EMAdaptersOFF =
                              OFFSET( pReqConfig->LEMAdapterdata ) -    /*@C33*/
                              OFFSET( pReqConfig->cb );

                                       /* length of Emulated adapter data @C33*/
                      pReqConfig->LEMAdapterdata = 1;                   /*@C33*/

/*
**  Emulated adapter types:
**              b0 - MPA adapter         b3 - VGA or PS/2 adapter
**              b1 - CGA adapter         b7 - 8514/A adapter
**              b2 - EGA adapter
*/

#if VDHMPA                                                            /*@MS00 */

                      pReqConfig->EMAdapters = EMULATE_TYPE_MPA;

#elif VDHCGA                                                          /*@MS00 */

                      pReqConfig->EMAdapters = EMULATE_TYPE_CGA;

#elif VDHEGA                                                          /*@MS00 */

                      pReqConfig->EMAdapters =
                             ( VideoHardware.display == Mono5151 ) ?    /*@T39*/
                                 EMULATE_TYPE_MPA + EMULATE_TYPE_EGA : /*@D184*/
                                 EMULATE_TYPE_CGA + EMULATE_TYPE_EGA;  /*@D184*/

#elif VDHVGA
                                                                       /*@MS00 */
                      pReqConfig->EMAdapters =
                                 EMULATE_TYPE_MPA + EMULATE_TYPE_CGA +
                                 EMULATE_TYPE_EGA + EMULATE_TYPE_VGA;

#elif VDH8514A                                                          /*@MS00 */

                      pReqConfig->EMAdapters = EMULATE_TYPE_8514A
                             + ( !VGA_PRESENT ? 0 :
                                 EMULATE_TYPE_MPA + EMULATE_TYPE_CGA +
                                 EMULATE_TYPE_EGA + EMULATE_TYPE_VGA );

#endif  /* VDHMPA                                                    @MS00 */

                      if ( ReqConfigLen < MinDLen_Config_EMDisplay )
                        ReqConfigLen = MinDLen_Config_EMAdapter;

                      else
                      {

/*
**  Emulated display type and offset its offset in ConfigData structure
*/

                        pReqConfig->EMDisplaysOFF =
                                     OFFSET( pReqConfig->LEMDisplaydata ) -
                                     OFFSET( pReqConfig->cb );

                                       /* length of Emulated display data @C33*/
                        pReqConfig->LEMDisplaydata = 1;                 /*@C33*/

/*
**  Emulated display types:
**                b0 - 5151 mono            b3 - 8503 mono
**                b1 - 5153 color           b4 - 8512/8513 color
**                b2 - 5154 enhanced        b9 - 8514 color
*/
                        pReqConfig->EMDisplays =
                          pReqConfig->EMAdapters & EMULATE_TYPE_MPA
                          ? EmDisp_MPA : 0; /*@D184*/

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

                        pReqConfig->EMDisplays |=
                          pReqConfig->EMAdapters & EMULATE_TYPE_CGA
                          ? EmDisp_CGA : 0; /*@D184*/

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

                        pReqConfig->EMDisplays |=
                          (VideoHardware.display == EnColor5154)        /*@T39*/
                          ? EmDisp_EGA : 0; /*@D184*/

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

                        pReqConfig->EMDisplays |=
                          pReqConfig->EMAdapters & EMULATE_TYPE_VGA
                          ? EmDisp_VGA + EmDisp_EGA : 0; /*@D184*/

#if VDH8514A                                                          /*@MS00 */

                        pReqConfig->EMDisplays |=
                           (VideoHardware.display==Color8512_8513      /*@T39*/
                                 || VideoHardware.display==Mono8503)
                           ? EmDisp_8514L : EmDisp_8514A; /*@D184*/

#endif  /* VDH8514A                                              @MS00 */
#endif  /* ! VDHEGA                                              @MS00 */
#endif  /* ! VDHCGA                                              @MS00 */
#endif  /* ! VDHMPA                                              @MS00 */

                        ReqConfigLen = MinDLen_Config_EMDisplay;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }

    }
  }

if (!rc)
{                              /*@S8*/
    pReqConfig->cb = ReqConfigLen;      /*@S8*/
}                                       /*@S8*/

return( rc );
}

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

/*****************************************************************************
 *
 *  SUBROUTINE NAME: GetPhysBuf
 *
 *  DESCRIPTIVE NAME: Get LDT selector to physical display buffer
 *
 *  FUNCTION: GetPhysBuf is called by BVS in order to obtain an LDT
 *            selector by which to address the display buffer
 *            corresponding to the current mode or the mode specified.
 *
 *  ENTRY POINT: GetPhysBuf
 *    LINKAGE:   CALL FAR ( via BVS-DDI call vector table entry 275 )
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *                     USHORT Length = length of this packet
 *                     USHORT Flags
 *                     FAR *PhysBufData = VioGetPhysBuf structure
 *             ULONG Function ( Call vector table entry = 275 )
 *         (Referenced)
 *             MemoryMaps[] (Table of memory map info for each mode)
 *
 *  EXIT-NORMAL: AX = 0
 *               An LDT selector to the PVB is returned to caller
 *
 *  EXIT-ERROR: AX = ERROR_VIO_INVALID_PARMS
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: PhysToUVirt
 *
 ****************************************************************************/

USHORT EXPENTRY GetPhysBuf( Environment, ParmBlock, Function )

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

{

USHORT rc,
       i,
       Mode,
       AmountAllocated,
       EnvBufferPassed;
ULONG  PVB_TOP, PVB_BOTTOM,
       PVBLen, NOT_ALLOCATED;
FarAddress PVB, Temp;                                                   /*@T30*/
ENVIRONMENT far *TempEnv;
SEL Selector;
USHORT far *ReturnDataArea;

USHORT return_alt_selectors;                                            /*@B29*/
USHORT use_ALT_VIOPHYSBUF;                                              /*@B29*/

return_alt_selectors = FALSE;                                           /*@B29*/

rc = ERROR_VIO_PTR;                                 /* LDTSelector not passed */

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

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

  if ( ParmBlock->PVBDataPTR->cb == 0L && ParmBlock->PVBDataPTR->pBuf != 0L )
  {
/*
**  Length = 0, use address and length corresponding to the current mode
**  on this adapter:
**    VGA: mono text      - Address: 0xB0000, Length: 4000
**         color text     - Address: 0xB8000, Length: 4000
**         lores graphics - Address: 0xB8000, Length: 8000  ( 1st page )
**         lores graphics - Address: 0xBA000, Length: 8000  ( 2nd page )
**         other graphics - Address: 0xA0000, Length: 64000
**    EGA: mono text      - Address: 0xB0000, Length: 4000
**         color text     - Address: 0xB8000, Length: 4000
**         lores graphics - Address: 0xB8000, Length: 8000  ( 1st page )
**         lores graphics - Address: 0xBA000, Length: 8000  ( 2nd page )
**         other graphics - Address: 0xA0000, Length: 28000
**    CGA: mono text      - Address: 0xB0000, Length: 4000
**         color text     - Address: 0xB8000, Length: 4000
**         lores graphics - Address: 0xB8000, Length: 8000  ( 1st page )
**         lores graphics - Address: 0xBA000, Length: 8000  ( 2nd page )
**    MPA: mono text      - Address: 0xB0000, Length: 4000
*/

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

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

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

       if ( !(rc = DosAllocSeg( sizeof( ENVIRONMENT ), (PSEL)&Selector, 0 )) )
       {

         TempEnv = (ENVIRONMENT far *)MakeFarPTR( Selector, 0 );

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

         TempEnv->VideoEnable = 1;              /* Assume video ON */   /*@T34*/
         SaveRestoreHW( TempEnv, GET );                 /* Read hardware      */

         Mode = GetModeIndex( TempEnv );                /* Get mode index + 1 */

         rc = ( !Mode-- ) ? ERROR_VIO_MODE : NO_ERROR;

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

         DosFreeSeg( Selector );

         }

#endif

       }

       else

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

      if ( EnvBufferPassed )
      {
        Mode = Environment->ModeIndex;
        rc   = NO_ERROR;

        }

    if ( !rc )
    {
      PVB.FullAddress = MemoryMaps[Modes[Mode].MemMap].Start.FullAddress;

      if (Environment->ModeData.fbType & GRAPHICS )
      {                /*@B70*/

         if (!(PVBLen = (ULONG)MemoryMaps[Modes[Mode].MemMap].PageLength))
            PVBLen = 0x10000;
      }

      else                                                           /*@B70*/
         PVBLen = (Environment->ModeData.row                         /*@B70*/
                     * Environment->ModeData.col * 2);               /*@B70*/

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

      if(((ALT_VIOPHYSBUF far *)(ParmBlock->PVBDataPTR->pBuf))->cb != 2)/*@B29*/
         return_alt_selectors = TRUE;                                   /*@B29*/

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

  else
  {

    if ( ParmBlock->PVBDataPTR->cb != 0L )
    {
      PVBLen = ParmBlock->PVBDataPTR->cb;
      PVB_BOTTOM = (ULONG)(PVB.FullAddress = ParmBlock->PVBDataPTR->pBuf);
      PVB_TOP    = PVB_BOTTOM + PVBLen - 1L;

      if ( ( (PVB_BOTTOM >= MIN_PVB_BOTTOM)  && (PVB_TOP <= MAX_PVB_TOP)))
           rc = NO_ERROR; /* This passes the A0000 to BFFFF text, say it's OK */

      else                                   /*@B68*/
          rc = ERROR_VIO_INVALID_PARMS;      /*@B68*/

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

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

      }
    }

  use_ALT_VIOPHYSBUF = FALSE;                                           /*@B29*/

  if (ReturnDataArea == (USHORT far *)&(((ALT_VIOPHYSBUF far *)
                        (ParmBlock->PVBDataPTR->pBuf))->asel[0])){ /*@B29*/
    use_ALT_VIOPHYSBUF = TRUE;                                          /*@B29*/

    }

  if ( !rc )

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

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

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

      if ( !rc )
      {                                                 /*@T30,@T53*/

        if (use_ALT_VIOPHYSBUF == TRUE)
        {                                /*@B29*/
          ((ALT_VIOPHYSBUF far *)(ParmBlock->PVBDataPTR->pBuf))->cb =
                                ((2*(i+1))+2); /*@B28*/
          if (return_alt_selectors == TRUE)                             /*@B29*/
             ReturnDataArea[i] = Temp.part.Selector;                    /*@B29*/
        }                                                               /*@B29*/

        else
          ReturnDataArea[i] = Temp.part.Selector;                       /*@T30*/
      }                                                                 /*@T53*/
    }
  }

return( rc );

}

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

USHORT EXPENTRY FreePhysBuf( Environment, ParmBlock, Function )

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

{

USHORT rc;

if ( ( Function == FnFreePhysBuf )                  && /* Valid function request */
     ( ParmBlock->Length >= sizeof( VDH_FREEPVB ) ) && /* Valid structure length */
      !ParmBlock->Flags )

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

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

return( rc );
}

#else

/*****************************************************************************
 *
 *  SUBROUTINE NAME: ChainRouter
 *
 *  DESCRIPTIVE NAME: Call default entry in call vector table
 *
 *  FUNCTION: During VDH chaining, the environment buffer of the
 *            previous call table entry is tacked on to the end of the
 *            current VDH environment buffer.  If a particular VDH
 *            service is not supported, the VDH has to call the
 *            previous entry with its environment.
 *
 *  ENTRY POINT: UnsupportedService
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *             ULONG Function ( Call vector table entry )
 *
 *  EXIT:      AX = return code from call table vector routine
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 ****************************************************************************/

USHORT EXPENTRY ChainRouter( Environment, ParmBlock, Function )

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

{

USHORT rc;

rc = (*ChainedCallVectorTable[ Function - FnTextBufferUpdate ])
             ((char far *)&Environment->VGAEnvironment, ParmBlock, Function );

return( rc );

}

#endif

#if DEBUG                                               /*@MS07 - BEGIN */

/*****************************************************************************
 *
 *  SUBROUTINE NAME: DEBUG_TRACE
 *
 *  DESCRIPTIVE NAME: Print Debug Trace
 *
 *  FUNCTION: Print debug trace
 *              then call the entry in call vector table
 *
 *  ENTRY POINT: UnsupportedService
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR *Environment ( Environment buffer for the session )
 *             FAR *ParmBlock
 *             ULONG Function ( Call vector table entry )
 *
 *  EXIT:      AX = return code from call table vector routine
 *
 *  EFFECTS: NONE
 *
 *  INTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: NONE
 *
 ****************************************************************************/

USHORT EXPENTRY DEBUG_TRACE( Environment, ParmBlock, Function )

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

{

USHORT rc;

   FNDEBUG(Function);

   (USHORT far *)DebugTrace = VDHEntryPoint[ Function - FnTextBufferUpdate ];

   rc = (DebugTrace)(Environment, ParmBlock, Function );

   return( rc );
}

#endif  /* DEBUG                                               @MS07 - END */

