/*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 = SVGASRVB.C
 *
 * DESCRIPTIVE NAME = Save/Restore Video Buffer
 *
 *
 * VERSION      V2.0
 *
 * DATE         
 *
 * DESCRIPTION  Super VGA specific routines to Save/Restore 
 *              the physical video buffer.
 *
 * FUNCTIONS    SAVERESTOREPVB
 *              
 * NOTES        THESE ROUTINES EXECUTE AS RING 2 CONFORMING
 *
 * STRUCTURES   NONE
 *
 * EXTERNAL REFERENCES  DOSDEVIOCTL, DOSDEVCONFIG         
 *                      ACCESSHARDWARE, ACCESSREGISTER    
 *              NONE
 *
 * EXTERNAL FUNCTIONS
 *
 *              NONE
 *
*/

#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>
#include "svgatype.h"

#define TEXTMODE        0x080          /* Set highest bit in bit-planes for text modes            */ 
/*
**  Externals
*/

extern HFILE hScreenDD;                /* Handle to screen device driver    */
extern USHORT OEMFlags;
extern USHORT HugeShift;               
extern PVIDEOMODE pModes;              /*                                      */
extern PMEMORYMAPS pMemoryMaps;        /*                                      */
extern OEMSVGAINFO SVGAHardware;       /*                                      */  


USHORT FAR HardwareColor(VOID);
VOID EXPENTRY AccessRegister(PREGADDRESS,USHORT,PBYTE);
USHORT PASCAL NEAR SaveRestorePVB(PVDHSAVEREST,USHORT,PENVIRONMENT);
VOID PASCAL NEAR SaveRestoreHW(PENVIRONMENT,USHORT);
VOID EXPENTRY AccessVideoEnable(USHORT,USHORT,USHORT FAR *);
VOID PASCAL FAR Transfer(SEL,SEL,ULONG,USHORT,USHORT,USHORT,USHORT,FPHWCOMMAND);
VOID PASCAL FAR AccessHardware(PREGADDRESS,USHORT,USHORT,USHORT,PREGDATA);

/****************************************************************************
 *
 * FUNCTION NAME = OpenScreenDD
 *
 * DESCRIPTION   = 
 *                                                                      
 * INPUT         = NONE
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

USHORT NEAR OpenScreenDD(VOID)
{
  USHORT rc,ActionTaken;
 

  if (rc = DosOpen(SCREENDD_NAME, &hScreenDD, &ActionTaken, NO_SIZE, 
     NO_ATTRIBUTES, OPEN_IF_EXISTS, NO_INHERIT+DENY_NONE+READ_WRITE, 
     RESERVED_LONG))
    hScreenDD = NULL;
  return (rc);
} 

/****************************************************************************
 *                                                                    
 *  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.                                
 *
 *            A check is made on the handle to SCREEN$, obtained by
 *            DosOpen, to determine it's validity. The handle is
 *            allocated on a per-process basis, which means it might
 *            not be valid the next time it is used. An alternative
 *            is to use instance data and store the handle there,
 *            but currently there is no other need for instance data
 *            and the overhead too high for 2 bytes out of a 4k page.
 *                                                                    
 *  ENTRY POINT: PhysToUVirt                                          
 *    LINKAGE:   CALL FAR                                             
 *                                                                    
 *  INPUT: (Passed on stack)                                          
 *             FAR *PhysicalAddress ( Physical address )              
 *             FAR *LDTSelector     ( 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(FARADDRESS PhysicalAddress,FARADDRESS far *LDTAddress,
                         USHORT Length)
{
  USHORT rc = 0;
  FARADDRESS ParmBlock;
  struct
  {
    FARADDRESS PhysicalAddress;
    short Length;
  } 
  ParmList;

  ParmList.Length = Length;
  ParmList.PhysicalAddress.FullAddress = PhysicalAddress.FullAddress;
 
  if (!hScreenDD)                      /* SCREEN$ not yet open              */
    rc = OpenScreenDD();
 
  if (!rc && !(rc = DosDevIOCtl((PVOID)&ParmBlock, (PVOID)&ParmList, 0x75, 0x3
     , hScreenDD)))
    *LDTAddress = ParmBlock;
 
  if (rc)
  {                                    /* try to reopen SCREEN$             */
 
    if (!(rc = OpenScreenDD()) && !(rc = DosDevIOCtl((PVOID)&ParmBlock, (PVOID
       )&ParmList, 0x75, 0x3, hScreenDD)))
      *LDTAddress = ParmBlock;
  } 
  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(USHORT LDTSelector)
{
  DosDevIOCtl((PVOID)NULL, 
              (PVOID)&LDTSelector, 
              0x71, 
              0x3, 
              hScreenDD);

  if (hScreenDD)
  {
    DosClose(hScreenDD);
    hScreenDD = 0;
  } 

} 

/****************************************************************************
 *
 *  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 VDM.
 *
 *  ENTRY POINT: SaveRestorePVB
 *    LINKAGE:   CALL FAR
 *
 *  INPUT: (Passed on stack)
 *             FAR *VDHSaveRest ( 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
 *
 *  EXTERNAL REFERENCES:
 *    ROUTINES: Transfer
 *
 *  Address a bitplane(some modes use same memory for all bitplanes)
 *
 *  For graphics modes the Sequencer Map Mask
 *  register is altered in order to save/restore each of the
 *  individually 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.
 *
 ****************************************************************************/

USHORT PASCAL NEAR SaveRestorePVB(PVDHSAVEREST VDHSaveRest,USHORT Direction,
                                  PENVIRONMENT Environment)
{
  USHORT rc,BitPlanes;
  FARADDRESS Source,Destination,Temp;
  ULONG BufSize;
  USHORT Mode;
  BYTE MapMask;
  REGDATA RegData;
  REGADDRESS RegAddress;

  Mode = Environment->ModeIndex;
  BitPlanes = pMemoryMaps[pModes[Mode].MemMap].BitPlanes; /*            */
  Destination.FullAddress = MAKEFARPTR(VDHSaveRest->PVBHugeSEL, 0);
 
  if (Environment->ModeData.fbType&MODE_FLAG_GRAPHICS)
    BufSize = pMemoryMaps[pModes[Mode].MemMap].PageLength; /*            */
  else
  {
    BitPlanes |= TEXTMODE;          //          
    BufSize = Environment->ModeData.BufferLength;
  }
  Source.FullAddress = pMemoryMaps[pModes[Mode].MemMap].Start.FullAddress;
 
  if (BufSize < 0x10000L)
    rc = PhysToUVirt(Source, &Temp, (USHORT)BufSize);
  else
    rc = PhysToUVirt(Source, &Temp, 0); /* set to 64k                       */
 
  if (!rc)
  {
 
    if (Direction == RESTORE)
    {                                  /* save MapMask state                */
      RegData.DataArea = &MapMask;
      RegData.FirstEntry = 2;
      RegData.NumEntries = 1;
      RegAddress.AddressPort = SEQADDRESSPORT;
      RegAddress.DataPort = SEQDATAPORT;
      RegAddress.ColorAdjust = NONE;
      RegAddress.Flags = SEQUENCERS_CMD;
      AccessHardware(&RegAddress, BYTES, 0, GET, &RegData);
    } 

    Transfer(Temp.Part.Selector,
	     VDHSaveRest->PVBHugeSEL,
	     BufSize,
	     Direction,
	     BitPlanes,
	     Environment->AdapterType,
	     Environment->ChipVersion,
	     Environment->pSetBankData);
 
    if (Direction == RESTORE)
    {
      RegData.DataArea = &MapMask;     /* restore Map Mask                  */
      RegData.FirstEntry = 2;
      RegData.NumEntries = 1;
      RegAddress.AddressPort = SEQADDRESSPORT;
      RegAddress.DataPort = SEQDATAPORT;
      RegAddress.ColorAdjust = NONE;
      RegAddress.Flags = SEQUENCERS_CMD;
      AccessHardware(&RegAddress, BYTES, 0, SET, &RegData);

      /*
      ** On Headland and Trident, second restore causes video corruption
      ** in text mode.           
      */
      if(!((SVGAHardware.AdapterType == VIDEO7_ADAPTER ||
          SVGAHardware.AdapterType == TRIDENT_ADAPTER) &&
          !(Environment->ModeData.fbType&MODE_FLAG_GRAPHICS)))
      SaveRestoreHW(Environment, SET); /* Restore Registers                 */

    } 

    FreePhysToUVirt(Temp.Part.Selector);
  } 

  return (rc?ERROR_VIO_MODE:0);
} 
