;*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.;
;*****************************************************************************/
;/*****************************************************************************
;*
;* SOURCE FILE NAME = EGAINIT.ASM
;*
;* DESCRIPTIVE NAME = Initialize the EGA/VGA card for color operation
;*
;*
;* VERSION      V2.0
;*
;* DATE         12/05/87
;*
;* DESCRIPTION  This module contains the function which will program an EGA
;*              or VGA for color operation. This file is part
;*              of the device dependent sources.                           
;*
;*              The display adapter is programmed for a 640x350 or 640x480 
;*              16 color mode of operation.  The palette registers are set 
;*              for the default color configuration.                       
;*                                                                         
;*              The VGA's DACs are assumed to be programmed correctly      
;*
;* FUNCTIONS    ring3_physical_enable
;*              ring3_VioGetPSAddress
;*              physical_enable 
;*              physical_disable 
;*              notify_vdd
;*              save_textvram 
;*              read_vram
;*              restore_textvram 
;*              write_vram
;*              setto800 
;*              notify_vwin
;*
;* 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/05/87                     Written by Walt Moore [waltm]
;*   05/06/88                     Bob Grudem [bobgru] Changed MAX_CHAR/ATTR_USE 
;*                                to 2*50*80 from 50*80.
;*   05/06/88                     Bob Grudem [bobgru] Added "/2" to the check   
;*                                against the number of bytes dirtied.  This is 
;*                                necessary because MAX_CHAR_USE and            
;*                                MAX_ATTR_USE are double the actual number of  
;*                                bytes needed to enable the use of "rep movsw".
;*                                In fact, only every other byte is considered  
;*                                dirtied.  A 43-line by 80 column screen of    
;*                                text escapes our rejection test without this  
;*                                compensation.                                 
;*                                Also only restore the number of dirtied       
;*                                bytes in planes 0 and 1, which means the      
;*                                source pointer into the saved bytes must be
;*                                updated before calling write_vram.         
;*   08/02/88                     Jeff Parsons [jeffpar] Now called from the 
;*                                new physical_disable routine.  No longer
;*                                saves plane 3 either.  See restore_textvram 
;*                                for more details.
;*   08/02/88                     Jeff Parsons [jeffpar]
;*                                Major revision.  Called before VioSetMode now,
;*                                so it must do some minimal amount of hardware 
;*                                reprogramming itself.  Also doesn't save plane
;*                                3 anymore, since BVS's random plane 3 trashing
;*                                problem should be fixed Real Soon Now.  And   
;*                                zaps memory clean if we know we can't restore 
;*                                it, including the case of physical_enable     
;*                                being called with "INIT_VRAM".                
;*   01/05/89                     Bob Grudem [bobgru]
;*                                Moved the hardware reprogramming into the     
;*                                function reprogram_hardware, and put that     
;*                                function at the beginning of the _TEXT        
;*                                segment.  See critsec.asm for details of why. 
;*   06/20/91                     Tatchi Lay - Video corruption occurs when
;*                                the Window VDM update thread (see PMVDMP.DLL)
;*                                and the death thread are not serialized.
;*   10/25/91                     John Colleran [johnc] Made ExpressWay changes
;*                                limited to VGA driver.  ExpressWay hardware
;*                                will not be run in EGA mode and the change 
;*                                they gave us read from a port that is write 
;*                                only on the EGA (and CGA).
;*   07/06/92              41616  DAK  model/submodel for nectarine and cursor
;*                                type
;*   06/01/93  @vcb        97576  Commented out VioGetPSAddress because of changes
;*                                made to DDC structure to hold the fontdef and
;*                                mapfontloaded values that used to be thunked in
;*                                this procedure.
;*****************************************************************************/

.386
.MODEL FLAT
ASSUME  SS:FLAT, DS:FLAT, CS:FLAT, ES:FLAT


        .xlist

INCL_DEV                equ     1
INCL_SUB                equ     1
INCL_DOSSEMAPHORES      equ     1
INCL_DOSMVDM            equ     1
        include pmgre.inc
DINCL_SAVE_SCREEN_BITS  equ     1
DINCL_ENABLE            equ     1
DINCL_BITMAP            equ     1
        include driver.inc
        include extern.inc
        include protos.inc

        include egafam.inc
ifdef SEAMLESS
        include seamless.inc
endif
if SCAN_CNT EQ 768
        include oem_macs.inc
endif
        .list

;/*
;** Palette colors as the EGA/VGA uses the adapter
;*/

PAL_BLACK       equ     0
PAL_BLUE        equ     1
PAL_GREEN       equ     2
PAL_RED         equ     4
PAL_YELLOW      equ     PAL_RED or PAL_GREEN
PAL_CYAN        equ     PAL_GREEN or PAL_BLUE
PAL_MAGENTA     equ     PAL_BLUE or PAL_RED
PAL_WHITE       equ     PAL_RED or PAL_GREEN or PAL_BLUE

PAL_I_BLACK     equ     PAL_BLACK       + (PAL_WHITE    shl 3)
PAL_I_RED       equ     PAL_RED         + (PAL_RED      shl 3)
PAL_I_GREEN     equ     PAL_GREEN       + (PAL_GREEN    shl 3)
PAL_I_YELLOW    equ     PAL_YELLOW      + (PAL_YELLOW   shl 3)
PAL_I_BLUE      equ     PAL_BLUE        + (PAL_BLUE     shl 3)
PAL_I_CYAN      equ     PAL_CYAN        + (PAL_CYAN     shl 3)
PAL_I_MAGENTA   equ     PAL_MAGENTA     + (PAL_MAGENTA  shl 3)
PAL_I_WHITE     equ     PAL_WHITE       + (PAL_WHITE    shl 3)

;/*
;** The following values are the initial values for the palette registers.
;*/

.DATA

;/*
;** The 1st three values are:
;** 38 = # bytes in structure
;** 0  = Set palette registers
;** 0  = Start with palette 0
;*/

vio_palette_data  TVIOPALSTATE  <38,0,0,<0,1,2,3,4,5,6,7,8,9,0Ah,0Bh,0Ch,0Dh,0Eh,0Fh>>

;/*
;** On the VGA, the palette contains indices into the array of color DACs.
;** Since we can program the DACs as we please, we'll just put all the indices
;** down at the beginning of the DAC array.
;*/

;/*
;** The following parameters are the parameters passed to VioSetMode
;** to enter the desired graphics mode.
;*/

VGMT_NATIVE EQU 08h

if SCAN_CNT EQ 480

CRTC11_PROTON   EQU     8Ch
CRTC11_PROTOFF  EQU     0Ch
vio_mode_data   VIOMODEINFO <           \
        sizeof VIOMODEINFO,             \
        VGMT_OTHER or VGMT_GRAPHICS,    \
        BITS_PEL,                       \
        80,                             \
        24,                             \
        SCREEN_CX,                      \
        SCREEN_CY                       \
        >
endif

if SCAN_CNT EQ 600

CRTC11_PROTON   EQU     082h
CRTC11_PROTOFF  EQU     002h
vio_mode_data   VIOMODEINFO <       \
        sizeof VIOMODEINFO,         \
        VGMT_OTHER or VGMT_GRAPHICS or VGMT_NATIVE,\
        BITS_PEL,                   \
        100,                        \
        37,                         \
        800,                        \
        600                         \
        >
endif

if SCAN_CNT EQ 768

CRTC11_PROTON   EQU     080h
CRTC11_PROTOFF  EQU     000h
vio_mode_data   VIOMODEINFO <       \
        sizeof VIOMODEINFO,         \
        VGMT_OTHER or VGMT_GRAPHICS or VGMT_NATIVE,\
        BITS_PEL,                   \
        128,                        \
        48,                         \
        1024,                       \
        768                         \
        >

endif

;/*
;** VGA DAC values for the default palette.
;**
;** These values are actually 18-bit numbers stored into three bytes by
;** setting the high two bits of each byte to zero.  Therefore, 3Fh is
;** the maximum value a color component can have.
;**
;**
;**              r    g    b
;*/

vga_dac_data    label   byte
        db      00h, 00h, 00h           ;black
        db      00h, 00h, 28h           ;blue
        db      00h, 28h, 00h           ;green
        db      00h, 28h, 28h           ;cyan
        db      28h, 00h, 00h           ;red
        db      28h, 00h, 28h           ;magenta
        db      28h, 28h, 00h           ;mustard/brown
        db      20h, 20h, 20h           ;dark gray   2A
        db      35h, 35h, 35h           ;light gray  36
        db      00h, 00h, 3Fh           ;bright blue
        db      00h, 3Fh, 00h           ;bright green
        db      00h, 3Fh, 3Fh           ;bright cyan
        db      3Fh, 00h, 00h           ;bright red
        db      3Fh, 00h, 3Fh           ;bright magenta
        db      3Fh, 3Fh, 00h           ;bright yellow
        db      3Fh, 3Fh, 3Fh           ;bright white


SIZE_VGA_DAC_DATA       equ     $ - vga_dac_data

;/*
;** Use 30% Red 59% Green and 11% Blue (from ppxy\phycolor.asm) to map
;** colors to greys
;** The above formula is used as the basis but the colors were adjusted
;** to give a greater distinction between all colors.
;*/


mono_dac_data   label   byte
        db      00h, 00h, 00h           ;black
        db      09h, 09h, 09h           ;blue
        db      19h, 19h, 19h           ;green
        db      1Eh, 1Eh, 1Eh           ;cyan
        db      0Dh, 0Dh, 0Dh           ;red
        db      11h, 11h, 11h           ;magenta
        db      22h, 22h, 22h           ;mustard/brown
        db      20h, 20h, 20h           ;dark gray
        db      35h, 35h, 35h           ;light gray
        db      18h, 18h, 18h           ;bright blue
        db      27h, 27h, 27h           ;bright green
        db      2Eh, 2Eh, 2Eh           ;bright cyan
        db      1Dh, 1Dh, 1Dh           ;bright red
        db      20h, 20h, 20h           ;bright magenta
        db      37h, 37h, 37h           ;bright yellow
        db      3Fh, 3Fh, 3Fh           ;bright white

;/*
;** TFT/LCD color notebook systems have a slighty modified color
;** table at the request of the h/w development group.
;*/

tftlcd_dac_data   label   byte
        db      00h, 00h, 00h           ;black
        db      00h, 00h, 2Ch           ;blue
        db      00h, 2Ch, 00h           ;green
        db      00h, 2Ch, 2Ch           ;cyan
        db      2Ch, 00h, 00h           ;red
        db      2Ch, 00h, 2Ch           ;magenta
        db      2Ch, 2Ch, 00h           ;mustard/brown
        db      20h, 20h, 20h           ;dark gray   2A
        db      38h, 38h, 38h           ;light gray  36
        db      00h, 00h, 3Fh           ;bright blue
        db      00h, 3Fh, 00h           ;bright green
        db      00h, 3Fh, 3Fh           ;bright cyan
        db      3Fh, 00h, 00h           ;bright red
        db      3Fh, 00h, 3Fh           ;bright magenta
        db      3Fh, 3Fh, 00h           ;bright yellow
        db      3Fh, 3Fh, 3Fh           ;bright white

public  vga_dac_data
public  mono_dac_data
public  tftlcd_dac_data

.CODE

;/***************************************************************************
;*
;* FUNCTION NAME = ring3_physical_enable 
;*
;* DESCRIPTION   = ring3_physical_enable makes the actual calls to Vio to enable
;*                 the desired graphics mode.  This code must reside at ring 3. 
;*                 It will be called from the ring2 code via DosCallback.       
;*
;*                 Registers Preserved:       
;*                       SI,DI,BP,DS          
;*                 Registers Destroyed:       
;*                       AX,BX,CX,DX,ES,FLAGS 
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = Vio return code  
;* RETURN-ERROR  = AX = Vio error return code  
;*
;**************************************************************************/

VioGetPSAddress32       PROTO SYSCALL,  hVIO    :DWORD

        ALIGN   4

ring3_physical_enable PROC SYSCALL

        INVOKE  Vio32SetMode,
                ADDR vio_mode_data,
                0

        or      eax,eax                 ;If error, bail out
        jnz     pe_fail

ifdef SCAN_600


        call    setto800
endif

        INVOKE  Vio32SetState,
                ADDR vio_palette_data,
                0

pe_exit::
        ret
ring3_physical_enable ENDP

pe_fail:
        INVOKE  Vga32CallBack,OFFSET ring3_CriticalError
        jmp     pe_exit

        ALIGN   4

ifndef IBMJ        ;IBMJ

;ring3_VioGetPSAddress PROC SYSCALL                          ;vcb


;        INVOKE  VioGetPSAddress32,                          ;vcb
;                edx                             ; hVIO      ;vcb

;        or      eax,eax                                     ;vcb
;        jnz     ring3_VioGetPS_okay                         ;vcb
;        mov     eax,0                                       ;vcb
;ring3_VioGetPS_okay:                                        ;vcb
;        ret                                                 ;vcb
;ring3_VioGetPSAddress ENDP                                  ;vcb

else  ;IBMJ        ;IBMJ

ring3_VioGetPSAddress PROC SYSCALL                          ;vcb


        INVOKE  VioGetPSAddress32,                          ;vcb
                edx                             ; hVIO      ;vcb

        or      eax,eax                                     ;vcb
        jnz     ring3_VioGetPS_okay                         ;vcb
        mov     eax,0                                       ;vcb
ring3_VioGetPS_okay:                                        ;vcb
        ret                                                 ;vcb
ring3_VioGetPSAddress ENDP                                  ;vcb

endif ;IBMJ        ;IBMJ

page


page
;/***************************************************************************
;*
;* FUNCTION NAME = physical_enable  
;*
;* DESCRIPTION   = Graphics mode is enabled by calling Vio.    
;*
;*                 Registers Preserved:       
;*                       SI,DI,BP,DS          
;*                 Registers Destroyed:       
;*                       AX,BX,CX,DX,ES,FLAGS 
;*
;* INPUT         = fInitMem is INIT_VRAM if called from fill_phys_dev_blk;   
;*                     FALSE if called from Resurrection; attempts a fast    
;*                     video RAM restoration in the latter case              
;*                 cbDirty is the number of VRAM bytes to restore for a fast 
;*                     video RAM restoration                                 
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 0 
;* RETURN-ERROR  = AX = Vio Error code if not successful (AX <> 0)               
;*                      or result of video RAM restoration if fInitMem was FALSE 
;*
;**************************************************************************/
        ALIGN   4

physical_enable PROC SYSCALL USES ESI EDI,
        fInitMem :DWORD,
        cbDirty  :DWORD

LOCAL   uRetcode:DWORD

ifdef  JTUNE        ;IBMJ
 or swFlags,SW_CT_DIS_REQ  ; redraw CELL if use it
endif ;JTUNE        ;IBMJ

        INVOKE  Vga32CallBack,OFFSET ring3_physical_enable
        or      eax,eax
        jz      enable_worked
        jmp     enable_failed

        ALIGN   4

enable_worked:
        mov     ecx,VISIBLE_SIZE_WORDS
        cmp     fInitMem,INIT_VRAM      ;init visible VRAM only?
        je      enable_restore          ;yes
        mov     eax,cbDirty
        mov     ecx,8000h               ; 32k words
enable_restore:
        call    restore_textvram        ;go to it!
        mov     uRetcode,eax            ;save return code

if SCAN_CNT EQ 768
        EnableBanks
endif
ifdef VGA132

;/*
;**            make sure screen pitch is correct, this
;** is needed if SCREEN_CBSCAN is not 80.
;*/

        mov     eax,SCREEN_CBSCAN
        cmp     eax,80
        jz      pitch_OK


iowcrtc macro   a,d
        mov     edx,03d4h               ; crtc reg index
        mov     al,&a                   ; reg address
        out     dx,al                   ; do I/O
        mov     edx,03d5h               ; crtc reg data
        mov     al,&d                   ; data for reg
        out     dx,al                   ; do I/O
        endm

        iowcrtc 11h,CRTC11_PROTOFF      ; Turn off protect bit

        mov     ah,SCREEN_CBSCAN        ; pitch in bytes
        shr     ah,1                    ; pitch in multiples of 16
        iowcrtc 13h,ah                  ; set it

        iowcrtc 11h,CRTC11_PROTON       ; Turn on protect bit

pitch_OK:
endif

;/*
;** Invalidate selDeathToUse.  Make sd_pBits.sel in the surface valid.
;** Hopefully this will hose anyone who thinks they can just pick up
;** selDeathToUse and use it.
;*/

        mov     eax,INVALID_ADDRESS
        xchg    eax,selDeathToUse
        mov     sdScreen.sd_pBits,eax
        mov     fGrimReaper,0           ;Screen access allowed

;/*
;** Perform special initialization required for interrupt state detection.
;*/

        clc                             ;do complete re-initialization
        call    init_hw_regs

        public  vga_special_color
vga_special_color::

;/*
;** This is a VGA, so program the color DACs.
;** Below we do the follow before actually sending out the palette:
;**
;** =)    in      03DAh
;** =)    in      03BAh
;** =)    out     03C0h,014h
;** =)    out     03C0h,0
;** =)    out     03C0h,20h
;**
;** The 1st two IN instructions will selectively reset the Attribute Controller
;** Register flip-flop, 3DAh is for color mode and 3BA is for mono.  The OUT
;** to the Attribute Controller Register (3C0) with a value of 14h selects the
;** Color Select Register as the target, a zero value written to the Color
;** Select Register enables the 1st 16 set of R,G,B values in the DAC for
;** attribute mapping.  The last out to 3C0h is required to re-enable the
;** video for display.
;*/

        cli
        mov     dx,EGA_BASE+FEATURE_CONTROL_1
        in      al,dx                   ; Reset the attr reg
        mov     dl,FEATURE_CONTROL_2
        in      al,dx                   ; Reset the attr reg
        mov     al,COLOR_SELECT
        mov     dl,ATTR_REG
        out     dx,al                   ;select "color select register"
        xor     al,al                   ;set color select register to 0
        out     dx,al                   ;This means we are using "palette 0".

        mov     al,PAL_ADDR_SRC         ;set palette address source flag to TRUE.
        out     dx,al                   ;I think this could be combined with the
                                        ;previous OUT.
        mov     dl,DAC_INDEX
        xor     al,al                   ;AL = 0 = starting index
        out     dx,al                   ;specify starting index
        mov     dl,DAC_DATA             ;DX --> DAC data register
        mov     ecx,SIZE_VGA_DAC_DATA

        mov     esi,OFFSET mono_dac_data ; reprogram the DACs according
        cmp     wDisplay,DISPLAY_8503    ; to the monitor attached
        je      slow_outs                ; 8503 and PLASMA are the only

        mov     esi,OFFSET tftlcd_dac_data
        cmp     wDisplay,DISPLAY_COLOR_LCD
        je      slow_outs

        mov     esi,OFFSET vga_dac_data
slow_outs:
        outs    dx,byte ptr [esi]       ; I'd sure like to make this loop
        loop    slow_outs               ; into REP OUTSB, but slow boxes die?
        sti
        mov     drqVideo.pPhysVRAM,MAKEULONG(000Ah,0000h)
        mov     drqVideo.nbReserved,SCREEN_CBRESERVED
        call    notify_vdd              ;notify the VDD, if any

IFDEF   SEAMLESS
        cmp     fInitMem,INIT_VRAM      ;Is this coming from Enable or Resurrection?
        je      @f                      ;We're being called from Enable
        test    fSeamless,SEAMLESS_ACTIVE
        je      @f
        mov     eax,VDM_RESUME_DRAW      ;Let the VDM's continue using the
        mov     ebx,uRetcode             ;Pass the Force Repaint flag to WINDD
        call    notify_vwin              ;  video hardware.
IFDEF   FIREWALLS
        or      eax,eax
        jne     resume_failed
        DebugMsg2 <PMVGA: VDM_RESUME_DRAW successful.>
        jmp     @f
resume_failed:
        DebugMsg2 <PMVGA: VDM_RESUME_DRAW failed.>
ENDIF   ;FIREWALLS
@@:
ENDIF   ;SEAMLESS
        mov     eax,uRetcode

enable_failed:                          ;error code already in AX
        ret
physical_enable ENDP

page
;/***************************************************************************
;*
;* FUNCTION NAME = physical_disable 
;*
;* DESCRIPTION   = Prepare for death.                                           
;*                     
;*                 Registers Preserved:       
;*                       SI,DI,BP,DS          
;*                 Registers Destroyed:       
;*                       AX,BX,CX,DX,ES,FLAGS 
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
        ALIGN   4

physical_disable PROC SYSCALL USES ESI EDI

;/*
;**
;**  Give the VDD a chance to complete all cleanup work first before the
;**  text portion of the VRAM is saved.
;**
;**  Note:  FSRSemEnter is chosen over enter_driver_sem because the call
;**         to req_controller is not needed.
;*/

        sub     eax,eax                 ;AX == 0
        mov     drqVideo.pPhysVRAM,eax
        dec     eax                     ;AX == 0FFFFh
        mov     drqVideo.nbReserved,eax
        call    notify_vdd

IFDEF   SEAMLESS
        test    fSeamless,SEAMLESS_ACTIVE
        je      @f
        mov     eax,VDM_SUSPEND_DRAW     ;Must stop seamless vdm's from
        xor     ebx,ebx
        call    notify_vwin             ;  tampering with the hardware.
IFDEF   FIREWALLS
        or      eax,eax
        jne     suspend_failed
        DebugMsg2 <PMVGA: VDM_SUSPEND_DRAW successful.>
        jmp     @f
suspend_failed:
        DebugMsg2 <PMVGA: VDM_SUSPEND_DRAW failed.>
ENDIF   ;FIREWALLS
@@:
ENDIF   ;SEAMLESS

        INVOKE  enter_driver_sem_only

        dec     fGrimReaper             ;Make it -1
        mov     eax,INVALID_ADDRESS
        xchg    sdScreen.sd_pBits,eax
        mov     selDeathToUse,eax

        call    save_textvram           ;save VRAM to be trashed

        INVOKE  leave_driver_sem_only

        ret
physical_disable ENDP


        ALIGN   4

notify_vdd PROC SYSCALL
        test    fbOffScreen,OFFSCR_VDD  ;is VDD open?
        jz      enable_exit             ;no

        INVOKE  DosRequestVDD,
                hVideoVDD,              ;hvdd
                0,
                VVDSYSREQ_SETDRQ,
                sizeof vvdrq_s,         ;cbInput
                OFFSET drqVideo,        ;pInput
                0,                      ;cbOutput,
                0                       ;pOutput
enable_exit:
        ret
notify_vdd ENDP

page

;/***************************************************************************
;*
;* FUNCTION NAME = save_textvram 
;*
;* DESCRIPTION   = Allocates a segment into which we save 8000 bytes of       
;*                 char/attr data (50 lines being the most a typical VIO text 
;*                 application will ever touch), and 8192 bytes from the 1st  
;*                 font block in plane 2. Note that although text information 
;*                 is contained only in even-address bytes in planes 0 and 1, 
;*                 the odd-address bytes seem to matter too.  They would      
;*                 certainly matter for the low-res CGA graphics modes, which 
;*                 use plane 0 for even bits and plane 1 for odd bits, but VIO
;*                 probably just returns -1 for the dirty count in that case, 
;*                 just because it isn't a text mode.  This is currently only 
;*                 called during Death(), and must be done AFTER the          
;*                 selDeathToUse selector is made valid.                      
;*                                                                            
;*                 Registers Preserved:                                                                       
;*                       BP,DS                                                                                
;*                 Registers Destroyed:                                                                       
;*                       AX,BX,CX,DX,SI,DI,ES,FLAGS                                                           
;*                                                                            
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 0 
;* RETURN-ERROR  = AX = Dos Error code 
;*
;**************************************************************************/

MAX_CHAR_USE    equ     60*132*2        ;9600 bytes (plane 0)
MAX_ATTR_USE    equ     60*132*2        ;9600 bytes (plane 1)
MAX_FONT_USE    equ     256*32          ;8192 bytes (plane 2)
MAX_SAVE_SIZE   equ     MAX_CHAR_USE + MAX_ATTR_USE + MAX_FONT_USE + MAX_FONT_USE


        ALIGN   4

save_textvram PROC SYSCALL
LOCAL   selTemp:DWORD

        lea     ebx,selTemp
        mov     eax,MAX_SAVE_SIZE
        mov     ecx,0
        call    private_alloc

;/*
;** returns pointer to buffer in selTemp
;*/

        xchg    eax,ecx
        or      eax,eax
        jnz     save_exit               ;exit w/error

        mov     eax,selTemp
        mov     selTextVram,eax

;/*
;** selTextVram now points to the buffer to save into
;*/

        cld

;/*
;** Is this an ExpressWay adapter; if so then do a special mode switch
;** VGA == 0FFh   ExpressWay == 0
;*/

        cmp     bVGAtype,VGA_EXPRESSWAY
        jne     st_do_save

;/*
;** Patch for save_textvram and restore_textvram
;** Corrupts ax and dx (but these are unlikely to be long term storage for
;**  anything, and could be saved)
;** Function:
;**  Sets the byte/word flag (which controls RAM remapping in Expressway) to
;**   the state that it is in in text modes for the save / restore function,
;**   and then restores it to its correct value. This code should be added to
;**   both save_textvram and restore_textvram
;*/

        mov     dx,3dah
        in      al,dx
        mov     dx,3c0h
        mov     al,0
        out     dx,al           ; turn video off first

        mov     dx,3d4h         ; Access CRTC register index 17h
        mov     al,17h
        out     dx,al
        inc     dx
        in      al,dx           ; Read value
        push    eax
        and     al,0bfh         ; Clear bit 6 (byte/word bit)
        out     dx,al           ; Write it back



st_do_save:
        mov     edi,selTextVram
        mov     ah,0                    ;read from plane 0
        mov     ecx,MAX_CHAR_USE/4      ;this many words
        .ERRNZ  MAX_CHAR_USE AND 3
        call    read_vram

        inc     ah                      ;read from plane 1
        mov     ecx,MAX_ATTR_USE/4      ;this many words
        .ERRNZ  MAX_ATTR_USE AND 3
        call    read_vram

        inc     ah                      ;read from plane 2
        mov     ecx,MAX_FONT_USE/4      ;this many words
        .ERRNZ  MAX_FONT_USE AND 3
        call    read_vram

        inc     ah                      ;read from plane 3
        mov     ecx,MAX_FONT_USE/4      ;this many words
        .ERRNZ  MAX_FONT_USE AND 3
        call    read_vram

        cmp     bVGAtype,VGA_EXPRESSWAY
        jne     st_nearly_done

        pop     eax             ; Retrieve register value
        mov     ah,al           ; Put value at correct end of register
        mov     dx,3d4h         ; Access CRTC register index 17h
        mov     al,17h
        out     dx,ax


st_nearly_done:

        mov     eax,0                   ;show success

save_exit:
        ret
save_textvram ENDP

        ALIGN   4

read_vram PROC SYSCALL
        mov     esi,selDeathToUse       ;ESI  -> top of VRAM

        mov     al,GRAF_READ_MAP        ;plane # already in AH
        mov     dx,EGA_BASE+GRAF_ADDR
        out     dx,ax                   ;select plane # to read
        rep     movsd                   ;transfer to private segment
        ret                             ;DS:ESI->ES:EDI
read_vram ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = restore_textvram 
;*
;* DESCRIPTION   = Copies the data from our temporary TextVram segment back
;*                 to VRAM, if the number of dirtied VRAM bytes does not   
;*                 exceed the number we saved at time of Death().  Assuming
;*                 that's the case, the shell will not need to perform any 
;*                 repainting.  Otherwise, an error is propagated back to  
;*                 the shell.  This is currently only called during        
;*                 Resurrection(), and must be done BEFORE selDeathToUse is
;*                 invalidated.                                            
;*                                                                         
;*                 Registers Preserved:                                                                  
;*                       BP,DS,ES                                                                        
;*                 Registers Destroyed:                                                                  
;*                       AX,BX,CX,DX,SI,DI,FLAGS                                                         
;*                                                                         
;* INPUT         = ECX = max words of VRAM to restore            
;*                      (VISIBLE_SIZE_WORDS implies init only)                                                           
;*                 EAX = count of VRAM bytes dirtied since Death                                                         
;*                                                                         
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = AX = 0 if successful
;* RETURN-ERROR  = AX = 1 if VRAM buffer has to be re-initialized.
;*
;**************************************************************************/
page

        ALIGN   4

restore_textvram PROC SYSCALL

        cld                             ;DS:ESI->ES:EDI

        push    eax
        push    ecx

        INVOKE  reprogram_hardware

        pop     ecx
        pop     eax

        cmp     ecx,VISIBLE_SIZE_WORDS
        je      restore_initonly        ;init visible VRAM only
        cmp     selTextVram,0           ;any pointer there?
        jz      restore_bad             ;no

        cmp     eax,(MAX_CHAR_USE+MAX_ATTR_USE)/2
        ja      restore_bad             ;count too big (too much dirtied)

        mov     ebx,eax                 ;set up adjusted word count
        shr     ebx,1                   ;CX = total words

; VGA == 0FFh   ExpressWay == 0
        cmp     bVGAtype,VGA_EXPRESSWAY
        jne     @F

;/*
;** Patch for save_textvram and restore_textvram
;** Corrupts ax and dx (but these are unlikely to be long term storage for
;**  anything, and could be saved)
;** Function:
;**  Sets the byte/word flag (which controls RAM remapping in Expressway) to
;**   the state that it is in in text modes for the save / restore function,
;**   and then restores it to its correct value. This code should be added to
;**   both save_textvram and restore_textvram
;** Is this an ExpressWay adapter; if so then do a special mode switch
;*/

        mov     dx,3dah
        in      al,dx
        mov     dx,3c0h
        mov     al,0
        out     dx,al           ; turn video off first

        mov     dx,3d4h         ; Access CRTC register index 17h
        mov     al,17h
        out     dx,al
        inc     dx
        in      al,dx           ; Read value
        push    eax
        and     al,0bfh         ; Clear bit 6 (byte/word bit)
        out     dx,al           ; Write it back

@@:

;/*
;**  Top part of video buffer missing when go from full screen to desktop
;**  using the Trident card.
;**
;** Patch for VGAs that have problems switching from text modes to PM
;**  eq. new Compaq VGA
;*/

        mov     dx,3dah         ; reset the flip-flop
        in      al,dx
        mov     dx,3c0h
        mov     al,10h          ; index the mode control reg of Attr controller
        out     dx,al
        mov     al,01h          ; set it treat data as graphics
        out     dx,al

        mov     al,0001b                ;write to plane 0
        mov     ecx,ebx                 ; 
        mov     esi,selTextVram         ;DS:SI -> top of private segment
        call    write_vram              ; 

        shl     al,1                    ;write to plane 1
        mov     ecx,ebx                 ; 
        mov     esi,selTextVram
        lea     esi,[esi]+MAX_CHAR_USE ;ESI -> top of private segment
        call    write_vram              ; 

        shl     al,1                    ;write to plane 2
        mov     ecx,MAX_FONT_USE/2      ;this many words
        mov     esi,selTextVram
        lea     esi,[esi]+(MAX_CHAR_USE+MAX_ATTR_USE)
        call    write_vram

        shl     al,1                    ;write to plane 3
        mov     ecx,MAX_FONT_USE/2      ;this many words
        mov     esi,selTextVram
        lea     esi,[esi]+(MAX_CHAR_USE+MAX_ATTR_USE+MAX_FONT_USE)
        call    write_vram

;/*
;** VGA == 0FFh   ExpressWay == 0
;*/

        cmp     bVGAtype,VGA_EXPRESSWAY
        jne     @F

        pop     eax             ; Retrieve register value
        mov     ah,al           ; Put value at correct end of register
        mov     dx,3d4h         ; Access CRTC register index 17h
        mov     al,17h
        out     dx,ax

@@:
        mov     eax,0                   ;show success
        jmp     restore_exit

        ALIGN   4

restore_bad:
        or      fbOffScreen,OFFSCR_TRASHED
                                        ;error: cannot restore
restore_initonly:
        mov     eax,0
        mov     edi,selDeathToUse       ;EDI  -> top of VRAM
        pushfd
        shr     ecx,1
        rep     stosw
        popfd
        je      restore_exit
        inc     eax                     ;on error, return error (AX=1)

restore_exit:
        push    eax
        mov     ecx,0
        xchg    ecx,selTextVram
        jecxz   @F
;SEL    call    global_free
        call    private_free
@@:
        pop     eax

        ret
restore_textvram ENDP

        ALIGN   4

;/***************************************************************************
;*
;* FUNCTION NAME = write_vram 
;*
;* DESCRIPTION   = Writes to VRAM
;*
;* INPUT         = AL - plane # to write
;*                 ECX - # of WORDs to write
;*                 DS:ESI - DATA to write
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

write_vram PROC SYSCALL
        mov     edi,selDeathToUse       ;EDI  -> top of VRAM
        mov     dx,EGA_BASE+SEQ_DATA
        out     dx,al                   ;select plane # to write
        shr     ecx,1                   ; get # DWORDS
        rep     movsd                   ;transfer back to screen surface
        jnc     wv_done
        movsw
wv_done:
        ret
write_vram ENDP

ifdef SCAN_600

        ALIGN   4

;/***************************************************************************
;*
;* FUNCTION NAME = setto800
;*
;* DESCRIPTION   = This init's the TSENG ET 4000 ONLY !!!!
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/
setto800 PROC SYSCALL


        mov     edx,EGA_BASE+MISC_OUTPUT
        mov     al,0EFh
        out     dx,al

        mov     edx,EGA_BASE+SEQ_ADDR
        mov     eax,0300h
        out     dx,ax

        inc     al
        mov     ah,01h
        out     dx,ax

        inc     al
        mov     ah,0fh
        out     dx,ax

        inc     al
        mov     ah,0h
        out     dx,ax

        inc     al
        mov     ah,06h
        out     dx,ax

        inc     al
        inc     al

        mov     ah,0h
        out     dx,ax

        inc     al
        mov     ah,0bch
        out     dx,ax
        mov     edx,EGA_BASE+CRTC_ADDR

        mov     al,011h         ;unlock the other registers
        mov     ah,002h
        out     dx,ax

        mov     al,0
        mov     ah,07fh
        out     dx,ax

        mov     al,01h
        mov     ah,063h
        out     dx,ax

        mov     al,02h
        mov     ah,064h
        out     dx,ax

        mov     al,03h
        mov     ah,02h
        out     dx,ax

        mov     al,04h
        mov     ah,064h
        out     dx,ax

        mov     al,05h
        mov     ah,017h
        out     dx,ax

        mov     al,06h
        mov     ah,077h
        out     dx,ax

        mov     al,07h
        mov     ah,0f0h
        out     dx,ax

        mov     al,08h
        mov     ah,0h
        out     dx,ax

        mov     al,09h
        mov     ah,060h
        out     dx,ax

        mov     al,0ah
        mov     ah,0h
        out     dx,ax

        mov     al,0bh
        mov     ah,0h
        out     dx,ax

        mov     al,0ch
        mov     ah,0h
        out     dx,ax

        mov     al,0dh
        mov     ah,0h
        out     dx,ax

        mov     al,0eh
        mov     ah,0h
        out     dx,ax

        mov     al,0fh
        mov     ah,0h
        out     dx,ax

        mov     al,010h
        mov     ah,60h
        out     dx,ax

        mov     al,012h
        mov     ah,057h
        out     dx,ax

        mov     al,013h
        mov     ah,032h
        out     dx,ax

        mov     al,014h
        mov     ah,0h
        out     dx,ax

        mov     al,015h
        mov     ah,05bh
        out     dx,ax

        mov     al,016h
        mov     ah,075h
        out     dx,ax

        mov     al,017h
        mov     ah,0c3h
        out     dx,ax

        mov     al,018h
        mov     ah,0ffh
        out     dx,ax

        mov     al,33h
        mov     ah,00h
        out     dx,ax

        mov     al,35h
        mov     ah,00h
        out     dx,ax

        mov     al,011h         ; lock them back
        mov     ah,082h
        out     dx,ax


        ret
setto800 ENDP
endif

IFDEF   SEAMLESS
;/***************************************************************************
;*
;* FUNCTION NAME = notify_vwin 
;*
;* DESCRIPTION   = This function tells the VWIN to notify all seamless     
;*                 VDM's to stop drawing to the screen or to continue      
;*                 drawing.                                                
;*
;* INPUT         = ax = VDM_SUSPEND_DRAW (4001h) to stop drawing           
;*                 ax = VDM_RESUME_DRAW (4002h) to continue drawing        
;*                 bx = 1 to force repaint on VDM_RESUME_DRAW, 0 otherwise.
;*                      (This is not relevalnt for VDM_SUSPEND_DRAW)       
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = ax = return code from DosRequestVDD 
;* RETURN-ERROR  = ax = return code from DosRequestVDD 
;*
;**************************************************************************/

        ALIGN   4

notify_vwin PROC SYSCALL
        test    fSeamless,SEAMLESS_ACTIVE
        je      not_seamless

        INVOKE  DosRequestVDD,
                hWinVDD,                ;hvdd
                -1,                     ; 
                VWIN_SIGVDMDIRTY,       ; 
                EAX,                    ;cbInput
                0,                      ;pInput
                EBX,                    ;cbOutput
                0                       ;pOutput
not_seamless:
        ret
notify_vwin ENDP

ENDIF   ;SEAMLESS

end
