;*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.;
;*****************************************************************************/
        PAGE    ,132
        TITLE   Virtual Video CRT I/O Processing

;/*****************************************************************************
;*
;* SOURCE FILE NAME = VVCRTIO.ASM
;*
;* DESCRIPTIVE NAME = Virtual Video Device Driver CRT I/O Processing
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/10/88
;*
;* DESCRIPTION  This module contains the VVD's CRT I/O handlers.
;*
;* FUNCTIONS
;*              VVReadCRTIndxFgnd()     Read CRT index byte
;*              VVReadCRTIndxBgnd()     Read CRT index byte
;*              VVWriteCRTIndxFgnd()    Write CRT index byte
;*              VVWriteCRTIndxBgnd()    Write CRT index byte
;*              VVReadCRTIndxFgndW()    Read CRT index word
;*              VVWriteCRTIndxFgndW()   Write CRT index word foreground
;*              VVWriteCRTIndxBgndW()   Write CRT index word background
;*              VVReadCRTDataFgnd()     Read CRT data byte
;*              VVReadCRTDataBgnd()     Read CRT data byte
;*              VVWriteCRTDataFgnd()    Write CRT data byte
;*              VVWriteCRTDataBgnd()    Write CRT data byte
;*              vvUpdateCursorData()    Return current cursor data
;*
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   11/10/88                     JTP - Created.
;*   07/18/91                     B724762 - Only shadow the CRTC register
;*                                if the target/source I/O port matches
;*                                the current video mode (MONO/COLOR).
;*   09/14/91                     Delete window syncronization references
;*                                (B726840)
;*   02/27/92                     B733211 - Performance enhancement to
;*                                320x200 mode.
;*   08/03/93                     72133 - Avoid Trap D in the PM Shield
;*                                by screening CRTC programming in the
;*                                the background.
;*   06/04/93              F69306  - Add support for S3
;*   11/02/93              75458  S3 Merge
;*   01/12/93  ChangeTeam  76726  Avoid video corruption in Flight Simulator 5.0
;*   04/14/94             D81883  Use vvCrtcPort instead of PORT_COLR*
;*   02/24/95  @V3.0YEE01 113003  Bit mask changed to byte mask
;*****************************************************************************/


        .xlist

        include mvdm.inc
        include vddseg.inc
        .list
        include vvd.inc
        include vvdp.inc


        DefData     IMPORT,SWAP,C
        ULONG       TKSSBase            ;required for SSToDS macro
       IFDEF SVGA
        PBYTE       abCRTMask                           ;          
       ENDIF
        EndData


        DefCode     IMPORT,SWAP,PASCAL
        DefFn       vvAddEvent
        DefFn       vvUpdateScreenState
        EndCode


        DefCode     EXPORT,SWAP,PASCAL

       IFNDEF VGA
        DefFn       VVReadCRTIndxFgnd
       ENDIF
        DefFn       VVReadCRTIndxBgnd
       IFNDEF VGA
        DefFn       VVWriteCRTIndxFgnd
       ENDIF
        DefFn       VVWriteCRTIndxBgnd
       IFNDEF VGA
        DefFn       VVReadCRTIndxFgndW
       ENDIF
        DefFn       VVWriteCRTIndxBgndW
        DefFn       VVWriteCRTIndxFgndW
       IFNDEF VGA
        DefFn       VVReadCRTDataFgnd
       ENDIF
        DefFn       VVReadCRTDataBgnd
       IFNDEF VGA
        DefFn       VVWriteCRTDataFgnd
       ENDIF
        DefFn       VVWriteCRTDataBgnd

        DefFn       vvUpdateCursorData


        IFNDEF VGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadCRTIndxFgnd()
;*
;* DESCRIPTION   = Read CRT index byte
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a byte from the CRT controller index register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;*                 Note that the only real purpose this routine serves is to
;*                 enhance operation on MONO/CGA/EGA adapters, which are
;*                 normally not readable.  This provides applications with a
;*                 benefit of operating in V86-mode that should in no way
;*                 affect compatibility.
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 case VGA:
;*                   none
;*                 case OTHER:
;*                   return CRT index value
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadCRTIndxFgnd
        FallInto VVReadCRTIndxBgnd
EndProc   VVReadCRTIndxFgnd

       ENDIF ;VGA


;/***************************************************************************
;*
;* FUNCTION NAME = VVReadCRTIndxBgnd()
;*
;* DESCRIPTION   = Read CRT index byte
;*
;*                 This registered subroutine is called whenever a
;*                 background VDM reads a byte from the CRT controller
;*                 index register (see VDHInstallIOHook for complete
;*                 semantics).
;*
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;* OUTPUT        =
;*                 AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadCRTIndxBgnd
       IFNDEF VGA
        FallFrom VVReadCRTIndxFgnd
       ENDIF
        mov     al,VDMData.regCRTIndx       ;return CRT controller index

;/*
;**
;**    Although 3Bx and 3Dx are available on the EGA/VGA, we must
;**    emulate the true effect when the target port is invalid
;**    under the current mode.  For example, if the VDM is currently
;**    in MONO mode then all accesses to the 3Dx are invalid.
;*/

       IFDEF EGAVGA                                                     ;          
        mov     cl,dl                       ;Get addr color bit         ;          
        shr     cl,6                        ;Shift to MISCOUT_COLRPORTS ;          
        xor     cl,[VDMData.regMiscOut]     ;Compare color bits         ;          
        and     cl,MISCOUT_COLRPORTS        ;access allowed?            ;          
        jz      short rCRTIndxExit          ;yes                        ;          
        mov     al,0FFh                     ;no, return emulated value  ;          
rCRTIndxExit:                                                           ;          
       ENDIF                                                            ;          

        ExitProc
EndProc   VVReadCRTIndxBgnd


       IFNDEF VGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteCRTIndxFgnd()
;*
;* DESCRIPTION   = Write CRT index byte
;*
;*                 This registered subroutine is called whenever a
;*                 foreground VDM writes a byte to the CRT controller
;*                 index register (see VDHInstallIOHook for complete
;*                 semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 case VGA:
;*                   none
;*                 case OTHER:
;*                   update hardware
;*                   update CRT index value
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteCRTIndxFgnd
        OUTB    dx,al                       ;output CRT controller index
        FallInto VVWriteCRTIndxBgnd
EndProc   VVWriteCRTIndxFgnd

       ENDIF ;VGA


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteCRTIndxBgnd()
;*
;* DESCRIPTION   = Write CRT index byte
;*
;*                 This registered subroutine is called whenever a
;*                 background VDM writes a byte to the CRT controller
;*                 index register (see VDHInstallIOHook for complete
;*                 semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteCRTIndxBgnd
       IFNDEF VGA
        FallFrom VVWriteCRTIndxFgnd
       ENDIF

;/*
;**
;**     Although 3Bx and 3Dx are available on the EGA/VGA, we must
;**     emulate the true effect when the target port is invalid
;**     under the current mode.  For example, if the VDM is currently
;**     in MONO mode then all accesses to the 3Dx are invalid.
;**
;*/

       IFDEF EGAVGA                                                     ;          
        mov     cl,dl                       ;Get addr color bit         ;          
        shr     cl,6                        ;Shift to MISCOUT_COLRPORTS ;          
        xor     cl,[VDMData.regMiscOut]     ;Compare color bits         ;          
        and     cl,MISCOUT_COLRPORTS        ;access allowed?            ;          
        jnz     short wCRTIndxExit          ;no                         ;          
       ENDIF                                                            ;          
        mov     VDMData.regCRTIndx,al       ;stash CRT controller index

wCRTIndxExit:                                                           ;          
        ExitProc
EndProc   VVWriteCRTIndxBgnd


       IFNDEF VGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadCRTIndxFgndW()
;*
;* DESCRIPTION   = Read CRT index word
;*
;*                 This registered subroutine is called whenever a
;*                 foreground VDM reads a word from the CRT controller
;*                 index register (see VDHInstallIOHook for complete
;*                 semantics).
;*
;*                 Note that the only real purpose this routine serves
;*                 is to enhance operation on MONO/CGA/EGA adapters, which
;*                 are normally not readable. This provides applications
;*                 with a benefit of operating in V86-mode that should in
;*                 no way affect compatibility.
;*
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = AX  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadCRTIndxFgndW

;/*
;**
;**    Although 3Bx and 3Dx are available on the EGA/VGA, we must
;**    emulate the true effect when the target port is invalid
;**    under the current mode.  For example, if the VDM is currently
;**    in MONO mode then all accesses to the 3Dx are invalid.
;**
;*/

       IFDEF EGA                                                        ;          
        mov     cl,dl                       ;Get addr color bit         ;          
        shr     cl,6                        ;Shift to MISCOUT_COLRPORTS ;          
        xor     cl,[VDMData.regMiscOut]     ;Compare color bits         ;          
        and     cl,MISCOUT_COLRPORTS        ;access allowed?            ;          
        jz      short rCRTWord              ;yes                        ;          
        mov     ax,0FFFFh                   ;no, return emulated value  ;          
        ExitProc premature                                              ;          
rCRTWord:                                                               ;          
       ENDIF                                                            ;          

        mov     al,VDMData.regCRTIndx       ;get CRT controller index
        movzx   ecx,al                      ;form our own index
        cmp     cl,REG_CRTLPENHI            ;lightpen status register?
        je      short vvrifw_gethw          ;yes, read hardware directly
        cmp     cl,REG_CRTLPENLO            ;other lightpen status register?
        je      short vvrifw_gethw          ;yes, read hardware directly
       IFDEF TSENG
       IFDEF EGA
        cmp     cl,REG_TSENG_CRTLPEN2       ;yet another status register?
        je      short vvrifw_gethw          ;yes, read hardware directly
       ENDIF
       ENDIF

        and     cl,MAX_CRTREGS-1            ;don't over-index
        mov     ah,VDMData.aregCRTData[ecx] ;get indexed CRT data
        ExitProc premature

vvrifw_gethw:
        INB     ah,dx                       ;read data directly from hardware
        ExitProc
EndProc   VVReadCRTIndxFgndW

       ENDIF ;VGA


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteCRTIndxFgndW()
;*
;* DESCRIPTION   = Write CRT index word foreground
;*
;*                 This registered subroutine is called whenever a
;*                 foreground VDM writes a word to the CRT controller
;*                 index register (see VDHInstallIOHook for complete
;*                 semantics).
;*
;*
;* INPUT         = AX == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteCRTIndxFgndW
        OUTW    dx,ax                       ;output index+data
        FallInto VVWriteCRTIndxBgndW
EndProc   VVWriteCRTIndxFgndW


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteCRTIndxBgndW()
;*
;* DESCRIPTION   = Write CRT index word background
;*
;*                 This registered subroutine is called whenever a
;*                 background VDM writes a word to the CRT controller
;*                 index register (see VDHInstallIOHook for complete
;*                 semantics).
;*
;*
;* INPUT         =  AX == data to write
;*                  EBX -> VDM register frame
;*                  EDX == port number (PORT_MONOCRTINDX or PORT_COLRCRTINDX)
;*
;* OUTPUT        =  None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteCRTIndxBgndW


;/*
;**
;**    Although 3Bx and 3Dx are available on the EGA/VGA, we must
;**    emulate the true effect when the target port is invalid
;**    under the current mode.  For example, if the VDM is currently
;**    in MONO mode then all accesses to the 3Dx are invalid.
;**
;*/

       IFDEF EGAVGA                                                     ;          
        mov     cl,dl                       ;Get addr color bit         ;          
        shr     cl,6                        ;Shift to MISCOUT_COLRPORTS ;          
        xor     cl,[VDMData.regMiscOut]     ;Compare color bits         ;          
        and     cl,MISCOUT_COLRPORTS        ;access allowed?            ;          
        jnz     short wCRTWordExit          ;no                         ;          
       ENDIF                                                            ;          

        mov     VDMData.regCRTIndx,al       ;stash CRT controller index
        mov     al,ah                       ;Get parameters for
;       inc     edx                         ;for VVWriteCRTDataBgnd     ;          
;                                           ;Check trapregs for SVGA!   ;          
        jmp     short VVWriteCRTDataBgndAllowed ;Be highly consistent!  ;          
wCRTWordExit:                                                           ;          
EndProc   VVWriteCRTIndxBgndW


       IFNDEF VGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadCRTDataFgnd()
;*
;* DESCRIPTION   = Read CRT data byte
;*
;*                 This registered subroutine is called whenever a
;*                 foreground VDM reads a byte from the CRT controller
;*                 data register (see VDHInstallIOHook for complete
;*                 semantics).
;*
;*                 Note that the only real purpose this routine serves
;*                 is to enhance operation on MONO/CGA/EGA adapters, which
;*                 are normally not readable. This provides applications
;*                 with a benefit of operating in V86-mode that should in
;*                 no way affect compatibility.
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTDATA or PORT_COLRCRTDATA)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 case VGA:
;*                   none
;*                 case OTHER:
;*                   if REG_CRTLPENHI, REG_CRTLPENLO
;*                     return hardware
;*                   else
;*                     mask index with MAX_CRTREGS-1
;*                     index into CRT array, return value
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadCRTDataFgnd
        FallInto VVReadCRTDataBgnd
EndProc   VVReadCRTDataFgnd

       ENDIF ;VGA


;/***************************************************************************
;*
;* FUNCTION NAME = VVReadCRTDataBgnd()
;*
;* DESCRIPTION   = Read CRT data byte
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM reads a byte from the CRT controller data register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;*
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTDATA or PORT_COLRCRTDATA)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 if REG_CRTLPENHI, REG_CRTLPENLO
;*                   return simulated hardware value
;*                 else
;*                   mask index with MAX_CRTREGS-1
;*                   index into CRT array, return value
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadCRTDataBgnd
       IFNDEF VGA
        FallFrom VVReadCRTDataFgnd
       ENDIF

;/*
;**
;**     Although 3Bx and 3Dx are available on the EGA/VGA, we must
;**     emulate the true effect when the target port is invalid
;**     under the current mode.  For example, if the VDM is currently
;**     in MONO mode then all accesses to the 3Dx are invalid.
;**
;*/

       IFDEF EGAVGA                                                     ;          
        mov     cl,dl                       ;Get addr color bit         ;          
        shr     cl,6                        ;Shift to MISCOUT_COLRPORTS ;          
        xor     cl,[VDMData.regMiscOut]     ;Compare color bits         ;          
        and     cl,MISCOUT_COLRPORTS        ;access allowed?            ;          
        jz      short rCRTData              ;yes                        ;          
        mov     al,0FFh                     ;no, return emulated value  ;          
        ExitProc premature                                              ;          
rCRTData:                                                               ;          
       ENDIF                                                            ;          

        movzx   ecx,VDMData.regCRTIndx      ;get CRT controller index

;/*
;**
;**   Note: the VGA doesn't support a light-pen, so there's no need to special-
;**         case those registers for a VGA.  That's also why the gethw and getvirt
;**         sections (below) can be conditionally assembled.
;**
;*/

       IFNDEF VGA
        cmp     cl,REG_CRTLPENHI            ;lightpen status register?
        je      short vvrdb_gethw           ;yes, read (virtual) hardware
        cmp     cl,REG_CRTLPENLO            ;other lightpen status register?
        je      short vvrdb_gethw           ;yes, read (virtual) hardware
       ENDIF

       IFDEF TSENG
       IFDEF EGA
        cmp     cl,REG_TSENG_CRTLPEN2       ;yet another status register?
        je      short vvrdb_gethw           ;yes, read hardware directly
       ENDIF
       ENDIF

        and     cl,MAX_CRTREGS-1            ;don't over-index
        mov     al,VDMData.aregCRTData[ecx] ;get indexed CRT data
        ExitProc premature

       IFNDEF VGA
vvrdb_gethw:
        testb   VDMData.flVDMVideo,VDM_FGND
        jz      short vvrdb_getvirt
        INB     al,dx                       ;read data directly from hardware
        ExitProc premature

vvrdb_getvirt:
        mov     al,0                        ;return simulated hardware value
        ExitProc
       ENDIF
EndProc   VVReadCRTDataBgnd


       IFNDEF VGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteCRTDataFgnd()
;*
;* DESCRIPTION   = Write CRT data byte
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes a byte to the CRT controller data register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTDATA or PORT_COLRCRTDATA)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 case VGA:
;*                   none
;*                 case OTHER:
;*                   update hardware
;*                   mask index with MAX_CRTREGS-1
;*                   index into CRT array, update value
;*
;*
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteCRTDataFgnd
        OUTB    dx,al                       ;output CRT controller data
        FallInto VVWriteCRTDataBgnd
EndProc   VVWriteCRTDataFgnd

       ENDIF ;VGA


;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteCRTDataBgnd()
;*
;* DESCRIPTION   = Write CRT data byte
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes a byte to the CRT controller data register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_MONOCRTDATA or PORT_COLRCRTDATA)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 mask index with MAX_CRTREGS-1
;*                 index into CRT array, update value
;*
;**************************************************************************/

        DefData EXPORT,SWAPINST,C
        _BYTE   nFlips,0
        EndData
        align   4                                                       ;          
Procedure VVWriteCRTDataBgnd
       IFNDEF VGA
        FallFrom VVWriteCRTDataFgnd
       ENDIF

       IFDEF SYNCFLIP
        LocalVar flDirtyTemp,ULONG
        EnterProc
       ENDIF

;/*
;**
;**    Although 3Bx and 3Dx are available on the EGA/VGA, we must
;**    emulate the true effect when the target port is invalid
;**    under the current mode.  For example, if the VDM is currently
;**    in MONO mode then all accesses to the 3Dx are invalid.
;**
;*/

       IFDEF EGAVGA                                                     ;          
        mov     cl,dl                       ;Get addr color bit         ;          
        shr     cl,6                        ;Shift to MISCOUT_COLRPORTS ;          
        xor     cl,[VDMData.regMiscOut]     ;Compare color bits         ;          
        and     cl,MISCOUT_COLRPORTS        ;access allowed?            ;          
        jnz     vvwdb_exit                  ;no, no op access           ;          
       ENDIF                                                            ;          

VVWriteCRTDataBgndAllowed:                  ;Be highly consistent!      ;          
        movzx   ecx,VDMData.regCRTIndx      ;get CRT controller index
        and     cl,MAX_CRTREGS-1            ;don't over-index
       IFDEF SVGA
;/*
;** If the index is not part of the trap list, don't shadow it.
;** This will prevent BIOS and DOS applications from erroneously
;** modifying read-only registers in the backgroud.
;** It turns out cheaper to preserve original index by push/pop then to
;** implement anything else. The whole trap mask test costs 32 cycles.
;*/
;@V3.0YEE01 mov     edx, ecx                    ;                           ;          
;@V3.0YEE01 mov     ah, 1
;@V3.0YEE01 and     cl, 7                       ;get the modulo 8 into cl
;@V3.0YEE01 shl     ah, cl                      ;get the right bit offset into ah
;@V3.0YEE01 mov     ecx, edx                    ;get cx again               ;          
;@V3.0YEE01 shr     edx, 3                      ;get abCRTMask byte offset  ;          
;@V3.0YEE01 test    byte ptr abCRTMask[edx], ah ;set the 0 flag
;@V3.0YEE01 jz      vvwdb_exit                  ;if not in the trap list, just exit
        cmp     byte ptr abCRTMask[ecx], 000h ;set the 0 flag
        je      vvwdb_exit                  ;if not in the trap list, just exit
       ENDIF
        mov     ah,al                       ;save previous CRT data     ;          
        xchg    ah,VDMData.aregCRTData[ecx] ;stash the indexed CRT data ;          
;/*
;**
;**    Don't allow the VDM to clear CRTC registers 00h - 06h and
;**    0Fh - 18h because the changes will cause vvUpdateScreenState
;**    to record bogus information that may lead to Traps and Hangs
;**    in the PM Shield.
;**
;*/
        or      al,al                                                   ;          
        jnz     bwCRTSaveIt                                             ;          
        cmp     ecx,REG_CRTLINECMP              ;Index 18h              ;          
        ja      bwCRTSaveIt                                             ;          
        cmp     ecx,REG_CRTOVERFLOW             ;Index 07h              ;          
        jb      bwCRTSkipIt                                             ;          
        cmp     ecx,REG_CRTVERTSTRTRC           ;Index 10h              ;          
        jb      bwCRTSaveIt                                             ;          
        cmp     ecx,REG_CRTUNDLINELOC           ;Index 14h               76726
        je      bwCRTSaveIt                                             ;76726
bwCRTSkipIt:                                                            ;          
        mov     VDMData.aregCRTData[ecx],ah ;Disallow change            ;          
bwCRTSaveIt:                                                            ;          
;/*
;**
;**   Check for page flip or cursor change, and add window event if necessary
;**
;*/

        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jz      vvwdb_exit                                              ;          
        testb   VDMData.flVDMVideo,VDM_STATEINIT
        jz      vvwdb_exit                                              ;          

vvwdb_checklvb:
        cmp     cl,REG_CRTSTARTADDRHI
        mov     ch,01h
        je      short vvwdb_lvbupdate
        cmp     cl,REG_CRTSTARTADDRLO
;       mov     ch,02h                                                  ;B729786
        jne     short vvwdb_checkmode

vvwdb_lvbupdate:
        or      [nFlips],ch
        movzx   eax,word ptr VDMData.aregCRTData[REG_CRTSTARTADDRHI]
        or      eax,eax                     ;try to determine if a valid
        jz      short vvwdb_lvbreset        ;offset exists yet
        xchg    al,ah
        mov     ecx,2000                    ;a likely offset
        push    eax
        div     ecx
        pop     eax
        or      edx,edx                     ;any remainder?
        jz      short vvwdb_lvbreset        ;no, reset
        cmp     [nFlips],01h                ;STARTADDRHI changed?       ;B729786
        jne     short vvwdb_exit            ;no, I give up
vvwdb_lvbreset:
        mov     [nFlips],0

;/*
;**
;**   Call vvUpdateScreenState strictly to update offPhysVRAMVisible
;**
;*/

        CallFn  vvUpdateScreenState,<CURRENT_VDM, FALSE>

        or      VDMData.flVDMVideo,VDM_SHADOWINVALID
       IFNDEF SYNCFLIP
        or      VDMData.flDirtyPages,-1     ;let next timer update handle this
       ELSE
        SSToDS  eax,flDirtyTemp
        mov     dword ptr [eax],-1
        CallFn  vvAddEvent,<CURRENT_VDM, VVDEVENT_LVB, eax, 0>
       ENDIF
        jmp     short vvwdb_exit

vvwdb_checkmode:
        mov     [nFlips],0
        cmp     al,ah                       ;did app *change* or simply rewrite?
        je      short vvwdb_exit            ;did not change!

       IFDEF MONOCGA
        cmp     cl,REG_CRTVERTTOTAL
       ENDIF
       IFDEF EGAVGA
        cmp     cl,REG_CRTLINECMP
        je      short vvwdb_modeupdate
        cmp     cl,REG_CRTVERTDSPEND
        je      short vvwdb_modeupdate
        cmp     cl,REG_CRTMAXSCAN
       ENDIF
        jne     short vvwdb_checkcursor

vvwdb_modeupdate:
        CallFn  vvUpdateScreenState,<CURRENT_VDM, TRUE>
        jmp     short vvwdb_exit

vvwdb_checkcursor:
        cmp     cl,REG_CRTCURLOCHI
        je      short vvwdb_cursorupdate
        cmp     cl,REG_CRTCURLOCLO
        je      short vvwdb_cursorupdate
        cmp     cl,REG_CRTCURSTSCAN
        je      short vvwdb_cursorupdate
        cmp     cl,REG_CRTCURENDSCAN
        jne     short vvwdb_exit

vvwdb_cursorupdate:
        or      VDMData.PtrData.flPtrVideo,PTR_HWDIRTY
        CallFn  vvUpdateCursorData,<CURRENT_VDM>

vvwdb_exit:
        ExitProc
EndProc   VVWriteCRTDataBgnd


;/***************************************************************************
;*
;* FUNCTION NAME = vvUpdateCursorData()
;*
;* DESCRIPTION   = Return current cursor data
;*
;*
;* INPUT         = hvdm -> VDM
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvUpdateCursorData
        ArgVar  hvdm,HVDM

        EnterProc
        push    ebx
        push    edi

        mov     ebx,[hvdm]
        lea     edi,VDMData.vvCursor[ebx]
        mov     ax,word ptr VDMData.aregCRTData[REG_CRTCURLOCHI][ebx]
        xchg    al,ah
        mov     cx,word ptr VDMData.aregCRTData[REG_CRTSTARTADDRHI][ebx]
        xchg    cl,ch
        sub     ax,cx

;/*
;**
;**   Check the cursor location, because apps can program huge values into it
;**   (eg, when Lotus hides the cursor).  Anything larger than the current
;**   visible screen size gets mapped to the last visible byte + 1 here, to avoid
;**   any possibility of division overflow....
;**
;*/

        mov     [edi].vvc_fVisible,TRUE     ;assume cursor is visible
        mov     dx,word ptr VDMData.nbPhysVRAMVisible[ebx]
        shr     dx,1
        cmp     ax,dx
        jb      short vvqcd_ok
        mov     ax,dx
        mov     [edi].vvc_fVisible,FALSE    ;cursor is not visible

vvqcd_ok:
        movzx   ecx,VDMData.aregCRTData[REG_CRTHORZDSPEND][ebx]
       IFDEF EGAVGA
        inc     cl                          ;# of chars/row in EGA/VGA
       ENDIF                                ;register is 1 less than actual #
        mov     dx,ax                       ;begin check for division underflow
        sub     eax,eax
        jecxz   short vvqcd_skipdiv
        dec     eax                         ;AL == 0FFh
        mul     cl
        cmp     dx,ax
        ja      short vvqcd_divbad
        mov     ax,dx                       ;end check
vvqcd_divbad:
        div     cl
vvqcd_skipdiv:
        movzx   ecx,al                      ;AL == row #
        mov     [edi].vvc_row,ecx
        mov     cl,ah                       ;AH == column #
        mov     [edi].vvc_col,ecx
        mov     ax,word ptr VDMData.aregCRTData[REG_CRTCURSTSCAN][ebx]
        testb   VDMData.PtrData.flPtrVideo[ebx],PTR_HARDWARE
        jz      short vvqcd_nothwptr        ;hardware cursor not enabled
        testb   VDMData.PtrData.flPtrVideo[ebx],PTR_HWDIRTY
        jz      short vvqcd_invisible       ;cursor should not be seen in window
vvqcd_nothwptr:
        test    al,20h                      ;cursor-off bit set?
        jnz     short vvqcd_invisible       ;yes
        and     ax,1F1Fh
       IFDEF VGA
        cmp     al,ah                       ;start greater than end?
        ja      short vvqcd_invisible       ;yes (no split cursors on VGA)
       ENDIF
       IFDEF EGA
        dec     ah                          ;on IBM EGA, ending line is 1 less
       ENDIF
        mov     cl,VDMData.aregCRTData[REG_CRTMAXSCAN][ebx]
        and     cl,1Fh
        cmp     al,cl                       ;is start scan line > max scan line?
        ja      short vvqcd_invisible       ;yes, assume invisible
        cmp     ah,cl                       ;is end scan line > max scan line?
        jbe     short vvqcd_checkmode       ;no
        mov     ah,cl                       ;yes, so set to largest allowed value
vvqcd_checkmode:
        cmp     VDMData.mstateVideo[ebx],MEMORY_TEXT
        je      short vvqcd_exit
vvqcd_invisible:
        mov     [edi].vvc_fVisible,FALSE    ;cursor is not visible
vvqcd_exit:
        mov     cl,al                       ;AL == start scan #
        mov     [edi].vvc_ulScanStart,ecx
        mov     cl,ah                       ;AH == stop scan #
        mov     [edi].vvc_ulScanEnd,ecx
;                  VDMData.flVDMXVideo[ebx],VDMX_SYNCOUTPUT
;                  short vvqcd_done
        CallFn  vvAddEvent,<ebx, VVDEVENT_CURSOR, edi, 0>
vvqcd_done:
        pop     edi
        pop     ebx
        ExitProc

EndProc   vvUpdateCursorData

        EndCode     EXPORT,SWAP,PASCAL


        END
