/*DDK*************************************************************************/
/*                                                                           */
/* 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 = VVCIRRUS.C
 *
 * DESCRIPTIVE NAME = Virtual Video Cirrus Specific Processing
 *
 *
 * VERSION = V2.1
 *
 * DATE      04/30/93
 *
 * DESCRIPTION  This module contains all accelerator specific SVGA code and data.
 *
 *
 * FUNCTIONS
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#define  IO8BIT           /* CL386 Version 6.00.054 FLAG:              */
#include <mvdm.h>
#include <vvd.h>
#include <vvdp.h>

#ifdef   VDDSTRICT
MODNAME = __FILE__;
#endif
#define  INCL_DOSERRORS
#include <bseerr.h>


#pragma  BEGIN_SWAP_DATA
/*
**     Externals
*/
extern ULONG ulSVGAChipType;
extern ULONG ulSVGAVRAMSize;                                    /*          */
extern SA8514INFO sA8514Info;
extern BOOL fSVGASeqFixups;
extern PLE pleGDCIndx;                                          /*          */
extern PLE pleGDCData;                                          /*          */
extern PLE pleSEQData;                                          /*          */
extern BYTE abAccelGDCReadMask[];                               /*          */
extern BYTE abCRTMask[];                                        /*          */

CHAR pszCirrusAdapterName [] = "CIRRUS" ;                       /*          */

PCHAR ppszCirrusChipNames [MAX_CIRRUS_CHIP] =                   /*          */
{  /* As produced by SVGA.EXE! */                               /*          */
  "GD5420",                                                     /*          */
  "GD5422",                                                     /*          */
  "GD5424",                                                     /*          */
  "GD5426",                                                     /*          */
  "GD5428",                                                     /*          */
  "GD5429",                                                     /*          */
  "GD543X",                                                     /*          */
  "GD5434",                                                     /*          */
};                                                              /*          */

RLE rleCirrusMemSEQ07 =                                         /*          */
{ /* See vvCirrusPackedMode below */
  &pleSEQData,                          /* 0x03c5h (R/W) */
  PORTF_NOTVALIDSVGAPORT,               /* Not required */      /*          */
  0x07, 0x00,                           /* Index range */
  0x00,                                 /* No conditions */
  0xff,
  {0x00, 0x00, 0x00, 0x00},
  NULL,
  NULL,
};

#pragma  END_SWAP_DATA

#pragma  BEGIN_SWAP_CODE

/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusEditTables()
 *
 * DESCRIPTION   = Called once to do SVGA-specific initialisation
 *
 * INPUT         =
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 **************************************************************************/

VOID PRIVENTRY vvCirrusEditTables( VOID )
{
  INT i;
  if (ulSVGAChipType > CIRRUS_5424_CHIP)                        /*          */
    ulSVGAVRAMSize = 0x200000L;                                 /*          */
  fSVGASeqFixups = FALSE;                                       /*          */
  rleCirrusMemSEQ07.rle_flags &= ~PORTF_NOTVALIDSVGAPORT;       /*          */
  /*           
  ** Fix up the masks as to allow all readable registers to be read.
  ** By default,  readmask pointer is set to writemasks. Accelerator masks
  ** set to all readable are available for fixups.
  ** Force 0's in all bit positions of non-existing or
  ** non-readable registers. Remove read-only regs from the write mask.
  ** If in any doubts about the write-only regs being initialized by the cleanup
  ** as part of the vvInt10SetModePrepare, use vvxxCreate
  ** as an occasion to initialize the shadow state of the write-only regs.
  */
//@V3.0YEE01  abAccelGDCReadMask[0xF >> 3] &= ~(1 << (0xF % 8));    //doesn't exist
  abAccelGDCReadMask [0x0f] = 0x00;              //doesn't exist
  if (ulSVGAChipType < CIRRUS_543X_CHIP)
  {
    for (i=12;i<0x20;i++)
      abAccelGDCReadMask [i] = 0x00;
//@V3.0YEE01      abAccelGDCReadMask[i >> 3] &= ~(1 << (i % 8));
  }
  else
  {
    for (i=16;i<0x20;i++)
      abAccelGDCReadMask [i] = 0x00;
//@V3.0YEE01    abAccelGDCReadMask[i >> 3] &= ~(1 << (i % 8));
  }
  for (i=0x1e;i<0x28;i++)                     //read only regs
    abCRTMask [i] = 0x00;
//@V3.0YEE01    abCRTMask[i >> 3] &= ~(1 << (i % 8));

  pleGDCData.pbBRegReadMask = &abAccelGDCReadMask [0];          /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusPackedMode
 *
 * DESCRIPTION   = Get SVGA packed pixel mode.
 *
 *                 This req'd because the GDC Mode reg doesn't reflect
 *                 256-colour modes.
 *
 *                 ATI has bits in extended 'ATI registers'.
 *                 Video7 have bits in extended sequencer 0xfc.
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = True = 256 colour mode
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * REMARK: More on the fault hook processing...
 *         Page mapping depends on the state evaluated from the
 *         shadow registers,
 *         which has to represent the true state of the hardware.
 *         If the register is not added to the aprleMemory structure,
 *         its shadow value represents the true state
 *         only after the mode set has returned,
 *         when vvUpdateAll will refresh them all.
 *         If the page mappings are believed to be       at that time,
 *         they will be invalidated and fault hooks enabled again.
 *         However, if evaluating 256-color (i.e. packed) mode
 *         is essential before the mode set returns,
 *         ensure that the register which is being evaluated is added
 *         to the aprleMemory struc.
 *
 ****************************************************************************/

BOOL PRIVENTRY vvCirrusPackedMode(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return( vvEGAPackedMode( hvdm )
          || (pvd->aregSEQData [0x07] & 0x01) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusInterlaced
 *
 * DESCRIPTION   = Get Interlaced Status
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = True = interlacing on
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

BOOL PRIVENTRY vvCirrusInterlaced(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return( (pvd->aregCRTData [0x1a] & 0x01) >> ZEROBITS( 0x01 ) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusStartAddr
 *
 * DESCRIPTION   = Get Display frame start address
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = offset into VRAM for display frame
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

ULONG PRIVENTRY vvCirrusStartAddr(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);

  return(  vvCGAStartAddr( hvdm )
           | ((pvd->aregCRTData [0x1b] & 0x01)
              >> ZEROBITS( 0x01) << 16)
           | ((pvd->aregCRTData [0x1b] & 0x0c)
              >> ZEROBITS( 0x0c) << 17) );
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusHorzLogEnd
 *
 * DESCRIPTION   = Get Horizontal Logical End
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Horizontal Logical End
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT PRIVENTRY vvCirrusHorzLogEnd(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  USHORT usLogEndBytes = (pvd->aregCRTData [REG_CRTOFFSET]+
                          ((pvd->aregCRTData [0x1b] & 0x10) >> ZEROBITS(0x10)<< 8))
                        << (1
                        + ((pvd->aregCRTData[REG_CRTUNDLINELOC])
                           ? 2
                           : !(pvd->aregCRTData [REG_CRTMODECTRL] & 0x40)));

  return(usLogEndBytes);                                        /*          */
}
                                                                /*          */
/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusBitsPerPixel
 *
 * DESCRIPTION   = Get Bits Per Pixel
 *
 * INPUT         = hvdm
 *
 * OUTPUT        = Bits Per Pixel
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 ****************************************************************************/

USHORT PRIVENTRY vvCirrusBitsPerPixel(
  HVDM hvdm )
{
  register PVDMDATA pvd = pVDMData(hvdm);
  register BYTE bPixelBytes;

  bPixelBytes = ((pvd->aregSEQData[0x07] & 0x06)
                 >> ZEROBITS( 0x06 )) + 1;
  if( bPixelBytes == 4)
    bPixelBytes = 2;
  return( ((!bPixelBytes)
           ? vvVGABitsPerPixel( hvdm )
           : (bPixelBytes << 3)) );
}

/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusSetBank()
 *
 * DESCRIPTION   = Set Cirrus bank register
 *
 * INPUT         = hvdm
 *                 ulBank
 *                 fSetWriteBank
 *
 * OUTPUT        = None
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 * NOTE: To address 4 MB of RAM, set bit 5 of 3ce,b to 1. Shift bank only twice.
 ****************************************************************************/
/*            */
VOID    PRIVENTRY vvCirrusSetBank(
  HVDM hvdm,
  ULONG ulBank,
  BOOL fSetWriteBank )
{
  register BYTE   bBank, bTmp, bIndx;

  fSetWriteBank;                       // shut the compiler up
  bIndx = vvInput( hvdm,
                   &pleGDCIndx );      // get current contents  /*          */
  vvOutput( hvdm,
            &pleGDCIndx,
            0x0b);                     // Graphics Controller   /*          */
  bBank = vvInput( hvdm,
                  &pleGDCData );
  if ((ulBank >= 0x10) && !(bBank & 0x20))                      /*          */
  {                                    // force 16K granularity
    vvOutput( hvdm,
              &pleGDCData,
              (BYTE) (bBank | 0x20));                           /*          */

  }
  vvOutput( hvdm,
            &pleGDCIndx,
            0x09);                     // Offset register       /*          */
  bTmp = vvInput( hvdm,
                  &pleGDCData );       // get current contents  /*          */

  if ((bBank & 0x20) == 0x20)
  {
    bTmp &= 0x03;
    bBank = (BYTE)ulBank << 2;         // shift into place (bits 7-2)           
  }
  else
  {
    bTmp &= 0x0f;
    bBank = (BYTE)ulBank << 4;         // shift into place (bits 7-4)           
  }

  bBank |= bTmp;                       // combine other previous bits

  vvOutput( hvdm,
            &pleGDCData,
            bBank );                   // Set Bank              /*          */
  vvOutput( hvdm,
            &pleGDCIndx,
            bIndx);                    // Restore Index         /*          */
}

/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusGetBank()
 *
 * DESCRIPTION   = Get Cirrus bank register
 *
 * INPUT         = hvdm
 *                 fGetWriteBank
 *
 * OUTPUT        = ulBank
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * NOTE: In dual-page mapping scheme, both offset registers can be used.
 * Address A(15) bit selects Offset 1. Currently not taken into account.
 *
 ****************************************************************************/
/*            */
ULONG   PRIVENTRY vvCirrusGetBank(
  HVDM hvdm,
  BOOL fGetWriteBank )
{
  BYTE bBank, bTmp;
  BYTE b2MBAddressing;

  bTmp = vvInput( hvdm,
                  &pleGDCIndx );      // get current contents   /*          */
  vvOutput( hvdm,
            &pleGDCIndx,
            0x0B );                   // Mode extn register     /*          */
  b2MBAddressing = vvInput( hvdm,
                            &pleGDCData )                       /*          */
                   & 0x20;
  vvOutput( hvdm,
            &pleGDCIndx,
            0x09);                    // Offset register        /*          */
  bBank = vvInput( hvdm,
                   &pleGDCData );     // get current contents   /*          */
  vvOutput( hvdm,
            &pleGDCIndx,
            bTmp );                   // Restore Index          /*          */
  if(b2MBAddressing)                                            /*          */
  {
    bBank = (bBank & 0x7F);
    bBank >>= 2;                                             //          
  }
  else
    bBank >>= 4;
  return( bBank );
}

/***************************************************************************
 *
 * FUNCTION NAME = vvCirrusWriteGDCData()
 *
 * DESCRIPTION   = Do gymnastics associated with emulating the
 *                 Cirrus GDC regs in the background.
 *
 * INPUT         = bNewValue = new GDC reg value
 *
 * OUTPUT        = Appropriate GDC data value in shadow updated
 *
 * RETURN-NORMAL =
 * RETURN-ERROR  =
 *
 * CALLED BY
 *      vvWriteGDCDataFgnd
 *      vvWriteGDCDataBgnd
 *
 **************************************************************************/

VOID PRIVENTRY vvCirrusWriteGDCData(
  BYTE bNewValue )
{
  if( (VDMData.regGDCIndx == 0x09)
      && !(VDMData.flVDMVideo & VDM_FGND)                       /*          */
      && (VDMData.mstateVideo == MEMORY_GRFX256)
      && !(VDMData.flVDMXVideo & VDMX_INT2F))                   /*          */
  {
    VDMData.ulDirtyBankEvent = VDMData.aregGDCData [0x09] >> 4; /*@V3.0MNH03*/
    /*
    ** Shadow before mapping, in case mapping causes a freeze.
    */                                                          /*          */
    VDMData.aregGDCData [0x09] = bNewValue;                     /*@V3.0MNH03*/
    vvMapBank( bNewValue >> 4);                                 /*          */
  }
  VDMData.aregGDCData [VDMData.regGDCIndx] = bNewValue;         /*@V3.0MNH03*/
}

#pragma  END_SWAP_CODE

#pragma  BEGIN_SWAP_DATA

SSVGAINFO sCirrusAdapterInfo =                                  /*          */
{
  { /* SVGAINFO */                                              /*          */
    { /* SEGAINFO */
      { /* SCGAINFO */
        &vvEGAAdjustedPort,
        &vvCirrusStartAddr,
        &vvEGAOddEvenMode,
        &vvEGAHighResMode,
        &vvEGAHorzDspEnd,
        &vvCirrusHorzLogEnd,                                    /*          */
        &vvVGAVertDspEnd,
        &vvVGABitsPerPixel,
        &vvVGAPrepareSetMode,                                   /*          */
      },
      &vvEGAPackedMode,
      &vvVGAVertLineCmp,
    },
    &vvVGADacSave,                                              /*          */
    &vvVGADacRestore,                                           /*          */
  },                                                            /*          */
  &vvCirrusEditTables,
  &vvCirrusInterlaced,
  &vvVGAUpdateIoState,
  &vvVGARestoreIoState,
  &vvCirrusSetBank,
  &vvCirrusGetBank,
  &vvVGAFixSetMode,
  &vvVGAFixSetBgnd,
  &vvCirrusWriteGDCData,                                        /*          */
  &vvVGAReadSEQDataBgnd,
  &vvVGAWriteSEQDataBgnd,
  &vvVGADacRS2Clear,                                            /*          */
  &vvVGADacRS2Set,                                              /*          */
  &vvVGADacRS3,                                                 /*          */
  NULL,                                                         /*          */
  pszCirrusAdapterName,
  MAX_CIRRUS_CHIP,
  ppszCirrusChipNames,
  NULL,                                                         /*          */
};

#pragma  END_SWAP_DATA
