;*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.;
;*****************************************************************************/
;-------------------------------------------------------------------------
;
;   Module          = VVGAA.ASM
;
;   Description     = VGA Virtualisation code
;
;   Functions       = Contains the functions that need to perform IO
;                     for VGA Virtualisation.
;
;
;-------------------------------------------------------------------------
ifdef   VVGA

.386p
INCL_GPIBITMAPS EQU     1
include os2.inc
include eddinclt.inc
?DF     equ     1                                                       ;**
include  cmacros.inc


extrn   _ActivatePlanarVGA_routine    :byte
extrn   _DeactivatePlanarVGA_routine  :byte

_DATA   segment use32 dword public 'DATA'                               ;**
extrn   _pVGAVRAM               :dword
extrn   _fPlanarVGAIsActive     :dword
extrn   _usPlanarXGAIOAddr      :word
extrn   _fFreePlanarXGA         :dword
_DATA   ends

_IOPL   segment dword use32 public 'CODE'
        assume  cs:FLAT, ds:FLAT, es:FLAT

iodelay MACRO
        jmp     @F
@@:
        ENDM

;-----------------------------------------------------------------
; Define the registers and bits necessary for enabling/disabling the
; planar VGA Video Subsystem.
;-----------------------------------------------------------------
SYSTEM_BOARD_ENABLE_REG equ     0094h
SETUP_VIDEO_SUBSYSTEM   equ     020h
ENABLE_VIDEO_SUBSYSTEM  equ     001h
POS_REG_2               equ     0102h

PORT_MONO_CRTC_INDEX    equ     03B4h
PORT_MONO_CRTC_DATA     equ     03B5h
PORT_COLOR_CRTC_INDEX   equ     03D4h
PORT_COLOR_CRTC_DATA    equ     03D5h


DEACTIVATE_XGA_VGA_MODE equ     0
ACTIVATE_XGA_VGA_MODE   equ     1


;-----------------------------------------------------------------
; VGAIsActive tests to see if there is an active VGA by doing a
; write/read/compare test on a VGA register.
;-----------------------------------------------------------------

; Define test patterns for the write/read/compare operations.
TEST_PATTERN1        EQU     001h    ; 00000001
TEST_PATTERN2        EQU     002h    ; 00000010

ALIGN   4
_VGAIsActive   PROC
PUBLIC  _VGAIsActive

        ; Read in current value from test port
        mov     dx,PORT_MONO_CRTC_INDEX
        call    TestPort
        or      eax,eax
        jnz     exit

        mov     dx,PORT_COLOR_CRTC_INDEX
        call    TestPort
        or      eax,eax
        jnz     exit

        ; Zero eax to indicate no active VGA
        xor     eax,eax
        jmp     exit


IFDEF   TEST_VGA_MEM
; !! The VGA must be put into an appropriate read mode before testing the !!
; !! memory location.                                                     !!

        ;------------------------------------------------------------------
        ; Load up the segment registers
        ;------------------------------------------------------------------
        mov     ax, SEG FLAT:_pVGAVRAM
        mov     ds, ax
        mov     es, ax

        ;------------------------------------------------------------------
        ; Test VGA memory location.
        ; !! NEED TO PUT VGA IN CORRECT READ MODE !!
        ;------------------------------------------------------------------
        mov     edx,_pVGAVRAM
        ; Save current memory contents
        mov     bl,byte ptr [edx]
        mov     byte ptr [edx],TEST_PATTERN1
        cmp     byte ptr [edx],TEST_PATTERN1
        jne     no_active_vga

        mov     byte ptr [edx],TEST_PATTERN2
        cmp     byte ptr [edx],TEST_PATTERN2
        jne     no_active_vga

        ; Restore original memory contents.
        mov     byte ptr [edx],bl

        ; There is an active VGA! Return 1 to indicate the fact.
        mov     eax,1
        jmp     short   exit

no_active_vga:
        ; Return zero to indicate no active VGA.
        xor     eax,eax
ENDIF  ;TEST_VGA_MEM

exit:
        ret

_VGAIsActive   ENDP

;-----------------------------------------------------------------
; TestPort checks whether the specified port is present
; by performing a read/compare/write operation.
; Port to be tested is in dx.
;-----------------------------------------------------------------
; Define test patterns for the write/read/compare operations.
TEST_PATTERN1        EQU     001h    ; 00000001
TEST_PATTERN2        EQU     002h    ; 00000010

TestPort        PROC
PUBLIC  TestPort

        ; Port to be tested is in dx
        in      al,dx
        mov     bl,al           ; Save current value in bl
        mov     al,TEST_PATTERN1
        out     dx,al
        iodelay
        in      al,dx
        cmp     al,TEST_PATTERN1
        jne     no_port
        mov     al,TEST_PATTERN2
        out     dx,al
        iodelay
        in      al,dx
        cmp     al,TEST_PATTERN2
        jne     no_port
        mov     al,bl           ; Restore saved value from bl
        out     dx,al
        mov     eax,1
        jmp     short test_port_exit

no_port:
        xor     eax,eax

test_port_exit:
        ret

TestPort        ENDP



;-----------------------------------------------------------------
;*****************************************************************
;-----------------------------------------------------------------


;-----------------------------------------------------------------
; ActivatePlanarVGA checks whether there is a disabled planar VGA
; and if so, activates it.
; It also copes with the case of a planar XGA that is unused,
; which will be enabled in VGA mode.
;-----------------------------------------------------------------
ALIGN   4
cProc   ActivatePlanarVGA,<PUBLIC,NODATA>
cBegin
        call    fword ptr _ActivatePlanarVGA_routine.cg_offset
cEnd

ALIGN   4
_ActivatePlanarVGAWorker PROC FAR
PUBLIC  _ActivatePlanarVGAWorker

        ; Load segment registers
        mov     bx, SEG FLAT:_fFreePlanarXGA
        mov     ds, bx
        mov     es, bx

        ; Check that there is not another active VGA.
        ; If so, we cannot enable the planar VGA (if there is one), so
        ; we must fail.
        call    _VGAIsActive
        or      eax,eax
        jnz     activate_failed

        ; See if there is a free XGA on the planar which we are
        ; using for VVGA.
        mov     eax,_fFreePlanarXGA
        or      eax,eax
        jz      check_for_planar_VGA

        ; Put the spare XGA into VGA mode
        mov     dx,_usPlanarXGAIOAddr
        mov     al,ACTIVATE_XGA_VGA_MODE
        out     dx,al

        jmp     activation_complete

check_for_planar_VGA:
        ; Now check to see if a planar VGA is present.
        ; We disable interrupts for this critical section.
        cli

        ; Put system into "setup video subsystem" mode.
        ; This is done by CLEARING the SETUP_VIDEO_SUBSYSTEM bit.
        mov     dx,SYSTEM_BOARD_ENABLE_REG
        in      al,dx
        iodelay
        and     al,NOT SETUP_VIDEO_SUBSYSTEM
        out     dx,al

        ; Try to activate the planar video.
        mov     dx,POS_REG_2
        in      al,dx
        iodelay
        or      al,ENABLE_VIDEO_SUBSYSTEM
        out     dx,al

        ; Take the system out of "setup video subsystem" mode.
        ; This is done by SETTING the SETUP_VIDEO_SUBSYSTEM bit.
        mov     dx,SYSTEM_BOARD_ENABLE_REG
        in      al,dx
        iodelay
        or      al,SETUP_VIDEO_SUBSYSTEM
        out     dx,al

        ; Reenable interrupts
        sti


activation_complete:
        ; Now see whether we have successfully activated a VGA adapter
        ; If there is an active VGA then we have been successful.
        ; If there is no active VGA then there was no planar VGA, and we have
        ; failed

        ; We can therefore just pass back the return code from VGAIsActive.
        call    _VGAIsActive
        jmp     short activate_exit

activate_failed:
        xor     eax,eax

activate_exit:
        ;------------------------------------------------------------------
        ; Store the result in a global variable (as returning through
        ; a callgate trashes eax).
        ;------------------------------------------------------------------
        mov     _fPlanarVGAIsActive,eax
        ret

_ActivatePlanarVGAWorker   ENDP


;-----------------------------------------------------------------
; DeactivatePlanarVGA disables the planar VGA video subsystem.
;-----------------------------------------------------------------
ALIGN   4
cProc   DeactivatePlanarVGA,<PUBLIC,NODATA>
cBegin
        call    fword ptr _DeactivatePlanarVGA_routine.cg_offset
cEnd

ALIGN   4
_DeactivatePlanarVGAWorker PROC FAR
PUBLIC  _DeactivatePlanarVGAWorker

        ; Load the segment registers
        mov     bx, SEG FLAT:_fFreePlanarXGA
        mov     ds, bx
        mov     es, bx

        ; See if there is a free XGA on the planar which we are
        ; using for VVGA.
        mov     eax,_fFreePlanarXGA
        or      eax,eax
        jz      deactivate_planar_vga

        ; Put the spare XGA into VGA mode
        mov     dx,_usPlanarXGAIOAddr
        mov     al,DEACTIVATE_XGA_VGA_MODE
        out     dx,al

        jmp     deactivation_complete

deactivate_planar_vga:
        ; We disable interrupts for this critical section.
        cli

        ; Put system into "setup video subsystem" mode.
        ; This is done by CLEARING the SETUP_VIDEO_SUBSYSTEM bit.
        mov     dx,SYSTEM_BOARD_ENABLE_REG
        in      al,dx
        iodelay
        and     al,NOT SETUP_VIDEO_SUBSYSTEM
        out     dx,al

        ; Deactivate the planar video.
        ; This is done by clearing the ENABLE_VIDEO_SUBSYSTEM bit.
        mov     dx,POS_REG_2
        in      al,dx
        iodelay
        and     al,NOT ENABLE_VIDEO_SUBSYSTEM
        out     dx,al

        ; Take the system out of "setup video subsystem" mode.
        ; This is done by SETTING the SETUP_VIDEO_SUBSYSTEM bit.
        mov     dx,SYSTEM_BOARD_ENABLE_REG
        in      al,dx
        iodelay
        or      al,SETUP_VIDEO_SUBSYSTEM
        out     dx,al

        ; Reenable interrupts
        sti

deactivation_complete:
        ret

_DeactivatePlanarVGAWorker ENDP




;-----------------------------------------------------------------
;*****************************************************************
;-----------------------------------------------------------------



ifdef   SET_VGA_MODE
;-----------------------------------------------------------------------
; DisableXGAVGA is called at initialisation time when the XGA adapter is
; in VGA mode. The routine disables the currently active XGA (remembering
; its instance number so that it can be reenabled later).
;-----------------------------------------------------------------------
ALIGN   4
cProc   DisableXGAVGA,<PUBLIC,NODATA>
cBegin
        call    fword ptr _DisableXGAVGA_routine.cg_offset
cEnd

FIRST_XGA_ENABLE_REG    EQU     02100h
INSTANCE_DELTA          EQU     010h
MAX_XGA_INSTANCES       EQU     16
XGA_VGA_ENABLED         EQU     1
XGA_VGA_DISABLED        EQU     0

ALIGN   4
_DisableXGAVGAWorker  PROC FAR
        mov     ecx,MAX_XGA_INSTANCES
        mov     dx,FIRST_XGA_ENABLE_REG
check_reg:
        in      al,dx
        cmp     al,XGA_VGA_ENABLED
        je      found_xga_instance
        add     dx,INSTANCE_DELTA
        loop    check_reg

        ; There don't seem to be any XGAs active!
        jmp     disable_exit

found_xga_instance:
        mov     al,XGA_VGA_DISABLED
        out     dx,al

        ;------------------------------------------------------------------
        ; Save the instance number so we can reactivate the XGA later.
        ;------------------------------------------------------------------
        mov     ax, SEG FLAT:DisabledXGAInstance
        mov     ds, ax
        mov     DisabledXGAInstance,dx

disable_exit:
        ret

_DisableXGAVGAWorker  ENDP



;-----------------------------------------------------------------------
; EnableXGA is called at initialisation time to reenable the XGA adapter
; which was disabled by a previous call to DisableXGA.
;-----------------------------------------------------------------------
ALIGN   4
cProc   EnableXGAVGA,<PUBLIC,NODATA>
cBegin
        call    fword ptr _EnableXGAVGA_routine.cg_offset
cEnd

ALIGN   4
_EnableXGAVGAWorker  PROC FAR
PUBLIC  _EnableXGAVGAWorker

        mov     ax, SEG FLAT:DisabledXGAInstance
        mov     ds, ax
        mov     dx,DisabledXGAInstance

        ; Check for a dud instance value
        cmp     dx, 0
        je      enable_exit

        ; Reenable the main XGA (in VGA mode)
        mov     al,XGA_VGA_ENABLED
        out     dx,al

enable_exit:
        ; Zero the Instance number
        xor     dx,dx
        mov     DisabledXGAInstance,dx
        ret


_EnableXGAVGAWorker  ENDP
endif   ;SET_VGA_MODE


_IOPL   ends

endif  ; VVGA

end
