;*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
        NAME    VVINT10
        TITLE   Virtual Video Device Driver Int 10h Support

;/*****************************************************************************
;*
;* SOURCE FILE NAME = VVINT10.ASM
;*
;* DESCRIPTIVE NAME = Virtual Video Device Driver Int 10h Support
;*
;*
;* VERSION      V2.0
;*
;* DATE         12/26/88
;*
;* DESCRIPTION  This module defines the VVD entry point and provides
;*              routing to various other C entry points.
;*
;* FUNCTIONS
;*              vvInt10EGA() - Process Extended Int 10h EGA services
;*              vvInt10Scroll() - Shadow Scroll Int 10h calls
;*              vvInt10WriteString() - Process special WriteString Int 10h calls
;*              vvInt10FontSelect() - Shadow font loading
;*              vvInt10VGASaveRestore() - Shadow VGA Save/Restore Int 10h calls
;*              vvOutputVDMChar() - Process one of the many Int 10h call
;*              vvGetVDMOutputBase() - Get base output address in VDM address space
;*              vvGetSystemOutputBase - Get base output address in system address space
;*              vvFreeSystemOutputBase - Free base output address
;*              vvSetVDMCursor - Set VDM cursor location
;*              vvScrollVDMUp - Scroll up entire VDM screen
;*              vvGetVDMCursorOffset() - Compute offset from cursor row/col
;*              vvVerifyVDMEmulation() - Verify that VDM operation should be emulated
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*   12/26/88                     Created.
;*   03/06/91                     Clear hide cursor bit when emulation fails, B720674.
;*
;*   04/22/91                     XGA enhancements to control whether VGA should
;*                                save/restore the video state on a single XGA
;*                                configuration system (i.e. P75 or PS/2 with
;*                                monitor attached only to the XGA) where the
;*                                XGA boots up in VGA mode.
;*
;*   09/14/91                     Delete window syncronization references
;*                                (tag B726840).
;*
;*   02/15/92                     B733006 - Performance enhancement to copy routines
;*
;*   02/20/92                     SVGA additions
;*
;*   02/27/92                     B733211 - Performance enhancement to 320x200 mode
;*
;*   03/17/92                     B7728098 - Complete VDM codepage support
;*
;*   08/19/92                     26127 - Timming problem when handling ALT-HOME and
;*                                INT10 SCROLL event.
;*
;*   10/29/92                     55059 - Disallow char write to invalid cursor pos
;*   10/29/92                             VESA style mode detection.
;*
;*   11/03/92                     Background execution.
;*
;*   01/26/93                     060914 remove            above
;*                                  replace with ignoring character writes
;*                                  beyond C0000
;*   02/16/93                     61075 - Back out GRAPHICS.COM support (see TPL05)
;*   03/11/93                     Allow IO trapping off in full-screen VDM.
;*   09/17/94             D93589  Redefinition of VDM_V86MACHINE
;*****************************************************************************/


        .xlist
        include mvdm.inc
        include vddseg.inc
        include beep.inc
        .list
        DEBUG equ 1
        INCL_VIDEOPTR equ 1
        include vvd.inc
        include vvdp.inc
        include propname.inc


        DefData     EXPORT,SWAP,C
       IFDEF VDDSTRICT
        ULONG       nbVDMData,<size vdmdata_s>
       ENDIF

;/*
;**
;**    Property names.  Defined globally that only one instance exists,
;**    and in assembly rather than C so that we can guarantee the strings
;**    are packed.
;**
;*/

       IFDEF PROPERTIES
        SZ          szPropInt10Emulate,<PROP_NAME_INT10EMULATE,NULL>
        SZ          szPropRtrcEmulate,<PROP_NAME_RTRCEMULATE,NULL>
        SZ          szPropModeRestrict,<PROP_NAME_MODERESTRICT,NULL>
        SZ          szPropNoRestrict,<PROP_NAME_NORESTRICT,NULL>
        SZ          szPropCGARestrict,<PROP_NAME_CGARESTRICT,NULL>
        IFNDEF CGA
        SZ          szPropMONORestrict,<PROP_NAME_MONORESTRICT,NULL>
        .ERRNZ      ($-szPropMONORestrict) GT (szPropMONORestrict-szPropCGARestrict)
        ENDIF
        SZ          szPropEndRestrict,NULL
        SZ          szPropUpdateWindow,<PROP_NAME_UPDATEWINDOW,NULL>
        SZ          szPropInt2F,<PROP_NAME_INT2F,NULL>
        SZ          szPropOnDemandAlloc,<PROP_NAME_ONDEMAND,NULL>
        SZ          szVMBoot,<'#', VDMP_ORD_VMBOOT+'0', NULL>
        SZ          szDOSBgndExec,<PROP_NAME_BGND_EXEC, NULL>           ;          
        SZ          szPropIOTrap,<PROP_NAME_8514A_IOTRAP, NULL>         ;          
       ENDIF
        EndData


        DefData     IMPORT,SWAP,C
        ULONG       ulAdapter
        VMFUNC      vmfunc
        ULONG       TKSSBase            ;required for SSToDS macro
        EndData


        DefCode     IMPORT,SWAP,PASCAL
        DefFn       VDHPopInt
        DefFn       VDHPopRegs
        DefFn       VDHResetEventSem
        DefFn       VDHWaitEventSem
        DefFn       VDHRequestMutexSem
        DefFn       VDHReleaseMutexSem
        DefFn       VDHNotIdle
        DefFn       VDHDevBeep
        DefFn       VDHArmReturnHook

       IFDEF EGAVGA                                                     ;          
        DefFn       vvGetCodePageFont                                   ;          
       ENDIF                                                            ;          
        DefFn       vvInt10SetMode
        DefFn       vvUpdateAll
        DefFn       vvAddEvent
        DefFn       vvFlushEvent
        DefFn       vvCheckForDirtyLVB
        DefFn       VVWriteCRTIndxFgndW
        DefFn       VVWriteCRTIndxBgndW

       IFDEF CGA
        DefFn       vvDisableDisplay
        DefFn       vvEnableDisplay
       ENDIF
        EndCode

        DefCode     IMPORT,GLOBAL,PASCAL
       IFDEF CGA
        DefFn       vvPtrPutByte
        DefFn       vvPtrPutWord
       ENDIF
        EndCode

        DefData     IMPORT,SWAPINST,C
        ULONG       nFlips,0
        EndData


        DefCode     EXPORT,SWAP,PASCAL

        DefFn       VVInt10Hook
        DefFn       VVInt10Return


        VVOUT_NONE      equ     00h     ;no options
        VVOUT_ATTR      equ     01h     ;output character w/attribute
        VVOUT_CMD       equ     02h     ;process command chars (eg, CR, LF)
        VVOUT_PAGE      equ     04h     ;output to specified page
        VVOUT_COUNT     equ     08h     ;output character specified # times
        VVOUT_CURSOR    equ     10h     ;output at specified cursor position
        VVOUT_NOCURHW   equ     20h     ;inhibit update of cursor hardware


;/***************************************************************************
;*
;* FUNCTION NAME = VVInt10Hook()
;*
;* DESCRIPTION   = Process VDM Int 10h calls
;*
;*
;* INPUT         = EBX -> VDM register frame
;*
;* OUTPUT        = EMULATED
;*                     Carry clear
;*                 NOT EMULATED
;*                     Carry set (pass control to next VDD)
;*
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;* PSEUDO-CODE
;*
;*     if no ownership
;*       return
;*     if function is EGARI
;*       dispatch to EGARI worker
;*       return
;*     if function is SetMode
;*       dispatch to SetMode worker
;*       return
;*     if video software vector is not hooked
;*       if function is WrtTTY or WrtString
;*         emulate without Int 10h(s)
;*     else
;*       if function is WrtString and ROM unsupported
;*         emulate with Int 10h(s)
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVInt10Hook

;/*
;**
;**   If another adapter has taken responsibility for the hardware, get out
;**
;*/

        testb   VDMData.flVDMXVideo,VDMX_DEVOWNER
        jz      short vvh_donteatintshortz

        movzx   eax,[ebx].crf_eax.off
        mov     [nFlips],0              ;this is a "safety reset"

;/*
;**
;**   Next, in case of EGA/VGA, check for extended functions immediately
;**
;*/

       IFDEF EGAVGA
        cmp     ah,INT10_EGAFIRST       ;could be an extended Int 10h call?
        jb      short vvh_checkfunc     ;no
        cmp     ah,INT10_EGALAST        ;is an extended Int 10h call?
        ja      short vvh_checkfunc     ;no
        call    vvInt10EGA              ;handle extended INT 10h EGA/VGA call
        jmp     vvh_eatint              ;eat interrupt, since we handled it
       ENDIF

vvh_checkfunc:
        or      ah,ah                   ;is this a SetMode call?
        .ERRNZ  INT10_SETMODE
        jnz     short vvh_emulate1      ;no, check for other functions
vvh_callsetmode:
        CallFn  vvInt10SetMode,<ebx>
        cmp     eax,1                   ;map TRUE to carry clear, FALSE set
vvh_exitshort:
        jmp     vvh_exit

vvh_emulate1:
        IFDEF SVGA                      ;          
        cmp     ax, 6f05h               ;Video7 setmode
        jz      vvh_callsetmode         ; 
        cmp     ax, 4f02h               ;VESA setmode             
        jz      vvh_callsetmode         ; 
        ENDIF                           ;          
        testb   VDMData.flVDMXVideo,VDMX_ACTIVE
vvh_donteatintshortz:
        jz      vvh_donteatint          ;we are not the active display

        cmp     ah,INT10_WRITETTY
        jne     short vvh_emulate2
        mov     ah,VVOUT_CMD
        call    vvOutputVDMChar         ;perform WRITETTY emulation
        jmp     short vvh_exitshort

vvh_emulate2:
        cmp     ah,INT10_EGAWRITESTRING
        jne     short vvh_emulate3
        call    vvInt10WriteString      ;perform WRITESTRING emulation
        jmp     short vvh_exitshort

vvh_emulate3:
        cmp     ah,INT10_QUERYLPEN
        jne     vvh_emulate4
        testb   VDMData.flVDMXVideo,VDMX_DEVOWNER
        jz      vvh_donteatintshortz
        testb   VDMData.PtrData.flPtrVideo,PTR_LPENEM
        jz      short vvh_donteatintshortz

        PCall   vmfunc.vmfunc_pfnQueryStatus,<CURRENT_VDM, <FLAToffset VDMData.PtrData.vmstatVideo>>
        or      eax,eax                 ;return FALSE?
        jz      short vvh_donteatintshortz
        mov     eax,VDMData.PtrData.vmstatVideo.vmstat_flButtons
        sub     ah,ah
        and     al,BUTBIT_LEFT or BUTBIT_RIGHT
        cmp     al,BUTBIT_LEFT or BUTBIT_RIGHT
        jne     short vvh_emulate3a
        inc     ah
vvh_emulate3a:
        mov     [ebx].crf_eax.hi,ah
        mov     ecx,VDMData.PtrData.vmstatVideo.vmstat_x
        mov     edx,VDMData.PtrData.vmstatVideo.vmstat_y
        mov     eax,VDMData.PtrData.vmssVideo.vmss_ulCellHeight
        cmp     eax,1
        je      short vvh_emulate3b
        and     ecx,NOT (8-1)
        and     edx,NOT (8-1)
        jmp     short vvh_emulate3c
vvh_emulate3b:
       IFDEF CGA
        mov     al,8
       ELSE
        mov     al,VDMBase.rb_nVCharHeight.lo
        or      al,al                   ;NEVER RELY ON VDM DATA STRUCTURES
        jnz     short vvh_emulate3c
        inc     al
       ENDIF
vvh_emulate3c:
        mov     [ebx].crf_ebx.off,cx
        shr     ecx,3                   ;divide by default cell width (8)
        mov     [ebx].crf_edx.lo,cl
        push    edx
        xchg    eax,edx
        div     dl
        mov     [ebx].crf_edx.hi,al
        pop     edx

        cmp     VDMData.PtrData.vmssVideo.vmss_ulCellHeight,1
        jne     short vvh_emulate3d
        cmp     VDMData.PtrData.vmssVideo.vmss_ulHeight,200
        jbe     short vvh_emulate3d     ;set user's CH; otherwise, set CX
        mov     [ebx].crf_ecx.off,dx
        jmp     short vvh_eatintshort
vvh_emulate3d:
        mov     dl,8
        mul     dl
        mov     [ebx].crf_ecx.hi,al
vvh_eatintshort:
        jmp     short vvh_eatint

vvh_emulate4:
        cmp     ah,INT10_SETCURSORPOS
        jne     short vvh_emulate4a
        mov     ah,VVOUT_NONE
        movzx   edx,[ebx].crf_edx.off   ;EDX == row (DH) and column (DL)
        movzx   ecx,[ebx].crf_ebx.hi    ;ECX == video page (BH)
        call    vvSetVDMCursor
        jmp     short vvh_exit

vvh_emulate4a:
        cmp     ah,INT10_SCROLLUP
        jb      short vvh_donteatint
        cmp     ah,INT10_SCROLLDOWN
        ja      short vvh_emulate5
        call    vvInt10Scroll           ;initiate SCROLL shadowing
        jmp     short vvh_exit

vvh_emulate5:
        cmp     ah,INT10_WRITECHARATTR
        jb      short vvh_donteatint
        cmp     ah,INT10_WRITECHAR
        ja      short vvh_emulate6
        movzx   ecx,[ebx].crf_ecx.off
        movzx   edx,[ebx].crf_ebx.off
        push    ebx
        mov     ebx,edx
        setb    ah                      ;AH == VVOUT_ATTR as appropriate
        .ERRNZ  (VVOUT_ATTR ne 1)
        or      ah,VVOUT_PAGE or VVOUT_COUNT
        call    vvOutputVDMChar         ;perform WRITECHAR emulation
        pop     ebx
        jmp     short vvh_exit

vvh_emulate6:
        testb   VDMData.flVDMXVideo,%(VDMX_CGARESTRICT or VDMX_MONORESTRICT)
        jz      short vvh_emulate6a     ;no CGA/MONO restrictions
        cmp     ah,INT10_EGASETPALETTE  ;restriction in effect,     function?
        jae     short vvh_eatint        ;yes, so "eat" interrupt
vvh_emulate6a:

       IFDEF EGAVGA
        cmp     ah,INT10_EGASELECTFONT
        jne     short vvh_emulate7
        call    vvInt10FontSelect       ;initiate font shadowing
        jmp     short vvh_exit

vvh_emulate7:
        cmp     ah,INT10_VGASAVERESTORE
        jne     short vvh_donteatint
        call    vvInt10VGASaveRestore   ;initiate VGASAVERESTORE shadowing
       ELSE
        stc                             ;in the MONO case, make sure we don't
       ENDIF                            ;eat the interrupt

vvh_exit:
        jc      short vvh_donteatint2   ;jump to next VDD and/or ROM

vvh_eatint:
        CallFn  VDHPopInt               ;eat interrupt (don't chain to the ROM)
        clc                             ;don't chain to next VDD
        ExitProc premature

vvh_donteatint:
        stc
vvh_donteatint2:
        ExitProc
EndProc   VVInt10Hook


;/***************************************************************************
;*
;* FUNCTION NAME = VVInt10Return()
;*
;* DESCRIPTION   = End-of-processing for specific Int 10hs
;*
;*
;* INPUT         = pvvInt10s -> string info
;*                 pcrf      -> VDM register frame (unused)
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure VVInt10Return
        ArgVar  pvvInt10s,PVVINT10S                                     ;          
        ArgVar  pcrf,PCRF

;/*
;**
;**   FLAG:  -- Clean up these "special values" (use jump tables), and add
;**             another special case for page-flipping (also, disable the LVB
;**             event in vvcrtio.asm if a page-flip INT 10h is in progress)
;**
;*/

        EnterProc
        mov     eax,[pvvInt10s]         ;check for value denoting cursor change
        cmp     [eax].func_type,-INT10_SETCURSORTYPE                    ;          
        jne     short vvr_notsetcursor
        CallFn  VDHPopRegs,<<VDHREG_AX or VDHREG_CX or VDHREG_BP>>
        jmp     vvr_exit                                                ;          

vvr_notsetcursor:
       IFDEF EGAVGA                     ;check for value denoting font load
        cmp     [eax].func_type,-INT10_EGASELECTFONT                    ;          
        jne     short vvr_notfontload   ;no
        cmp     [eax].reg_ds,1                                          ;          
        jb      short vvr_updateAll                                     ;          

        ;*** restore EAX, ECX, EBP and ES registers ***                 ;          
        mov     ecx,[eax].reg_eax       ;restore VDM registers          ;          
        mov     [ebx].crf_eax,ecx                                       ;          
        mov     ecx,[eax].reg_ecx                                       ;          
        mov     [ebx].crf_ecx,ecx                                       ;          
        mov     ecx,[eax].reg_ebp                                       ;          
        mov     [ebx].crf_ebp,ecx                                       ;          
        mov     cx,[eax].reg_es                                         ;          
        mov     [ebx].crf_es,cx                                         ;          
        je      short vvr_updateAll     ;graphics font load used        ;          

        ;*** restore EBX and EDX used by user text font load ***        ;          
        mov     ecx,[eax].reg_ebx                                       ;          
        mov     [ebx].crf_ebx,ecx                                       ;          
        mov     ecx,[eax].reg_edx                                       ;          
        mov     [ebx].crf_edx,ecx                                       ;          

vvr_updateAll:                                                          ;          
        CallFn  vvUpdateAll,<CURRENT_VDM, TRUE>
        jmp     short vvr_exit

vvr_notfontload:                        ;check for value denoting save/restore
        cmp     [eax].func_type,-INT10_VGASAVERESTORE                   ;          
        jne     short vvr_notsave       ;no
        and     VDMData.flVDMVideo,NOT VDM_IGNOREFAULT
        jmp     short vvr_exit

vvr_notsave:
        cmp     [eax].func_type,-6Fh    ;special initialization test?   ;          
        jne     short vvr_notvideo7     ;no
        mov     eax,[pcrf]
        cmp     [eax].crf_ebx.off,5637h
        jne     short vvr_init
        mov     [ulAdapter],ADAPTER_VIDEO7
        jmp     short vvr_skipinit
vvr_init:
        and     VDMBase.rb_bVInfo,BIOSVINFO_NOEMULATE or BIOSVINFO_EGAMONO or \
                                  BIOSVINFO_WAITRETRC or BIOSVINFO_EGAINACTIVE or \
                                  BIOSVINFO_MEMMASK   or BIOSVINFO_DONTCLEAR

        and     VDMBase.rb_bVFlags,BIOSVFLAGS_VGAACTIVE or BIOSVFLAGS_GRAYSCALES or \
                                   BIOSVFLAGS_VGAMONO   or BIOSVFLAGS_NODEFPALETTE or \
                                   BIOSVFLAGS_DSPSWITCHING or BIOSVFLAGS_RESRVDLINES
vvr_skipinit:
        CallFn  VDHPopRegs,<<VDHREG_AX or VDHREG_BX>>
        jmp     short vvr_exit

vvr_notvideo7:
       ENDIF ;EGAVGA
                                        ;check for value denoting scroll
        cmp     [eax].func_type,-INT10_SCROLLUP                         ;          
        jne     short vvr_string        ;nope
        cmp     VDMData.mstateVideo,MEMORY_FONT
        ja      short vvr_string        ;in any case, it's a     idea for graphics
        CallFn  vvCheckForDirtyLVB,<CURRENT_VDM, EVENT_FLUSH>

vvr_string:

vvr_exit:
        mov     eax,[pvvInt10s]                                         ;          
        mov     [eax].func_type,0       ;return hook no longer in use   ;          
        ExitProc
EndProc   VVInt10Return


        EndCode     EXPORT,SWAP,PASCAL


        DefCode     PRIVATE,SWAP,PASCAL


       IFDEF EGAVGA

;/***************************************************************************
;*
;* FUNCTION NAME = vvInt10EGA()
;*
;* DESCRIPTION   = Process Extended Int 10h EGA services
;*
;*
;* INPUT         = AX  == VDM's AX register
;*                 EBX -> VDM register frame
;*
;* OUTPUT        = Varies
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvInt10EGA
        ExitProc
EndProc   vvInt10EGA

       ENDIF ;EGAVGA


;/***************************************************************************
;*
;* FUNCTION NAME = vvInt10Scroll()
;*
;* DESCRIPTION   = Shadow Scroll Int 10h calls
;*
;*
;* INPUT         = EAX == VDM's AX register
;*                 EBX -> VDM register frame
;*
;* OUTPUT        = EMULATED
;*                     Carry clear
;*                 NOT EMULATED
;*                     Carry set (pass control to next VDD and/or ROM)
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvInt10Scroll

;/*
;**
;**   First, check for the only scroll functions we currently emulate,
;**   which are single-line scroll-ups, starting from the top of the screen
;**
;*/

        call    vvVerifyVDMEmulation
        jc      short vvs_noemulate     ;emulation disabled or inappropriate

        cmp     ax,1+INT10_SCROLLUP*256 ;scroll up 1 line?
        jne     short vvs_noemulate     ;no

        cmp     [ebx].crf_ecx.off,0     ;upper-left corner == 0,0?
        jne     short vvs_noemulate

        movzx   edx,[ebx].crf_edx.off
        inc     edx
        cmp     dl,VDMBase.rb_nVCols.lo
        jne     short vvs_noemulate

        push    ebx
        push    esi
        push    edi
        mov     ah,[ebx].crf_ebx.hi     ;AH == attribute to use
        movzx   ecx,VDMBase.rb_bVPage   ;scroll active page
        call    vvGetVDMOutputBase      ;EDI -> VDM output address
        jc      short vvs_badscroll     ;target is outside legal domain
        call    vvGetSystemOutputBase   ;EBX -> system output address

        call    vvScrollVDMUp           ;do the scroll operation

        call    vvFreeSystemOutputBase  ;returns carry clear, too
vvs_badscroll:
        pop     edi
        pop     esi
        pop     ebx
        jc      short vvs_noemulate
        ExitProc premature

vvs_noemulate:
        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jz      short vvs_exit

        CallFn  vvFlushEvent,<CURRENT_VDM, VVDEVENT_STRING, 0>

        mov     eax,VDMData.pInt10ReturnData
        cmp     [eax].func_type,0                                       ;          
        jne     short vvs_exit          ;return hook still in use

        mov     [eax].func_type,-INT10_SCROLLUP                         ;          
        CallFn  VDHArmReturnHook,<VDMData.hhookInt10Return, VDHARH_NORMAL_IRET>

vvs_exit:
        stc                             ;we don't emulate these, only shadow
        ExitProc
EndProc   vvInt10Scroll


;/***************************************************************************
;*
;* FUNCTION NAME = vvInt10WriteString()
;*
;* DESCRIPTION   = Process special WriteString Int 10h calls
;*
;*                 This is essentially a private interface between CON driver
;*                 and virtual video driver.  It uses the WRITESTRING INT 10h
;*                 function code, but a private subfunction code (0FFh).
;*                 In general, the CON driver should only issue the call if
;*                 the INT 10h vector is unhooked;  otherwise, for
;*                 compatibility, it should use conventional INT 10h functions.
;*
;* INPUT         = EAX == VDM's AX register
;*                 EBX -> VDM register frame
;*
;* OUTPUT        = EMULATED
;*                     Carry clear
;*                     VDM's AL is zeroed on emulation failure
;*                 NOT EMULATED
;*                     Carry set (pass control to next VDD and/or ROM)
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvInt10WriteString
        mov     ah,VVOUT_CMD
        cmp     al,0FFh                 ;our special emulation request?
        je      short vvws_emulate      ;yes

        mov     ah,VVOUT_CMD OR VVOUT_ATTR OR VVOUT_PAGE OR VVOUT_CURSOR
        cmp     al,1                    ;write chars w/cursor motion?
        stc
        jne     short vvws_leave        ;no

;/*
;**
;**   VDM's ES:BP points to string
;**   VDM's CX contains string length
;**
;*/

vvws_emulate:
        push    esi
        push    ebx

        movzx   esi,[ebx].crf_es
        shl     esi,4
        movzx   edx,[ebx].crf_ebp.off
        add     esi,edx                 ;ESI -> string (same as ES:BP)
        movzx   ecx,[ebx].crf_ecx.off   ;ECX == count
        movzx   edx,[ebx].crf_edx.off   ;EDX == row (DH) and column (DL)
        movzx   ebx,[ebx].crf_ebx.off   ;EBX == page (BH) and attribute (BL)

        jecxz   short vvws_exit
        dec     ecx                     ;last character is special
        jecxz   short vvws_last
        or      ah,VVOUT_NOCURHW                                        ;          
        align   4                                                       ;          
vvws_loop:
        push    ecx
        lodsb
        call    vvOutputVDMChar         ;write 1 character
        pop     ecx
        jc      short vvws_error        ;emulation failed, so get out
        hploop  vvws_loop
vvws_last:
        lodsb
        and     ah,NOT VVOUT_NOCURHW
        call    vvOutputVDMChar         ;write the last character
        jnc     short vvws_exit

vvws_error:
        and     ah,NOT VVOUT_NOCURHW    ;clear hide hardware cursor bit ;          
        cmp     ah,VVOUT_CMD+1          ;force carry clear for funky INT 10h
        cmc
        jc      short vvws_exit
        pop     ebx
        mov     [ebx].crf_eax.lo,0      ;zero AL to indicate failure
        push    ebx

vvws_exit:
        pop     ebx
        pop     esi

vvws_leave:
        ExitProc
EndProc   vvInt10WriteString


       IFDEF EGAVGA

;/***************************************************************************
;*
;* FUNCTION NAME = vvInt10FontSelect()
;*
;* DESCRIPTION   = Shadow font loadin
;*
;*
;* INPUT         = EAX == VDM's AX register
;*                 EBX -> VDM register frame
;*
;* OUTPUT        = EMULATED
;*                     Carry clear
;*                 NOT EMULATED
;*                     Carry set (pass control to next VDD and/or ROM)
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvInt10FontSelect

        cmp     al,30h                  ;is this just a "information" call?
        je      vvf_exit                ;yes, ignore                    ;          

        SaveReg <esi,edi>                                               ;          
        sub     edx,edx                 ;didn't shadow VDM regs         ;          
        ;*** skip codepage check for any user font loads ***            ;          
        cmp     al,00h                                                  ;          
        je      vvf_shadow                                              ;          
        cmp     al,10h                                                  ;          
        je      vvf_shadow                                              ;          
        cmp     al,20h                                                  ;          
        je      vvf_shadow                                              ;          
        cmp     al,21h                                                  ;          
        je      vvf_shadow                                              ;          
                                                                        ;          
        ;*** skip VM BOOT guys ***                                      ;          
        test    VDMData.flVDMX2Video,VDMX2_V86MACHINE                   ;          
        jnz     vvf_shadow                                              ;          
                                                                        ;          
        ;*** skip if Codepage is disabled ***                           ;          
        cmp     VDMData.vvMode.vvm_cpID,00h                             ;          
        je      vvf_shadow                                              ;          
                                                                        ;          
        ;*** skip if Codepage buffer is NULL ***                        ;          
        cmp     VDMData.pCPBuff,00h                                     ;          
        je      vvf_shadow                                              ;          
                                                                        ;          
        ;*** setup the VDM codepage buffer based on font size ***       ;          
        mov     esi,8                   ;use 8x8 font                   ;          
        cmp     al,02h                  ;8x8 text?                      ;          
        je      short vvf_get_text                                      ;          
        cmp     al,12h                  ;8x8 text with CRTC changes?    ;          
        je      short vvf_get_text                                      ;          
        cmp     al,23h                  ;8x8 graphics?                  ;          
        je      short vvf_get_graphics                                  ;          
                                                                        ;          
        mov     esi,14                  ;use 8x14 font                  ;          
        cmp     al,01h                  ;8x14 text?                     ;          
        je      short vvf_get_text                                      ;          
        cmp     al,11h                  ;8x14 text with CRTC changes?   ;          
        je      short vvf_get_text                                      ;          
        cmp     al,22h                  ;8x14 graphics?                 ;          
        je      short vvf_get_graphics                                  ;          
                                                                        ;          
        mov     esi,16                  ;use 8x16 font                  ;          
        cmp     al,04h                  ;8x16 text?                     ;          
        je      short vvf_get_text                                      ;          
        cmp     al,14h                  ;8x16 text with CRTC changes?   ;          
        je      short vvf_get_text                                      ;          
        cmp     al,24h                  ;8x16 graphics?                 ;          
        jne     vvf_shadow              ;shadow the rest!               ;          
                                                                        ;          
vvf_get_graphics:                                                       ;          
        SaveReg    <eax>                                                ;          
        CallFn  vvGetCodePageFont <8, esi, VDMData.pCPBuff>             ;          
        sub     edx,edx                                                 ;          
        or      eax,eax                                                 ;          
        RestoreReg <eax>                                                ;          
        jz      vvf_shadow              ;failed to load codepage font   ;          
                                                                        ;          
        mov     edi,VDMData.pInt10ReturnData                            ;          
        mov     edx,[ebx].crf_eax                                       ;          
        mov     [edi].reg_eax,edx       ;save VDM's EAX                 ;          

        mov     edx,[ebx].crf_ecx                                       ;          
        mov     [edi].reg_ecx,edx       ;save VDM's ECX                 ;          

        ;*** convert ROM font load to user font load ***                ;          
        mov     byte ptr [ebx].crf_eax.off,21h  ;Use graphics font load ;          
        mov     [ebx].crf_ecx,esi       ;bytes per character            ;          

        inc     edx                     ;indicate graphics font load    ;          
        jmp     short vvf_setup_cpbuff                                  ;          
vvf_get_text:                                                           ;          
        SaveReg    <eax>                                                ;          
        CallFn  vvGetCodePageFont <8, esi, VDMData.pCPBuff>             ;          
        sub     edx,edx                                                 ;          
        or      eax,eax                                                 ;          
        RestoreReg <eax>                                                ;          
        jz      vvf_shadow              ;failed to load codepage font   ;          
                                                                        ;          
        mov     edi,VDMData.pInt10ReturnData                            ;          
        mov     edx,[ebx].crf_eax                                       ;          
        mov     [edi].reg_eax,edx       ;save VDM's EAX                 ;          

        ;*** setup AX for text user font load ***                       ;          
        and     [ebx].crf_eax.off,0FFF0h;convert to user font load      ;          

        mov     edx,[ebx].crf_ebx                                       ;          
        mov     [edi].reg_ebx,edx       ;save VDM's EBX                 ;          

        mov     ecx,esi                 ;                               ;          
        mov     dh,cl                   ;setup VDM BH with              ;          
        mov     [ebx].crf_ebx,edx       ;  # of bytes per character     ;          

        mov     edx,[ebx].crf_ecx       ;                               ;          
        mov     [edi].crf_ecx,edx       ;save VDM's ECX                 ;          

        mov     [ebx].crf_ecx.off,256   ;# of characters                ;          

        mov     edx,[ebx].crf_edx       ;                               ;          
        mov     [edi].crf_edx,edx       ;save VDM's EDX                 ;          

        mov     [ebx].crf_edx.off,0     ;character table offset         ;          
        mov     edx,2                   ;indicate text font load        ;          

vvf_setup_cpbuff:                       ;ECX = # of bytes per char      ;          
        mov     cx,[ebx].crf_es         ;                               ;          
        mov     [edi].reg_es,cx         ;save VDM's ES                  ;          
        mov     ecx,[ebx].crf_ebp       ;                               ;          
        mov     [edi].reg_ebp,ecx       ;save VDM's BP                  ;          

        mov     eax,VDMData.pCPBuff     ;                               ;          
        mov     ecx,eax                 ;use CX for offset              ;          
        shr     eax,4                   ;convert to segment from flat   ;          
        mov     [ebx].crf_es,ax         ;                               ;          
        and     ecx,0000000Fh           ;convert to offset              ;          
        mov     [ebx].crf_ebp.off,cx    ;                               ;          
;                                                                       ;          
;       cmp     edx,1                   ;graphics font load?            ;          
;       jne     vvf_shadow              ;no                             ;          
;
;       ;*** see if INT 1F is hooked by a TSR like GRAPHTBL.COM ***     ;          
;       mov     ecx,VDMBase.rb_avpIVT[BIOSINT_VIDEOGRAPH]               ;          
;       shr     ecx,16                  ;get selector                   ;          
;       cmp     ax,cx                   ;we took INT 1F?                ;          
;       je      short vvf_cal_1f_offset ;yes                            ;          
;       cmp     cx,VDMData.ROMint1fSeg  ;someone hooked INT 1F?         ;          
;       jne     vvf_shadow              ;yes                            ;          
;
;vvf_cal_1f_offset:                     ;                               ;          
;       shl     eax,16                  ;put Segment into high word     ;          
;       mov     ecx,esi                 ;recall point size              ;          
;       imul    ecx,ecx,128             ;calculate 128th char offset    ;          
;       mov     ax,cx                   ;                               ;          
;       mov     VDMBase.rb_avpIVT[BIOSINT_VIDEOGRAPH],eax               ;          

vvf_shadow:                             ;                               ;          
        RestoreReg <edi,esi>                                            ;          
        mov     eax,VDMData.pInt10ReturnData
        cmp     [eax].func_type,0                                       ;          
        jne     short vvf_exit          ;return hook still in use

        mov     [eax].reg_ds,dx         ;use to restore original regs   ;          
        mov     [eax].func_type,-INT10_EGASELECTFONT                    ;          
        CallFn  VDHArmReturnHook,<VDMData.hhookInt10Return, VDHARH_NORMAL_IRET>

vvf_exit:
        stc                             ;we don't emulate these, only shadow
        ExitProc
EndProc   vvInt10FontSelect

       ENDIF ;EGAVGA


       IFDEF EGAVGA

;/***************************************************************************
;*
;* FUNCTION NAME = vvInt10VGASaveRestore()
;*
;* DESCRIPTION   = Shadow VGA Save/Restore Int 10h calls
;*
;*
;* INPUT         = EAX == VDM's AX register
;*                 EBX -> VDM register frame
;*
;* OUTPUT        = EMULATED
;*                     Carry clear
;*                 NOT EMULATED
;*                     Carry set (pass control to next VDD and/or ROM)
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvInt10VGASaveRestore
        mov     eax,VDMData.pInt10ReturnData
        cmp     [eax].func_type,0                                       ;          
        jne     short vvsr_exit         ;return hook still in use

        or      VDMData.flVDMVideo,VDM_IGNOREFAULT

        mov     [eax].func_type,-INT10_VGASAVERESTORE                   ;          
        CallFn  VDHArmReturnHook,<VDMData.hhookInt10Return, VDHARH_NORMAL_IRET>

vvsr_exit:
        stc                             ;we don't emulate these, only shadow
        ExitProc
EndProc   vvInt10VGASaveRestore

       ENDIF ;EGAVGA


;/***************************************************************************
;*
;* FUNCTION NAME = vvOutputVDMChar()
;*
;* DESCRIPTION   = Process one of the many Int 10h call
;*
;*
;* INPUT         = AL  == character
;*                 AH  == function bits (see VVOUT_ constants)
;*                 BL  == attribute (ignored if VVOUT_ATTR not specified)
;*                 BH  == video page (forced to active page if VVOUT_PAGE not specified)
;*                 ECX == # characters (forced to 1 if VVOUT_COUNT not specified)
;*                 EDX == cursor row (DH) and column (DL) (only if VVOUT_CURSOR specified)
;*
;* OUTPUT        = EMULATED
;*                     Carry clear
;*                 NOT EMULATED
;*                     Carry set (pass control to next VDD and/or ROM)
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
OutTbl  dd      FLAToffset VVWriteCRTIndxBgndW
        dd      FLAToffset VVWriteCRTIndxFgndW
Procedure vvOutputVDMChar
        LocalVar charfunc,DWORD
        LocalVar attrpage,DWORD
        LocalVar count,DWORD
        LocalVar nChanges,DWORD
        LocalVar vva,VVSTRING

        char    equ <charfunc.lo>
        func    equ <charfunc.hi>
        attr    equ <attrpage.lo>
        vpage   equ <attrpage.hi>


        call    vvVerifyVDMEmulation
        jnc     short vvoc_enter        ;emulation may proceed
        ret

vvoc_enter:
        EnterProc
        push    eax                     ;save registers
        push    ebx
        push    esi
        push    edi

        test    ah,VVOUT_PAGE
        jnz     short vvoc_gotpage
        mov     bh,VDMBase.rb_bVPage
vvoc_gotpage:
        and     bh,7                    ;keep page in range (0-7)
        test    ah,VVOUT_COUNT
        jnz     short vvoc_gotcount
        sub     ecx,ecx
        inc     ecx
vvoc_gotcount:
        test    ah,VVOUT_CURSOR
        jnz     short vvoc_gotcursor
        movzx   edx,bh                  ;EDX == page #
        movzx   edx,VDMBase.rb_awVCursorPos[edx*2]
vvoc_gotcursor:
        or      ecx,ecx                 ;non-zero output count?
        jz      short vvoc_emulatedshort;no, leave

; caused defect #060914. fix replaced by           
;        cmp     dh,VDMBase.rb_nVRows      ;valid screen position?                 
;        ja      short vvoc_emulatedshort  ;leave if too big                       
;        cmp     dl,VDMBase.rb_nVCols.lo   ;valid screen position?                 
;        jae     short vvoc_emulatedshort  ;leave if too big                       

        movzx   edi,dh
        dec     edi                     ;EDI == new row-1
        cmp     edi,VDMData.vvStringEvent.vva_row
        jne     short vvoc_notvertical  ;not a row advance
        cmp     dl,VDMData.vvStringEvent.vva_col.lo
        jne     short vvoc_notvertical
        cmp     ecx,1                   ;is this single-character output?
        jne     short vvoc_notvertical  ;no
        cmp     cl,VDMData.vvStringEvent.vva_nChars.lo
        stc
        je      vvoc_exit               ;don't emulate "vertical" output

vvoc_notvertical:
        mov     [charfunc],eax
        mov     [attrpage],ebx
        mov     [count],ecx
        and     ah,VVOUT_CMD
        movzx   ecx,bh                  ;ECX == destination page #

        cmp     ax,BELL+VVOUT_CMD*256   ;bell?
        jne     short vvoc_notbell      ;no

        CallFn  VDHDevBeep,<BELL_FREQ, BELL_DURATION>
vvoc_emulatedshort:
        jmp     vvoc_emulated           ;we're all done

vvoc_notbell:
        cmp     ax,CR+VVOUT_CMD*256     ;CR?
        je      vvoc_cr                 ;yes

        cmp     ax,BS+VVOUT_CMD*256     ;Backspace?
        je      vvoc_bs                 ;yes

        call    vvGetVDMOutputBase      ;EDI -> VDM output address
        jc      vvoc_exit               ;target is outside legal domain

        call    vvGetSystemOutputBase   ;EBX -> system output address

        cmp     ax,LF+VVOUT_CMD*256     ;LF?
        je      vvoc_lf                 ;yes

        call    vvGetVDMCursorOffset    ;ESI == current cursor offset
        add     esi,esi                 ;convert to byte offset

; fix for defect #060914 and replacement for defect 055059
        testb   VDMData.flVDMVideo,VDM_WINDOWED                         ;          
        jz      short vvoc_dontcheck    ; don't check if fullscreen     ;          
        mov     ecx,esi                 ; = byte offset of character    ;          
        add     ecx,edi                 ; = B0000 or B8000              ;          
        cmp     ecx,0C0000h             ; if write is beyond C0000      ;          
        jge     short vvoc_emulatedshort;    then leave                 ;          

vvoc_dontcheck:                                                         ;          
        mov     ah,[attr]               ;AH == attribute
        mov     ecx,[count]             ;ECX == count (we know it's non-zero)
        mov     [nChanges],0
        push    edx
        align   4                                                       ;          
vvoc_writeloop:
       IFDEF CGA
        testb   VDMData.flVDMVideo,VDM_FGND
        jz      short vvoc_nowait

;/*
;**
;**   I'm defining a side-effect of disabling Video Retrace Emulation on CGAs
;**   to be that no wait-for-retrace be performed here.  Because we don't trap
;**   the status register on the CGA during foreground operation, this is really
;**   the only effect the property has for foreground VDMs anyway.
;**
;*/

        testb   VDMData.flVDMXVideo,VDMX_RTRCEMULATE
        jz      short vvoc_nowait
        testb   [func],VVOUT_ATTR
        jnz     short vvoc_putword
        call    vvPtrPutByte            ;wait for retrace, write char
        jmp     short vvoc_writenext
vvoc_putword:
        push    ecx
        sub     ecx,ecx
        call    vvPtrPutWord            ;wait for retrace, write char/attr
        pop     ecx
        jmp     short vvoc_writenext
       ENDIF ;CGA

vvoc_nowait:
        testb   [func],VVOUT_ATTR
        jnz     short vvoc_writeword
        mov     dl,[edi+esi]            ;READ through VDM
        cmp     dl,al                   ;any change?
        je      short vvoc_writenext    ;no
        inc     [nChanges]
        mov     [ebx+esi],al            ;WRITE the character
        jmp     short vvoc_writenext
vvoc_writeword:
        mov     dx,[edi+esi]            ;READ through VDM
        cmp     dx,ax                   ;any change?
        je      short vvoc_writenext    ;no
        inc     [nChanges]
        mov     [ebx+esi],ax            ;WRITE the character/attribute

vvoc_writenext:
        add     esi,2
        hploop  vvoc_writeloop          ;continue until count exhausted
        pop     edx

        push    edx
        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jz      short vvoc_notwindowed
        cmp     [nChanges],ecx          ;any changes? (ECX is zero)
        je      short vvoc_notwindowed  ;no, so pretend nothing happened
        movzx   eax,dh
        mov     [vva].vva_row,eax       ;row of string
        mov     al,dl
        mov     [vva].vva_col,eax       ;column of string
        mov     eax,[count]
        mov     [vva].vva_nChars,eax    ;length
        SSToDS  eax,[vva]
        CallFn  vvAddEvent,<CURRENT_VDM, VVDEVENT_STRING, eax, 0>

vvoc_notwindowed:
        testb   [func],VVOUT_NOCURHW    ;should we post activity?
        jnz     short vvoc_printed      ;no
        CallFn  VDHNotIdle              ; 

vvoc_printed:
        pop     edx
        testb   [func],VVOUT_CMD        ;must we bother with the rest of this?
        jz      short vvoc_emulated     ;no, we can leave now

        inc     dl                      ;bump the column
        cmp     dl,VDMBase.rb_nVCols.lo
        jb      short vvoc_setcur
        sub     dl,dl                   ;reset the column

vvoc_lf:

;/*
;**
;**   FLAG: 05-Jun-90
;**
;**   Does VDMBase.rb_nVRows get properly set on CGA systems?  If so, then
;**   the EGAVGA presence test in vvinit.c is somewhat bogus.  If not, then
;**   this code wouldn't work....
;**
;*/

        inc     dh
        cmp     dh,VDMBase.rb_nVRows    ;at maximum rows yet?
        jbe     short vvoc_setcur       ;no
        mov     dh,VDMBase.rb_nVRows    ;yes; insure that DH stays valid

        call    vvGetVDMCursorOffset    ;ESI == new cursor offset
        mov     ah,[edi+esi*2+1]        ;get fill attribute

        call    vvScrollVDMUp           ;do the scroll
        jmp     short vvoc_setcur

vvoc_cr:
        sub     dl,dl                   ;zero the column, and reset the cursor
        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jz      short vvoc_setcur
        push    edx
        CallFn  vvFlushEvent,<CURRENT_VDM, VVDEVENT_STRING, 0>
        pop     edx
        jmp     short vvoc_setcur

vvoc_bs:
        or      dl,dl                   ;already at beginning of line?
        jz      short vvoc_emulated     ;yes
        dec     dl

vvoc_setcur:
        mov     ah,[func]
        movzx   ecx,[vpage]             ;ECX == destination page #
        call    vvSetVDMCursor          ;set the cursor as appropriate

vvoc_emulated:
        call    vvFreeSystemOutputBase  ;returns carry clear, too

vvoc_exit:
        pop     edi
        pop     esi
        pop     ebx
        pop     eax
        ExitProc
EndProc   vvOutputVDMChar


;/***************************************************************************
;*
;* FUNCTION NAME = vvGetVDMOutputBase()
;*
;* DESCRIPTION   = Get base output address in VDM address space
;*
;*
;* INPUT         = ECX == current video page #
;*
;* OUTPUT        = EDI -> base output address in VDM
;*                 Carry set if destination is bad, clear otherwise
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvGetVDMOutputBase
        push    eax
        mov     edi,CGAMEM_START        ;default to B8000h
        mov     al,VDMBase.rb_fsEquip.lo
        and     al,BIOSEQUIP_VIDEOMASK
        cmp     al,BIOSEQUIP_MONOVIDEO
        jne     short vvgv_color
        mov     edi,MONOMEM_START       ;no, should use B0000h

vvgv_color:
        movzx   eax,VDMBase.rb_wVLen    ;get video page size
        imul    eax,ecx                 ;EAX == video page offset
        add     edi,eax                 ;EDI == video page address
        pop     eax
        cmp     edi,VRAM_START + VRAM_LEN
        cmc
        ExitProc
EndProc   vvGetVDMOutputBase


;/***************************************************************************
;*
;* FUNCTION NAME = vvGetSystemOutputBase
;*
;* DESCRIPTION   = Get base output address in system address space
;*
;*
;* INPUT         = EDI -> base output address in VDM
;*
;* OUTPUT        = EBX -> base output address in system
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvGetSystemOutputBase
        push    eax
        mov     ebx,edi                 ;prime to same value as EDI

        orb     VDMData.flVDMXVideo,VDMX_VDDFAULT

        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jz      short vvgs_writethru

; Beginning of windowed memory optimization

        orb     VDMData.flVDMXVideo,VDMX_WDWSEMREQ
        push    edx
;                  See comments below
;                  CallFn  VDHRequestMutexSem,<VDMData.hmxWindowedState, SEM_INDEFINITE_WAIT>
        pop     edx
        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jnz     short vvgs_cont
        clrb    VDMData.flVDMXVideo,VDMX_WDWSEMREQ
        jmp     short vvgs_writethru    ;hmm, we must have been preempted

vvgs_cont:
        cmp     VDMData.mstateVideo,MEMORY_TEXT
        jne     short vvgs_writethru    ;hmm, internal/external state mismatch?


        mov     eax,edi
        sub     eax,VDMData.pvdmPhysVRAMActive
        shr     eax,12                  ;convert offset to page #
        cmp     eax,8                   ;text modes only have 8 pages...
        jae     short vvgs_writethru    ;page # out of range

;/*
;**
;**   I have determined that this is a background VDM in text mode, which is
;**   writing to a page within the supported virtual address space.  Therefore,
;**   we modify EBX to point to a corresponding location within system
;**   address space, and use that to write into the VDM's video buffer, thereby
;**   leaving the dirty-page bits for the VDM untouched, and avoiding spurious
;**   LVB updates (the goal: better windowed performance).
;**
;**   Note that the particular page(s) we want to write in the virtual buffer
;**   may not be mapped into the VDM yet, or worse, may not even be allocated yet.
;**   But... all I have to do is read from the corresponding location in the
;**   VDM, and if the page isn't validated yet, a page fault will occur which will
;**   insure the virtual page in question is both valid and mapped in.  Note the
;**   read won't dirty the VDM page(s) either, which is why I chose the method.
;**
;**   Note that I have to take a semaphore that insures the page states won't
;**   change out from under me (since we *are* preemptible), and hmxWindowedState
;**   does this by blocking any Shell requests to change this VDM from WINDOWED to
;**   NONWINDOWED (or even vice versa, though that's not the concern here).
;**             
;**              NOT ANYMORE!!!!!!!!!!!!!!  I have found no use for it here.
;**              Besides, the alternative is worse, i.e., that occassionally we'll
;**              grab that semaphore and lockout vvSysSetAccess, preventing it from
;**              progressing to the point where it calls vvFlushEventNotify in order
;**              to post the hevShieldSynced semaphore which vvFlushEvent is waiting
;**              on.  The result is a System Deadlock, refer to Defect 26127.
;**
;**   I want to be just as smart about scrolling, so I READ from the VDM but write
;**   to the virtual buffer directly.  Again, reading from the VDM insures that
;**   the writes to the virtual buffer will succeed;  all we have to worry about
;**   is the scrolling of the first line, as that's the only line we don't normally
;**   read during a scroll, hence the "priming" read (as flagged below).
;**
;*/

        mov     eax,VDMData.apPlane[BANK0][PLANE0]                      ;          
        or      eax,eax                 ;do we have a buffer at all?
        jz      short vvgs_writethru    ;no, so we better just write-through
        add     eax,edi
        sub     eax,VDMData.pvdmPhysVRAMActive
        mov     ebx,eax

vvgs_writethru:
        pop     eax
        ExitProc
EndProc   vvGetSystemOutputBase


;/***************************************************************************
;*
;* FUNCTION NAME = vvFreeSystemOutputBase
;*
;* DESCRIPTION   = Free base output address
;*
;*
;* INPUT         = None
;*
;* OUTPUT        = Carry clear
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvFreeSystemOutputBase
        btrx    VDMData.flVDMXVideo,VDMX_WDWSEMREQ
;                  jnc     short vvfs_exit

;                  push    edx
;          
;                  No need to Release it if we no longer Request it.
;          
;                  CallFn  VDHReleaseMutexSem,<VDMData.hmxWindowedState>
;                  pop     edx

vvfs_exit:
        clrb    VDMData.flVDMXVideo,VDMX_VDDFAULT
        ExitProc
EndProc   vvFreeSystemOutputBase


;/***************************************************************************
;*
;* FUNCTION NAME = vvSetVDMCursor
;*
;* DESCRIPTION   = Set VDM cursor location
;*
;* INPUT         = AH  == function bits (see VVOUT_ constants)
;*                 ECX == video page
;*                 EDX == cursor row (DH) and column (DL)
;*
;* OUTPUT        = EMULATED
;*                     Carry clear
;*                 NOT EMULATED
;*                     Carry set (pass control to next VDD and/or ROM)
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvSetVDMCursor
        call    vvVerifyVDMEmulation
        jc      short vvsc_noemulate    ;emulation disabled or inappropriate

        push    esi
        push    edi
        and     cl,7                    ;ensure page in range (0-7)
        mov     VDMBase.rb_awVCursorPos[ecx*2],dx

        test    ah,VVOUT_NOCURHW        ;should we update the h/w cursor?
        jnz     short vvsc_done         ;no
        cmp     cl,VDMBase.rb_bVPage    ;is specified page same as active?
        jne     short vvsc_done         ;no, so don't update h/w cursor

        mov     edi,FLAToffset VVWriteCRTIndxBgndW
        testb   VDMData.flVDMVideo,VDM_FGND
        jz      short vvsc_notfgnd
        mov     edi,FLAToffset VVWriteCRTIndxFgndW

vvsc_notfgnd:
        call    vvGetVDMCursorOffset    ;ESI == new offset
        push    edx
        movzx   eax,VDMBase.rb_wVStart  ;get controller offset
        shr     eax,1                   ;chop it in half
        add     eax,esi                 ;EAX == true cursor offset
        push    eax
        mov     al,REG_CRTCURLOCHI
        movzx   edx,VDMBase.rb_wVPort
        cmp     dx,PORT_MONOCRTINDX     ;make sure the VDM didn't stuff
        je      short vvsc_portok       ;some random port in its ROM BIOS data
        mov     dx,PORT_COLRCRTINDX
vvsc_portok:
        push    edx
        call    edi                     ;output the word in AX
        pop     edx
        pop     eax
        mov     ah,al
        mov     al,REG_CRTCURLOCLO
        call    edi                     ;output the word in AX
        pop     edx
vvsc_done:
        pop     edi
        pop     esi
        clc

vvsc_noemulate:
        ExitProc
EndProc   vvSetVDMCursor


;/***************************************************************************
;*
;* FUNCTION NAME = vvScrollVDMUp
;*
;* DESCRIPTION   = Scroll up entire VDM screen
;*
;*
;* INPUT         = AH  == attribute for blank line
;*                 DH  == # rows-1 to scroll (from top)
;*                 EDI -> base output address in VDM
;*                 EBX -> base output address in system
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvScrollVDMUp
        LocalVar nRows,ULONG
        LocalVar vvs,VVSCROLL

        EnterProc
        mov     al,' '
        mov     [vvs].vvs_fill,eax
        mov     [nRows],edx             ;save EDX

        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jz      short vvsu_skipflush

;/*
;**
;**   Note that we have to flush any pending string event NOW, because after the
;**   scroll, the LVB will have different data at the point recorded in the string
;**   event.  This is also a problem for STRING and SCROLL operations performed
;**   by separate INT 10h calls (and/or by the DOS app itself): the inevitable LVB
;**   event will eventually clear things up, but in the meantime all I can do is
;**   put the same sort of flush in my INT 10h scroll hook....
;**
;*/

        CallFn  vvFlushEvent,<CURRENT_VDM, VVDEVENT_STRING, 0>

vvsu_skipflush:

;/*
;**
;**   I'm defining a side-effect of disabling Video Retrace Emulation on CGAs
;**   to be that no video disabling be performed here.  Because we don't trap
;**   the status register on the CGA during foreground operation, this is really
;**   the only effect the property has for foreground VDMs anyway.
;**
;*/

       IFDEF CGA
        testb   VDMData.flVDMXVideo,VDMX_RTRCEMULATE
        jz      short vvsu_nowait1
        CallFn  vvDisableDisplay,<CURRENT_VDM>
vvsu_nowait1:
       ENDIF ;CGA

        mov     al,[edi]                ;do "priming" READ thru VDM
        movzx   eax,VDMBase.rb_nVCols.lo; 
        lea     esi,[edi+eax*2]         ;ESI -> top of buffer + 1 row
        movzx   ecx,[nRows].hi          ; 
        imul    ecx,eax                 ;ECX == # cols * # rows-1
        shr     ecx,1                   ;convert words to dwords
        mov     edi,ebx                 ; 
        rep     movsd                   ;move "top+1" to "top"
        mov     ecx,[vvs].vvs_fill      ; 
        xchg    eax,ecx                 ;AX == fill word, ECX == # cols
        rep     stosw                   ;initialize the bottom line

       IFDEF CGA
        testb   VDMData.flVDMXVideo,VDMX_RTRCEMULATE
        jz      short vvsu_nowait2
        CallFn  vvEnableDisplay,<CURRENT_VDM>
vvsu_nowait2:
       ENDIF ;CGA

        testb   VDMData.flVDMVideo,VDM_WINDOWED
        jz      short vvsu_notwindowed
        sub     eax,eax
        mov     [vvs].vvs_rcl.yTop,eax
        mov     [vvs].vvs_rcl.xLeft,eax
        mov     [vvs].vvs_nCols,eax
        inc     eax
        mov     [vvs].vvs_nRows,eax
        mov     al,[nRows].hi
        mov     [vvs].vvs_rcl.yBottom,eax
        mov     al,VDMBase.rb_nVCols.lo
        dec     eax
        mov     [vvs].vvs_rcl.xRight,eax
        SSToDS  eax,[vvs]
        CallFn  vvAddEvent,<CURRENT_VDM, VVDEVENT_SCROLL, eax, EVENT_FLUSH>

vvsu_notwindowed:
        mov     edx,[nRows]             ;restore EDX
        ExitProc
EndProc   vvScrollVDMUp


;/***************************************************************************
;*
;* FUNCTION NAME = vvGetVDMCursorOffset()
;*
;* DESCRIPTION   = Compute offset from cursor row/col
;*
;*
;* INPUT         = EDX == Cursor row (DH) and column (DL)
;*
;* OUTPUT        = ESI == Offset
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvGetVDMCursorOffset
        movzx   ecx,dh                  ;get the row
        movzx   esi,VDMBase.rb_nVCols.lo
        imul    esi,ecx
        movzx   ecx,dl                  ;now get the column
        add     esi,ecx                 ;and add it in
        ExitProc
EndProc   vvGetVDMCursorOffset


;/***************************************************************************
;*
;* FUNCTION NAME = vvVerifyVDMEmulation()
;*
;* DESCRIPTION   = Verify that VDM operation should be emulated
;*
;*
;* INPUT         = Carry clear if emulation can proceed, set otherwise.
;*
;* OUTPUT        = None
;*
;* RETURN-NORMAL =
;* RETURN-ERROR  =
;*
;**************************************************************************/

        align   4                                                       ;          
Procedure vvVerifyVDMEmulation
        testb   VDMData.flVDMXVideo,VDMX_INT10EMULATE
        jz      short vvv_noemulate     ;emulation disabled

        cmp     VDMBase.rb_bVMode,BIOSVMODE_CO80+1
        cmc
        jnc     short vvv_emulate       ;it's color text mode, proceed
        cmp     VDMBase.rb_bVMode,BIOSVMODE_MONO80
        je      short vvv_emulate       ;it's monochrome mode, proceed

;/*
;**
;**     return with Carry cleared if VGA is present while
;**     an XGA is currently running in enhanced mode
;**
;*/

        testb   VDMData.flVDMXVideo,VDMX_SAVERESTORE                    ;          
        jz      vvv_noemulate                                           ;          
        cmp     VDMBase.rb_bVMode,7fh   ;XGA is in enhanced mode        ;          
        jz      vvv_emulate             ;  but VGA is present           ;          
vvv_noemulate:
        stc
vvv_emulate:
        ExitProc
EndProc   vvVerifyVDMEmulation


        EndCode     PRIVATE,SWAP,PASCAL


        END
