;*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 GDC I/O Processing

;/*****************************************************************************
;*
;* SOURCE FILE NAME = VVGDCIO.ASM
;*
;* DESCRIPTIVE NAME = Virtual Video Device Driver GDC I/O Processing
;*
;*
;* VERSION      V2.0
;*
;* DATE         11/10/88
;*
;* DESCRIPTION  This module contains the VVD's GDC I/O handlers.
;*
;* FUNCTIONS    VVWriteGDC2Fgnd()         Write GDC Pos2 byte
;*              VVWriteGDC2Bgnd()         Write GDC Pos2 byte
;*              VVWriteGDC1Fgnd()         Write GDC Pos1 byte
;*              VVWriteGDC1Bgnd()         Write GDC Pos1 byte
;*              VVReadGDCIndxFgnd()       Read GDC index byte
;*              VVReadGDCIndxBgnd()       Read GDC index byte
;*              VVWriteGDCIndxFgnd()      Write GDC index byte
;*              VVWriteGDCIndxBgnd()      Write GDC index byte
;*              VVReadGDCIndxFgndW()      Read GDC index word
;*              VVWriteGDCIndxFgndW()     Write GDC index word
;*              VVReadGDCDataFgnd()       Read GDC data byte
;*              VVReadGDCDataBgnd()       Read GDC data byte
;*              VVWriteGDCDataFgnd()      Write GDC data byte
;*              VVWriteGDCDataBgnd()      Write GDC data byte
;*
;* 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.
;*
;*   02/27/92                     B733211 - Performance enhancement to 320x200
;*                                mode
;*
;*   10/15/92                     Background virtualisation for Western Digital
;*
;*   12/04/92                     Move reg shadowing before vvMapBank call - can
;*                                return when VDM is foreground if freeze occurs.
;*
;*   12/12/92                     GDC port trashed when VDM runs background.
;*   01/03/93                     Background virtualisation for Cirrus. GDC(9) bank reg.
;*   02/04/93                     Prevent GDCMode 256-color bit from being
;*                                toggled in bgnd, causes desktop flashing.
;*   10/05/94             97868   Don't re-enable the buffer if GDC touched is not memory related.
;*****************************************************************************/


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


        DefCode     EXPORT,SWAP,PASCAL

       IFDEF EGA
        DefFn       VVWriteGDC2Fgnd
        DefFn       VVWriteGDC2Bgnd
        DefFn       VVWriteGDC1Fgnd
        DefFn       VVWriteGDC1Bgnd
       ENDIF
       IFDEF EGA
        DefFn       VVReadGDCIndxFgnd
       ENDIF
       IFDEF EGAVGA
        DefFn       VVReadGDCIndxBgnd
       ENDIF
       IFDEF EGAVGA
        DefFn       VVWriteGDCIndxFgnd
        DefFn       VVWriteGDCIndxBgnd
       ENDIF
       IFDEF EGA
        DefFn       VVReadGDCIndxFgndW
        DefFn       VVWriteGDCIndxFgndW
       ENDIF
       IFDEF EGA
        DefFn       VVReadGDCDataFgnd
       ENDIF
       IFDEF EGAVGA
        DefFn       VVReadGDCDataBgnd
       ENDIF
       IFDEF EGAVGA
        DefFn       VVWriteGDCDataFgnd
        DefFn       VVWriteGDCDataBgnd
        DefFn       _vvWriteGDCDataFgnd
        DefFn       _vvWriteGDCDataBgnd
       ENDIF


        DefCode     IMPORT,SWAP,PASCAL
        DefFn       VVEnableBuffer
        DefFn       VVSpecialCaseIO
       IFDEF SVGA                                       ;          
        DefFn       vvMapBank                           ;          
       ENDIF                                            ;          
        EndCode

        DefCode     IMPORT,GLOBAL,PASCAL
        DefFn       vvShadowIndxBgnd
        DefFn       vvShadowDataBgnd
        EndCode

        DefData     IMPORT,SWAP,C
        PBYTE       pbGDCExtShadowIndx
        PRLE        prleGDCExtShadowData
       IFDEF SVGA
        PSADAPTERINFO   psCurAdapterInfo
       ENDIF
        EndData


       IFDEF EGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteGDC2Fgnd()
;*
;* DESCRIPTION   = Write GDC Pos2 byte
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes a byte to the GDC controller Position 2 register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_GDCPOS2)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 update hardware
;*                 update GDCPos2 value
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteGDC2Fgnd
        OUTB    dx,al                       ;output GDC position 2
        FallInto VVWriteGDC2Bgnd
EndProc   VVWriteGDC2Fgnd

       ENDIF ;EGA


       IFDEF EGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteGDC2Bgnd()
;*
;* DESCRIPTION   = Write GDC Pos2 byte
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes a byte to the GDC controller Position 2 register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_GDCPOS2)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteGDC2Bgnd
        FallFrom VVWriteGDC2Fgnd
        mov     VDMData.regGDCPos2,al       ;stash GDC position 2
        ExitProc
EndProc   VVWriteGDC2Bgnd

       ENDIF ;EGA


       IFDEF EGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteGDC1Fgnd()
;*
;* DESCRIPTION   = Write GDC Pos1 byte
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM writes a byte to the GDC controller Position 1 register (see
;*                 VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_GDCPOS1)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteGDC1Fgnd
        OUTB    dx,al                       ;output GDC position 1
        FallInto VVWriteGDC1Bgnd
EndProc   VVWriteGDC1Fgnd

       ENDIF ;EGA


       IFDEF EGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVWriteGDC1Bgnd()
;*
;* DESCRIPTION   = Write GDC Pos1 byte
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM writes a byte to the GDC controller Position 1 register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = AL == data to write
;*                 EBX -> VDM register frame
;*                 EDX == port number (PORT_GDCPOS1)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVWriteGDC1Bgnd
        FallFrom VVWriteGDC1Fgnd
        mov     VDMData.regGDCPos1,al       ;stash GDC position 1
        ExitProc
EndProc   VVWriteGDC1Bgnd

       ENDIF ;EGA


       IFDEF EGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadGDCIndxFgnd()
;*
;* DESCRIPTION   = Read GDC index byte
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a byte from the GDC controller index register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;*                 Note that the only real purpose this routine serves is to
;*                 enhance operation on 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_GDCINDX)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadGDCIndxFgnd
        FallInto VVReadGDCIndxBgnd
EndProc   VVReadGDCIndxFgnd

       ENDIF ;EGA


       IFDEF EGAVGA

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

        align   4                                                       ;          
Procedure VVReadGDCIndxBgnd
       IFDEF EGA
        FallFrom VVReadGDCIndxFgnd
       ENDIF
        mov     al,VDMData.regGDCIndx       ;return GDC controller index
        ExitProc
EndProc   VVReadGDCIndxBgnd

       ENDIF ;EGAVGA


       IFDEF EGAVGA

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

        align   4                                                       ;          
Procedure VVWriteGDCIndxFgnd
        OUTB    dx,al                       ;output GDC controller index
        FallInto VVWriteGDCIndxBgnd
EndProc   VVWriteGDCIndxFgnd

       ENDIF ;EGAVGA


       IFDEF EGAVGA

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

        align   4                                                       ;          
Procedure VVWriteGDCIndxBgnd
        FallFrom VVWriteGDCIndxFgnd
        mov     VDMData.regGDCIndx,al       ;stash GDC controller index

        test    VDMData.flVDMVideo,VDM_PHYSPAGE
        jz      short vvwi_exit

;/*
;**
;**   OK, the magic bit is set, so we have to drop into the magic code that
;**   allows reprogramming of specific bits of certain physical registers,
;**   as well as optional uninterruptible shadowing in external storage.
;**
;*/

        mov     ecx,pbGDCExtShadowIndx
        call    vvShadowIndxBgnd            ;shadow this register

vvwi_exit:
        ExitProc
EndProc   VVWriteGDCIndxBgnd

       ENDIF ;EGAVGA


       IFDEF EGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadGDCIndxFgndW()
;*
;* DESCRIPTION   = Read GDC index word
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a word from the GDC controller index register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;*                 Note that the only real purpose this routine serves is to
;*                 enhance operation on 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_GDCINDX)
;*
;* OUTPUT        = AX  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadGDCIndxFgndW
        mov     al,VDMData.regGDCIndx       ;get GDC controller index
        movzx   ecx,al                      ;form our own index
        and     cl,MAX_GDCREGS-1            ;don't over-index
        mov     ah,VDMData.aregGDCData[ecx] ;get indexed GDC data
        ExitProc
EndProc   VVReadGDCIndxFgndW

       ENDIF ;EGA


       IFDEF EGA

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

        align   4                                                       ;          
Procedure VVWriteGDCIndxFgndW
        OUTW    dx,ax                       ;output index+data
        mov     VDMData.regGDCIndx,al       ;stash GDC controller index
        movzx   ecx,al                      ;form our own index
        and     cl,MAX_GDCREGS-1            ;don't over-index (critical!)
        mov     VDMData.aregGDCData[ecx],ah ;stash indexed GDC data as well

;/*
;**
;**   If we're NOT in a graphics mode, then disable all video pages, in
;**   preparation for mode re-determination on the next page fault.  This
;**   allows us to distinguish between text modes and graphics modes that
;**   share the text address space (ie, CGA graphics modes).
;**
;*/

        cmp     VDMData.mstateVideo,MEMORY_GRFX
        jne     short vvwd_disableall
        ExitProc
EndProc   VVWriteGDCIndxFgndW

       ENDIF ;EGA
       IFDEF EGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadGDCDataFgnd()
;*
;* DESCRIPTION   = Read GDC data byte
;*
;*                 This registered subroutine is called whenever a foreground
;*                 VDM reads a byte from the GDC controller data register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;*                 Note that the only real purpose this routine serves is to
;*                 enhance operation on 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_GDCDATA)
;*
;* OUTPUT        =
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 case VGA:
;*                   none
;*                 case OTHER:
;*                   mask index with MAX_GDCREGS-1
;*                   index into GDC array, return value
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadGDCDataFgnd
        FallInto VVReadGDCDataBgnd
EndProc   VVReadGDCDataFgnd

       ENDIF ;EGA


       IFDEF EGAVGA

;/***************************************************************************
;*
;* FUNCTION NAME = VVReadGDCDataBgnd()
;*
;* DESCRIPTION   = Read GDC data byte
;*
;*                 This registered subroutine is called whenever a background
;*                 VDM reads a byte from the GDC controller data register
;*                 (see VDHInstallIOHook for complete semantics).
;*
;* INPUT         = EBX -> VDM register frame
;*                 EDX == port number (PORT_GDCDATA)
;*
;* OUTPUT        = AL  == data read
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*                 mask index with MAX_GDCREGS-1
;*                 index into GDC array, return value
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVReadGDCDataBgnd
       IFDEF EGA
        FallFrom VVReadGDCDataFgnd
       ENDIF
        movzx   ecx,VDMData.regGDCIndx      ;get GDC controller index
        and     cl,MAX_GDCREGS-1            ;don't over-index
        mov     al,VDMData.aregGDCData[ecx] ;get indexed GDC data
        ExitProc
EndProc   VVReadGDCDataBgnd

       ENDIF ;EGAVGA


       IFDEF EGAVGA

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

        align   4                                                       ;          
Procedure _vvWriteGDCDataFgnd               ;VVWriteGDCDataFgnd is inside...

;/*
;**
;**   Disable special UNKNOWNFAULT trapping
;**
;*/

        and     VDMData.flVDMVideo,NOT VDM_UNKNOWNFAULT
        push    eax                         ;save output data
       IFDEF VGA
        CallFn  VVSpecialCaseIO,<NULL, NULL>
       ENDIF

;/*
;**
;**   Redo all the page mappings (ie, get rid of any "don't care" stuff now)
;**
;*/

        CallFn  VVEnableBuffer,<TRUE, ebx>
        pop     eax                         ;restore output data
        jmp     short vvwd_shadow           ;continue with common processing

Entry     VVWriteGDCDataFgnd
        OUTB    dx,al                       ;output GDC controller data
                                            ;are we trapping for active change?
        test    VDMData.flVDMVideo,VDM_UNKNOWNFAULT
        jnz     short _vvWriteGDCDataFgnd   ;yes, do some special work first

vvwd_shadow:
        movzx   ecx,VDMData.regGDCIndx      ;get GDC controller index
IFDEF SVGA                                              ;          
        push    eax                                     ;          
        push    ebx
        push    ecx                                     ;          
        mov     ecx,[psCurAdapterInfo]
        push    eax
        call    [ecx].pfnSVGAWriteGDCDataFgnd
        pop     ecx                                     ;          
        pop     ebx
        pop     eax                                     ;          
ELSE
        and     cl,MAX_GDCREGS-1            ;don't over-index (critical!)
        mov     VDMData.aregGDCData[ecx],al ;stash the indexed GDC data
ENDIF                                                   ;          

;/*
;**
;**   If we're NOT in a graphics mode, then disable all video pages, in
;**   preparation for mode re-determination on the next page fault.  This
;**   allows us to distinguish between text modes and graphics modes that
;**   share the text address space (ie, CGA graphics modes).
;**
;*/

        cmp     VDMData.mstateVideo,MEMORY_GRFX
        jne     short vvwd_disableall
        test    VDMData.flVDMVideo,VDM_PHYSPAGE
        jz      short vvwd_exit

;/*
;**
;**   OK, the magic bit is set, so we have to drop into the magic code that
;**   allows reprogramming of specific bits of certain physical registers,
;**   as well as optional uninterruptible shadowing in external storage.
;**
;*/

        cmp     ecx,REG_GDCMODE             ;prevent flashes to the     ;          
        jne     short vvwd_cont             ;  Desktop                  ;          
        and     al,NOT (GDCMODE_ODDEVENBITS + GDCMODE_256COLOR)         ;          
vvwd_cont:                                                              ;          
        mov     ecx,prleGDCExtShadowData[ecx*4]
        jecxz   short vvwd_exit
        call    vvShadowDataBgnd
        jmp     short vvwd_exit

vvwd_disableall:
;This test was too broad. There is no need to reenable the buffer if VDM is
;only changing the read map select or color compare or any other non-memory map
;related register.           
;                  cmp     cl,REG_GDCBITMASK           ;known register?
;                  ja      short vvwd_exit             ;no, so don't fiddle with buffer
        cmp      cl,REG_GDCMODE                         ;memory related register?                       
        jz      short @F                               ;no, so don't fiddle with buffer           

        cmp      cl, REG_GDCMISC                         ;memory related register?                       
        jnz      short vvwd_exit                        ;no, so don't fiddle with buffer           

@@:
        CallFn  VVEnableBuffer,<FALSE, ebx>

vvwd_exit:
        ExitProc
EndProc   _vvWriteGDCDataFgnd

       ENDIF ;EGAVGA


       IFDEF EGAVGA

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

        align   4                                                       ;          
Procedure _vvWriteGDCDataBgnd               ;VVWriteGDCDataBgnd is inside...

;/*
;**
;**   Disable special UNKNOWNFAULT trapping
;**
;*/

        and     VDMData.flVDMVideo,NOT VDM_UNKNOWNFAULT

;/*
;**
;**   Redo all the page mappings (ie, get rid of any "don't care" stuff now)
;**
;*/

        push    eax                         ;save output data
        CallFn  VVEnableBuffer,<TRUE, ebx>
        pop     eax                         ;restore output data
        jmp     vvwd_shadow                 ;continue with common processing

Entry     VVWriteGDCDataBgnd
                                            ;are we trapping for active change?
        test    VDMData.flVDMVideo,VDM_UNKNOWNFAULT
        jnz     _vvWriteGDCDataBgnd         ;yes, do some special work first
        jmp     vvwd_shadow

EndProc   _vvWriteGDCDataBgnd

       ENDIF ;EGAVGA


        EndCode     EXPORT,SWAP,PASCAL


        DefCode     EXPORT,GLOBAL,PASCAL

        EndCode     EXPORT,GLOBAL,PASCAL


        END
