/*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 = BVHACCS.C
*
* DESCRIPTIVE NAME = Video Device Handler Ring 2 Routines
*
*
* VERSION      V2.0
*
* DATE
*
* DESCRIPTION
*
* FUNCTIONS
*
*
* NOTES        NONE
*
* STRUCTURES   NONE
*
* EXTERNAL REFERENCES
*
*              NONE
*
* EXTERNAL FUNCTIONS
*
*              NONE
*
*/
#include "bvhtype.h"

/***************************************************************************
*
* FUNCTION NAME = _HardwareColor
*
* DESCRIPTION   = Determine if current mode is color or monochrome .
*                 _HardwareColor is called by routines who need to know
*                 whether the current mode is color or monochrome.
*                 Determine whether color or monochrome mode to determine
*                 which ports should be used.  This is done by checking
*                 the I/O Address Select bit (b0) of the Miscellaneous
*                 Output Register:  b0:  0 = Monochrome emulation mode, 1
*                 = Color emulation mode
*
*                 ENTRY POINT: _HardwareColor
*                   LINKAGE:   CALL FAR
*
* INPUT         = NONE
* OUTPUT        = NONE
*
* RETURN-NORMAL =  1 - color, 0 - monochrome
* RETURN-ERROR  = NONE
*
**************************************************************************/

USHORT PASCAL NEAR HardwareColor (VOID)
{
   return ( (USHORT)(HWInpByte (MISCOUTPUTREGREAD) & 1) );
}

/***************************************************************************
*
* FUNCTION NAME = ACCESSVIDEOENABLE
*
* DESCRIPTION   = Set or read physical video enable
*                 AccessVideoEnable is called to query or set the physical
*                 video enable setting.
*
*                 ENTRY POINT: AccessVideoEnable
*                 LINKAGE:   CALL FAR
*
* INPUT         = (Passed on stack)
*                 WORD  ColorMode : Color or MonoChrome
*                 WORD  Direction ( GET or SET )
*                 DWORD VideoEnable ( far pointer to word )
*
*                 VideoEnable : 1 - display memory can access the palette
*                               0 - cannot
* RETURN-NORMAL = Video enable is set or returned
* RETURN-ERROR  = NONE
*
**************************************************************************/

VOID PASCAL NEAR AccessVideoEnable (USHORT ColorMode,
                                    USHORT Direction,
                                    USHORT FAR * pVideoEnable)
{
   USHORT usStatus1Reg;

   /*
    * usStatus1Reg: port of Input Status #1 Register.
    * 0x3DA for color and 0x3BA for monochrome.
    */
   usStatus1Reg = ColorMode ? 0x3DA : 0x3BA;

   /*
    * set the attribute controller register (0x3C0) to attribute address
    * register.
    */
   HWInpByte (usStatus1Reg);


   /*
    *  bit 5 of Attribute Address Port (0x3c0):
    *  1 (0x20) : Allows the display memory to access the palette
    *             RAM. Disable the host from gaining access to the
    *             plaette.
    *  0        : Allow the host to access and disable the display
    *             memory from gaining the access.
    */

   if (Direction == SET)
   {
      if (*pVideoEnable)
         HWOutpByte (ATTADDRESSPORT, 0x20);
      else
         HWOutpByte (ATTADDRESSPORT, 0);
   }
   else    /* GET */
   {
      if (HWInpByte (ATTADDRESSPORT) & 0x20)
         *pVideoEnable = 1;
      else
         *pVideoEnable = 0;
   }

}

/*****************************************************************************
*
*  SUBROUTINE NAME: AccessCursorPos
*
*  DESCRIPTIVE NAME: Set or read physical cursor position
*
*  FUNCTION: AccessCursorPos is called to determine or set the
*            physical cursor location
*
*  ENTRY POINT: AccessCursorPos
*  LINKAGE:   CALL FAR
*
*  INPUT: (Passed on stack)
*         WORD ModeColumn - the number of columns in this mode
*         WORD ColorMode
*         WORD Direction ( GET or SET )
*         WORD pCursor (far pointer to structure)
*
*  EXIT-NORMAL: Cursor position set or returned
*
*  INTERNAL REFERENCES:
*    ROUTINES: NONE
*
*  EXTERNAL REFERENCES:
*    ROUTINES: NONE
*
*****************************************************************************/

VOID PASCAL NEAR AccessCursorPos (USHORT ModeColumn,
                                  USHORT ColorMode,
                                  USHORT Direction,
                                  PVDH_CURSOR pCursor)
{
   USHORT CRTAddressPort, CRTDataPort, CursorPos;
   BYTE LowerByte, HigherByte;

   /*
    * CRT Controller Register Addr. Port: 0x3d4 - Color, 0x3b4 - Monochrome
    */
   CRTAddressPort = ColorMode ? CRTCOLORADDRPORT : CRTMONOADDRPORT;
   CRTDataPort    = ColorMode ? CRTCOLORDATAPORT : CRTMONODATAPORT;

   /*
    * The cursor position is determined by a 16-bit pointer to display memory,
    * CRT_CURSOR_LOW_LOC saves the lower 8 bits while CURSOR_HIGH_LOC
    * the higher 8 bits
    */

   if (Direction == SET)
   {
      CursorPos  = ModeColumn * pCursor->Row + pCursor->Column;

      LowerByte  = (BYTE)(USHORT)(CursorPos & 0xff);
      HWOutpByte (CRTAddressPort, CRT_CURSOR_LOW_LOC);
      HWOutpByte (CRTDataPort,    LowerByte);

      HigherByte = (BYTE)(USHORT)((CursorPos & 0xff00) >> 8);
      HWOutpByte (CRTAddressPort, CRT_CURSOR_HIGH_LOC);
      HWOutpByte (CRTDataPort,    HigherByte);
   }
   else /* GET */
   {
      HWOutpByte (CRTAddressPort, CRT_CURSOR_LOW_LOC);
      LowerByte = HWInpByte (CRTDataPort);

      HWOutpByte (CRTAddressPort, CRT_CURSOR_HIGH_LOC);
      HigherByte = HWInpByte (CRTDataPort);

      CursorPos = (((USHORT)HigherByte) << 8) +
                   (USHORT)LowerByte;

      pCursor->Row    = CursorPos / ModeColumn;
      pCursor->Column = CursorPos % ModeColumn;
   }

}

/*****************************************************************************
*
*  SUBROUTINE NAME: AccessCursorType
*
*  DESCRIPTIVE NAME: Set or read physical cursor type
*
*  FUNCTION: AccessCursorType is called to determine or set the
*            physical cursor type
*
*  ENTRY POINT: AccessCursorType
*    LINKAGE:   CALL FAR
*
*  INPUT: (Passed on stack)
              WORD  ColorMode
*             WORD  Direction ( GET or SET )
*             DWORD pCursor ( far pointer to structure )
*
*  EXIT-NORMAL: Cursor type is set or returned
*
*  INTERNAL REFERENCES:
*    ROUTINES: NONE
*
*  EXTERNAL REFERENCES:
*    ROUTINES: NONE
*
*****************************************************************************/

VOID PASCAL NEAR AccessCursorType (USHORT ColorMode,
                                   USHORT Direction,
                                   PVDH_CURSOR pCursor)
{
   USHORT CRTAddressPort, CRTDataPort;
   BYTE ScanLine;

   /*
    * CRT Controller Register Addr. Port: 0x3d4 - Color, 0x3b4 - Monochrome
    */
   CRTAddressPort = ColorMode ? CRTCOLORADDRPORT : CRTMONOADDRPORT;
   CRTDataPort    = ColorMode ? CRTCOLORDATAPORT : CRTMONODATAPORT;

   /*
    * Cursor type means the shape of cursor. There are 32 scan lines in a
    * cursor just like a character. topscanline and bottomscanline define
    * the height of the cursor, which are saved in ports CRT_CURSOR_START
    * and CRT_CURSOR_END (lower 5 bits). Bit 5 (0x20) is cursor ON/OFF bit.
    * 1 is OFF and pCursor->Attribute should be -1.
    */

   if (Direction == SET)
   {
      HWOutpByte (CRTAddressPort, CRT_CURSOR_START);
      ScanLine = HWInpByte (CRTDataPort);

      ScanLine &= 0xC0;          /* 11000000B, Clear bits we will set */
      ScanLine |= (BYTE)(pCursor->TopScanLine);

      if (pCursor->Attribute == -1)                  /* Hidden Cursor */
         ScanLine |= 0x20;                           /*     00100000B */

      HWOutpByte (CRTDataPort, ScanLine);

      HWOutpByte (CRTAddressPort, CRT_CURSOR_END);
      ScanLine = HWInpByte (CRTDataPort);

      ScanLine &= 0xE0;          /* 11100000B, Clear bits we will set */
      ScanLine |= (BYTE)(pCursor->BottomScanLine);

      HWOutpByte (CRTDataPort, ScanLine);
   }
   else   /* GET */
   {
      pCursor->Width = 1;   /* Cursor is always one column wide */

      HWOutpByte (CRTAddressPort, CRT_CURSOR_START);
      ScanLine = HWInpByte (CRTDataPort);

      if (ScanLine & 0x20)   /* Hidden Cursor ? */
         pCursor->Attribute = -1;
      else
         pCursor->Attribute = 0;

      pCursor->TopScanLine = ScanLine & 0x1F;  /* lower 5 bits */

      HWOutpByte (CRTAddressPort, CRT_CURSOR_END);
      ScanLine = HWInpByte (CRTDataPort);

      pCursor->BottomScanLine = ScanLine & 0x1F;  /* lower 5 bits */
   }

}

/*****************************************************************************
*
*  SUBROUTINE NAME: AccessBlink
*
*  DESCRIPTIVE NAME: Set or read physical blink vs. BG intensity
*
*  FUNCTION: AccessBlink is called to query or set the physical
*            blink versus background intensity setting
*
*  ENTRY POINT: AccessBlink
*    LINKAGE:   CALL FAR
*
*  INPUT: (Passed on stack)
*             WORD  ColorMode
*             WORD  Direction ( GET or SET )
*             DWORD * pBlink ( far pointer to word )
*                   *pBlink: 0 - blink, 1 - select a background color
*
*  EXIT-NORMAL: Blink vs. BG intensity is set or returned
*
*  INTERNAL REFERENCES:
*    ROUTINES: NONE
*
*  EXTERNAL REFERENCES:
*    ROUTINES: NONE
*
*****************************************************************************/

VOID PASCAL NEAR AccessBlink (USHORT ColorMode,
                              USHORT Direction,
                              USHORT FAR * pBlink)
{
   USHORT usStatus1Reg;
   BYTE bData;

   /*
    * usStatus1Reg: port of Input Status #1 Register.
    * 0x3DA for color and 0x3BA for monochrome.
    */
   usStatus1Reg = ColorMode ? 0x3DA : 0x3BA;

   /*
    * set the attribute controller register (0x3C0) to attribute address
    * register.
    */
   HWInpByte (usStatus1Reg);

   /*
    * Bit 3 (0x08) of Mode Control Register:
    * 0 - Use bit 7 of the character attribute code to select a background
    *     color. Do not allow blinking.  *pBlink = 1;
    * 1 - Use bit 7 to enable or disable blinking.   *pBlink = 0;
    */
   HWOutpByte (ATTADDRESSPORT, ATT_MODE_CTRL);
   bData = HWInpByte (ATTDATAREADPORT);

   if (Direction == SET)
   {
      bData &= 0xF7;        /* 11110111B, select background intensity */

      if (*pBlink == 0)
         bData |= 0x08;    /* 00001000B, enable blinking */

      HWOutpByte (ATTDATAWRITEPORT, bData);
   }
   else   /* GET */
   {
      if (bData & 0x08)
         *pBlink = 1;    /* Background intensity */
      else
         *pBlink = 0;    /* Blinking*/
   }

   /*
    * video on, make display memory access palette RAM
    */
   HWInpByte (usStatus1Reg);
   HWOutpByte (ATTADDRESSPORT, 0x20); /* bit 5 */

}

/*****************************************************************************
*
*  SUBROUTINE NAME: AccessOverscan
*
*  DESCRIPTIVE NAME: Set or read physical border color
*
*  FUNCTION: AccessOverscan is called to query or set the physical
*            overscan color
*
*  ENTRY POINT: AccessOverscan
*    LINKAGE:   CALL FAR
*
*  INPUT: (Passed on stack)
*             WORD  ColorMode
*             WORD  Direction ( GET or SET )
*             WORD  pOverscan ( far pointer to word )
*
*  EXIT-NORMAL: Overscan color is set or returned
*
*  INTERNAL REFERENCES:
*    ROUTINES: NONE
*
*  EXTERNAL REFERENCES:
*    ROUTINES: NONE
*
*****************************************************************************/

VOID PASCAL NEAR AccessOverscan (USHORT ColorMode,
                                 USHORT Direction,
                                 USHORT FAR * pOverscan)
{
   USHORT usStatus1Reg;

   usStatus1Reg = ColorMode ? 0x3DA : 0x3BA;

   /*
    * set the attribute controller register (0x3C0) to attribute address
    * register.
    */
   HWInpByte (usStatus1Reg);

   HWOutpByte (ATTADDRESSPORT, ATT_OVERSCAN_CLR);

   if (Direction == SET)
   {
      HWOutpByte (ATTDATAWRITEPORT, (BYTE)(*pOverscan));
   }
   else /* GET */
   {
      *pOverscan = (USHORT)HWInpByte (ATTDATAREADPORT);
   }

   /*
    * video on, make display memory access palette RAM
    */
   HWInpByte (usStatus1Reg);
   HWOutpByte (ATTADDRESSPORT, 0x20); /* bit 5 */

}

/*****************************************************************************
*
*  SUBROUTINE NAME: AccessUnderscore
*
*  DESCRIPTIVE NAME: Set or read physical underscore scan line no.
*
*  FUNCTION: AccessUnderscore is called to query or set the physical
*            underscore scan line
*
*  ENTRY POINT: AccessUnderscore
*    LINKAGE:   CALL FAR
*
*  INPUT: (Passed on stack)
*             WORD  ColorMode
*             WORD  Direction ( GET or SET )
*             DWORD * pUnderscore ( far pointer to word )
*
*  EXIT-NORMAL: Underscore scan line is set or returned
*
*  INTERNAL REFERENCES:
*    ROUTINES: NONE
*
*  EXTERNAL REFERENCES:
*    ROUTINES: NONE
*
*****************************************************************************/

VOID PASCAL NEAR AccessUnderscore (USHORT ColorMode,
                                   USHORT Direction,
                                   USHORT FAR * pUnderscore)
{
   USHORT CRTAddressPort, CRTDataPort;
   BYTE bUnderscore;

   /*
    * CRT Controller Register Addr. Port: 0x3d4 - Color, 0x3b4 - Monochrome
    */
   CRTAddressPort = ColorMode ? CRTCOLORADDRPORT : CRTMONOADDRPORT;
   CRTDataPort    = ColorMode ? CRTCOLORDATAPORT : CRTMONODATAPORT;

   /*
    * bits 0-4 of CRT_UNDERSCORE port contains the line position of the
    * underscore within a charcter since maximum 32 scanlines are possible.
    */

   HWOutpByte (CRTAddressPort, CRT_UNDERSCORE);
   bUnderscore = HWInpByte (CRTDataPort);

   if (Direction == SET)
   {
      /*
       * 0xE0 = 11100000B, clear bits we will set
       * and put the bits we will set in bUnderscore.
       */
      bUnderscore = (BYTE)(((USHORT)bUnderscore & 0xE0) | *pUnderscore);

      HWOutpByte (CRTDataPort, bUnderscore);
   }
   else  /* GET */
   {
      /* extract the line number */
      *pUnderscore = (USHORT)(bUnderscore & 0x1F);
   }

}

/***************************************************************************
*
* FUNCTION NAME = ACCESSHARDWARE
*
* DESCRIPTION   = Set or read physical indexed registers
*                 AccessHardware is called to query or set the physical
*                 indexed registers - Sequencers, Attributes, CRTs, or
*                 Graphics
*
*                 ENTRY POINT: AccessHardware
*                 LINKAGE:   CALL FAR
*
* INPUT         = (Passed on stack)
*                 DWORD  pRegAddress ( far pointer to structure )
*                              RegAddressPort
*                              RegDataPort
*                              RegColorAdjust
*                              RegFlags
*                 WORD   DataType ( BYTES or WORDS )
*                 WORD   ColorMode
*                 WORD   Direction ( GET or SET )
*                 DWORD  pRegData ( far pointer to structure )
*                           DWORD DataArea  ( far pointer to data table )
*                           WORD  FirstEntry
*                           WORD  NumEntries
*
* RETURN-NORMAL = Indexed registers are altered or queried
* RETURN-ERROR  = NONE
*
**************************************************************************/

VOID PASCAL NEAR AccessHardware (PREGADDRESS   pRegAddr,
                                 USHORT        DataType,
                                 USHORT       ColorMode,
                                 USHORT       Direction,
                                 PREGDATA      pRegData)
{
   USHORT NumEntries, DataRegIndex, AddressPort, DataPort, Status1Reg,
         IsATTReg = FALSE, IsSEQReg = FALSE;
   PBYTE pDataArea;

   DataRegIndex = pRegData->FirstEntry;
   NumEntries   = pRegData->NumEntries;
   pDataArea    = pRegData->DataArea;

   if (ColorMode)
   {
      AddressPort = pRegAddr->AddressPort + pRegAddr->ColorAdjust;
      DataPort    = pRegAddr->DataPort + pRegAddr->ColorAdjust;
      Status1Reg = 0x3DA;   /* for attribute Control Reg */
   }
   else /* Monochorme */
   {
      AddressPort = pRegAddr->AddressPort;
      DataPort    = pRegAddr->DataPort;
      Status1Reg = 0x3BA;   /* for attribute Control Reg */
   }

   if (pRegAddr->Flags == IS_ATT_CTRL_REG) IsATTReg = TRUE;
   if (pRegAddr->Flags == IS_SEQ_REG)      IsSEQReg = TRUE;

   /*
    * When updating the Clocking Mode Reg. (0x01) of sequencer register,
    * sequencer must be reset to preserve display memory contents by
    * setting bits 0-1 of Reset Reg. (0x00) to 0.
    */
   if ((IsSEQReg) && (Direction == SET))
   {
      HWOutpByte (SEQADDRESSPORT, SEQ_RESET);
      HWOutpByte (SEQDATAPORT, 0);
   }

   while (NumEntries--)
   {

      /*
       * If attribute controller reg, set the attribute controller register
       * (0x3C0) to attribute address register by input port Status1Reg.
       */
      if (IsATTReg)
         HWInpByte (Status1Reg);

      /* set the index to data registers and increment the index */
      HWOutpByte (AddressPort, (BYTE)(USHORT)(DataRegIndex));

      if (Direction == SET)
      {
         /*
          * If we are going to set Mode Control Reg. of Attr Ctrl reg,
          * we have to wait for vertical retrace to avoid glitching VRAM.
          * bit 3 (0x08) of input status #1 reg. is the retrace bit.
          */
         if ((IsATTReg) && (DataRegIndex == ATT_MODE_CTRL))
         {
            /* wait while in vertical retrace mode */
            while (HWInpByte(Status1Reg) & 0x08);
            /*
             * wait while in display mode, i.e., wait for vertical retrace
             *  to begin again.
             */
            while (!(HWInpByte(Status1Reg) & 0x08));
         }

         HWOutpByte (DataPort, *(pDataArea++));
         DataRegIndex++;
      }
      else    /* GET */
      {
         if (DataType == WORDS)
            *(USHORT *)(pDataArea++) = (USHORT)HWInpByte (DataPort);
         else
            *(pDataArea++) = HWInpByte (DataPort);
         DataRegIndex++;
      }

      if (DataType == WORDS)
         pDataArea++;       /* advance one more byte */

   } /* while */

   /*
    * Set the sequencer back
    */
   if ((IsSEQReg) && (Direction == SET))
   {
      HWOutpByte (SEQADDRESSPORT, SEQ_RESET);
      HWOutpByte (SEQDATAPORT, 0x03);
   }

}

;/***************************************************************************
;*
;* FUNCTION NAME = ACCESSREGISTER
;*
;* DESCRIPTION   = Set or read physical non-indexed register
;*                 AccessRegister is called to query or set the physical
;*                 non-indexed register specified
;*
;*                 ENTRY POINT: AccessRegister
;*                 LINKAGE:   CALL FAR
;*
;* INPUT         = (Passed on stack)
;*                 DWORD  RegAddress ( far pointer to structure )
;*                           WORD AddressPort
;*                           WORD DataPort
;*                           WORD ColorAdjust
;*                           WORD Flags
;*                 WORD   Direction ( GET or SET or SETWORD )
;*                 DWORD  RegData ( far pointer to data )
;*
;* RETURN-NORMAL = Non-indexed register is altered or queried
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

VOID PASCAL NEAR AccessRegister (PREGADDRESS pRegAddr,
                                 USHORT     Direction,
                                 PVOID          pData)
{
   USHORT DataPort;

   DataPort = pRegAddr->DataPort;

   if (Direction == SET)    /* output a byte */
   {

      if (DataPort == MISCOUTPUTREGWRITE)
      {
         /*
          * When updating Miscellaneous Output Reg. (0x3c2),
          * sequencer must be reset to preserve display memory contents by
          * setting bits 0-1 of Reset Reg. (0x00) to 0.
          */
         HWOutpByte (SEQADDRESSPORT, SEQ_RESET);
         HWOutpByte (SEQDATAPORT, 0);

         HWOutpByte (DataPort, *((BYTE *)pData));

         /* Set the sequencer back */
         HWOutpByte (SEQADDRESSPORT, SEQ_RESET);
         HWOutpByte (SEQDATAPORT, 0x03);
      }
      else /* other registers */
      {
         HWOutpByte (DataPort, *((BYTE *)pData));
      }

   }   /* end of SET */

   else if (Direction == SETWORD)
      HWOutpWord (DataPort, *((USHORT *)pData));

   else     /* GET */
     *(BYTE *)pData = HWInpByte (DataPort);

}

/*************************************************************************
*
* FUNCTION NAME = MAKE32P
*
* DESCRIPTION   = Use CRMA to convert Selector:Offset to linear address.
*
* INPUT         = USHORT Selector
*                 USHORT Offset
*                 PULONG FlatPointer
* OUTPUT        = ULONG Linear address equivalent
*
* RETURN-NORMAL = Linear address of selector:offset
* RETURN-ERROR  = NULL
*
**************************************************************************/

VOID PASCAL NEAR MAKE32P (USHORT          Sel,
                          USHORT       Offset,
                          ULONG FAR *   pFlat)
{
   *pFlat = ((ULONG)(Sel >> 3) << 16) | (ULONG)Offset;
}

