;*DDK*************************************************************************/
;
; COPYRIGHT (C) Microsoft Corporation, 1989
; 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).
;*   ??/??/92              56370  Fixed various problems with VRAM getting trashed
;*                                by a mode switch from full-screen to PM.
;*   01/15/93              59385  Add Cirrus Logic support.
;*   07/27/93              70227  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.
;*   09/23/93              74076  Force repaint on Headland HT209 because of bug
;*                                in Virtual Video. We are getting a zero count
;*                                in cbDirty in physical_enable and yet the
;*                                Desktop is corrupted.
;*
;*****************************************************************************/

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


        .xlist
ifdef PALMGR2
INCL_GPIBITMAPS         equ                      1
endif
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
INCL_DOSERRORS  EQU     1
        include bseerr.inc
        include driver.inc
        include extern.inc
        include protos.inc

        include egafam.inc
ifdef SEAMLESS
        include seamless.inc
endif

        INCLUDE POINTER.INC
        INCLUDE ASSERT.MAC
        include curstrc.inc


        .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.
;*/


EXTERNDEF CurData:CURSORSTRUCT
EXTERNDEF SM_WINDRV:_SM_WINDRV


.DATA

ext_save1    db 4 dup (0)
ext_save2    db 4 dup (0)

;/*
;** 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
BANK_USE        EQU     0008h

vio_mode_data   VIOMODEINFO <    \
        12,                      \
        11,                      \
        8,                       \
        80,                      \
        30 ,                     \
        640,                     \
        480                      \
        >
endif

if SCAN_CNT EQ 600


CRTC11_PROTON   EQU     082h
CRTC11_PROTOFF  EQU     002h
BANK_USE        EQU     000ah

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
BANK_USE        EQU     000ch

vio_mode_data   VIOMODEINFO <       \
        12,                         \
        11,                         \
        8,                          \
        128,                        \
        48,                         \
        1024,                       \
        768                         \
        >
endif


EXTERNDEF       PalColor:BYTE         ;physical palette triplets from
                                      ;from phycolor.asm

;/*
;** 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

SIZE_MONO_DAC_DATA      equ                      $ - mono_dac_data
public  mono_dac_data


public  spdway_reg
spdway_reg      dw      0


;/*
;** the following tables contain the code offsets of the device specific
;** routines used by physical_enable
;*/

scanlength_adj_rtns     dd      offset oem_scanlength_adj_rtn
                        dd      offset generic_scanlength_adj_rtn
                        dd      offset generic_scanlength_adj_rtn
                        dd      offset generic_scanlength_adj_rtn
                        dd      offset generic_scanlength_adj_rtn
                        dd      offset ati_scanlength_adj_rtn
                        dd      offset generic_scanlength_adj_rtn
                        dd      offset generic_scanlength_adj_rtn ;          

chip_specific_init_rtns dd      offset oem_specific_init_rtn
                        dd      offset video7_specific_init_rtn
                        dd      offset trident_specific_init_rtn
                        dd      offset tseng_specific_init_rtn
                        dd      offset wd_specific_init_rtn
                        dd      offset ati_specific_init_rtn
                        dd      offset spdway_specific_init_rtn
                        dd      offset cirrus_specific_init_rtn  ;          

save_textvram_rtns      dd      offset oem_save_textvram_rtn
;                       dd      offset generic_save_textvram_rtn
                        dd      offset save_textvram_rtn         ;          
;                       dd      offset trident_save_textvram_rtn
                        dd      offset save_textvram_rtn         ;          
                        dd      offset generic_save_textvram_rtn
;                       dd      offset generic_save_textvram_rtn
                        dd      offset save_textvram_rtn         ;          
                        dd      offset generic_save_textvram_rtn
                        dd      offset generic_save_textvram_rtn
                        dd      offset save_textvram_rtn         ;          

restore_textvram_rtns   dd      offset oem_restore_textvram_rtn
;                       dd      offset generic_restore_textvram_rtn
;                       dd      offset restore_textvram_rtn      ;          
                        dd      offset forcerepaint_restore_textvram_rtn  ;          
;                       dd      offset trident_restore_textvram_rtn
                        dd      offset restore_textvram_rtn      ;          
                        dd      offset generic_restore_textvram_rtn
;                       dd      offset generic_restore_textvram_rtn
                        dd      offset restore_textvram_rtn      ;          
                        dd      offset generic_restore_textvram_rtn
                        dd      offset generic_restore_textvram_rtn
                        dd      offset restore_textvram_rtn      ;          

save_textvram           dd      offset generic_save_textvram_rtn

restore_textvram        dd      offset generic_restore_textvram_rtn

.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

ring3_physical_enable PROC SYSCALL

        INVOKE  Vio32SetMode,
                ADDR vio_mode_data,
                0

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

@@:
        INVOKE  Vio32SetState,
                ADDR vio_palette_data,
                0
pe_exit::
        ret
ring3_physical_enable ENDP

pe_fail:

        INVOKE  Vga32CallBack,OFFSET ring3_CriticalError

        jmp     pe_exit


;            ***************************************************************************
;           *
;           * FUNCTION NAME = ring3_VioGetPSAddress
;           *
;           * DESCRIPTION   = Calls the thunked VIO cal VioGetPSAddress32
;           *
;           * INPUT         = NONE
;           * OUTPUT        = NONE
;           *
;           * RETURN-NORMAL = NONE
;           * RETURN-ERROR  = NONE
;           *
;           **************************************************************************/
;                                PROC SYSCALL
;          
;                  INVOKE  VioGetPSAddress32,
;                          edx
;          
;                  or      eax,eax
;                  jz      ring3_VioGetPS_okay
;                  mov     eax,0
;                              
;                  ret
;                                ENDP


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
;*
;**************************************************************************/

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

LOCAL   uRetcode:DWORD




        INVOKE  Vga32CallBack,OFFSET ring3_physical_enable

        or      eax,eax
        jz      enable_worked
        jmp     enable_failed

enable_worked:




        movzx   eax,wSVGAtype

        or      eax,eax
        jz      enable_failed           ;bvh didn't recognize the chip

        shl     eax,2                   ;use as index into dword table

@@:

; initialize our run time chip-specific routine addresses

        mov     edx,bank_switch_rtns[eax]
        mov     set_bank_select,edx

        mov     edx,save_textvram_rtns[eax]
        mov     save_textvram,edx

        mov     edx,restore_textvram_rtns[eax]
        mov     restore_textvram,edx

        mov     edx,cursor_bank_switch_rtns[eax]
        mov     CurData.curs_bank_switch_rtn,edx

        mov     edx,save_hw_state_rtns[eax]
        mov     CurData.curs_save_hw_state_rtn,edx

        mov     edx,restore_hw_state_rtns[eax]
        mov     CurData.curs_restore_hw_state_rtn,edx

;/*
;** set the logical scan line length to 1024 if it's not already
;*/

ifndef  VARLEN
ife     SCAN_CNT eq 768

        push    ax
        call    scanlength_adj_rtns[eax]
        pop     ax

endif   ;scan_cnt
endif   ; VARLEN



;/*
;** do any chip specific initializations
;*/

        mov     edx,fInitMem
        call    chip_specific_init_rtns[eax]
        or      eax,eax
        jz      enable_worked2
        jmp     enable_failed

enable_worked2:

; restore that portion of PM graphics screen destroyed by another context

        mov     edx,fInitMem
        mov     eax,cbDirty
        mov     ecx,8000h               ; 32k words
enable_restore:
        call    restore_textvram        ;go to it!
        mov     uRetcode,eax            ;save return code

;/*
;** 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

ifdef PALMGR2

EXTERN InitDefaultColorTables:NEAR

        call    InitDefaultColorTables
        jmp     special_color_done

else

        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_MONO_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
        cmp     wDisplay,DISPLAY_PLASMA     ; monochromes supported by VGA driver
        je      slow_outs
        mov     esi,OFFSET PalColor
        mov     ecx,256*3
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?

endif   ;PALMGR2

special_color_done:


        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
;       color_puts      BLUE,BLACK,<   PMVGA: VDM_RESUME_DRAW successful.>
        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
;*
;**************************************************************************/

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


;/***************************************************************************
;*
;* FUNCTION NAME = notify_vdd
;*
;* DESCRIPTION   = Generic function to notify the Virtual Video device driver
;*                 of some event
;*
;* INPUT         = NONE
;*
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

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 = generic_save_textvram_rtn
;*
;* 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*80*2         ;9600 bytes (plane 0)
MAX_ATTR_USE    equ     60*80*2         ;9600 bytes (plane 1)
MAX_FONT_USE    equ     512*32          ;8192 bytes (plane 2)
MAX_SAVE_SIZE   equ     MAX_FONT_USE*4

generic_save_textvram_rtn PROC SYSCALL
LOCAL   selTemp:DWORD

        lea     ebx,selTemp

        mov     eax,MAX_SAVE_SIZE
        mov     ecx,0

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

        mov     eax,selTemp
        mov     selTextVram,eax

        cld

st_do_save:

        mov     al,0                    ;read from plane 0
        mov     ecx,MAX_SAVE_SIZE/2
        mov     edi,selTextVram
        mov     esi,selDeathToUse       ;ESI  -> top of VRAM
        call    read_vram

st_nearly_done:

        mov     eax,0                   ;show success

save_exit:
        ret
generic_save_textvram_rtn ENDP

;/***************************************************************************
;*
;* FUNCTION NAME = read_vram
;*
;* DESCRIPTION   = Reads from VRAM into private memory
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

read_vram PROC SYSCALL
        mov     dl,al
        call    set_bank_select
        rep     movsw                   ;transfer to private segment
        ret                             ;DS:ESI->ES:EDI
read_vram ENDP

page
;/***************************************************************************
;*
;* 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.
;*
;**************************************************************************/

generic_restore_textvram_rtn PROC SYSCALL

        cld                             ;DS:ESI->ES:EDI

        cmp     edx,INIT_VRAM           ;init visible VRAM only?
        je      restore_initonly        ;init visible VRAM only

        cmp     selTextVram,0           ;any pointer there?
        jz      restore_bad             ;no

        cmp     eax,MAX_FONT_USE

        ja      restore_bad             ;count too big (too much dirtied)

        mov     ebx,MAX_FONT_USE
        shl     ebx,1                   ;account for four bytes/planes per char

        mov     al,0                    ;write to plane 0
        mov     esi,selTextVram         ;DS:SI -> top of private segment

@@:
        mov     edi,selDeathToUse       ;EDI  -> top of VRAM
        mov     ecx,ebx                 ; 
        call    write_vram              ; 


        mov     eax,0                   ;show success
        jmp     restore_exit

restore_bad:
        or      fbOffScreen,OFFSCR_TRASHED
                                        ;error: cannot restore
restore_initonly:

        pushf
        mov     BX,BANK_USE
        xor     eax,eax
        mov     dl,bh
        xor     bh,bh
buf_clr_loop:
        mov     edi,selDeathToUse
        call    set_bank_select
        mov     ecx,4000h
        rep     stosd
        inc     dl
        dec     bl
        jnz     buf_clr_loop
        popf
        je      restore_exit
        inc     eax                     ;on error, return error (AX=1)

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

        ret
generic_restore_textvram_rtn ENDP

;/***************************************************************************
;*
;* 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     dl,al
        call    set_bank_select
        rep     movsw                   ;transfer back to screen surface
        ret
write_vram ENDP


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
;*
;**************************************************************************/


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

ifdef PALMGR2
;/***************************************************************************
;*
;* FUNCTION NAME = LoadPaletteEntries
;*
;* DESCRIPTION   = Loads the hardware palette to the pointer passed in.
;*
;* INPUT         = start           :ULONG,
;*                 count           :ULONG,
;*                 pPaletteEntries :DWORD
;*
;* OUTPUT        = pPaletteEntries - filled in
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;**************************************************************************/

LoadPaletteEntries PROC SYSCALL USES ESI,
        start           :ULONG,
        count           :ULONG,
        pPaletteEntries :DWORD


        mov     dx,EGA_BASE
        mov     dl,DAC_INDEX
        mov     eax,start
        out     dx,al                   ;specify starting index
        mov     dl,DAC_DATA             ;DX --> DAC data register
        mov     esi,pPaletteEntries
        mov     ecx,count
        cli
slow_outs:
        mov     al,[esi].RGB2.rgb2_bRed
        shr     al,2
        out     dx,al
        mov     al,[esi].RGB2.rgb2_bGreen
        shr     al,2
        out     dx,al
        mov     al,[esi].RGB2.rgb2_bBlue
        shr     al,2
        out     dx,al
        add     esi,sizeof RGB2
        loop    slow_outs               ; into REP OUTSB, but slow boxes die?
        sti
        ret
LoadPaletteEntries ENDP
endif


ati_scanlength_adj_rtn PROC SYSCALL

if      SCAN_CNT eq 480

        mov     dx,03d4h
        mov     al,13h
        out     dx,al                   ;pt CRTC Reg13 (offset register)
        inc     dl
        in      al,dx
        mov     ah,al                   ;*256
        xor     al,al
        mov     bl,160                  ;/160
        div     bl
        out     dx,al

else

if      SCAN_CNT eq 600

        mov     dx,03d4h
        mov     al,13h
        out     dx,al                   ;pt CRTC Reg13 (offset register)
        inc     dl
        in      al,dx
        mov     ah,al                   ;*256
        xor     al,al
        mov     bl,200                  ;/200
        div     bl
        out     dx,al

        mov     dx,01CEh
        mov     al,0b6h
        out     dx,al                   ;01CEh
        inc     dx
        in      al,dx                   ;01CFh
        or      al,01h
        mov     ah,0b6h
        xchg    ah,al
        dec     dx
        out     dx,ax                   ;01CEh

endif   ;600
endif   ;480

        ret

ati_scanlength_adj_rtn  ENDP


generic_scanlength_adj_rtn PROC SYSCALL

        mov     dx,3d4h
        mov     al,13h
        out     dx,al
        inc     dx
        in      al,dx
        cmp     al,40h
        ja      use_long_val
        mov     al,40h                  ;a lot of chips halve the crtc13 value
        jmp     short offset_val_set
use_long_val:
        mov     al,80h
offset_val_set:
        out     dx,al
        ret

generic_scanlength_adj_rtn ENDP


oem_scanlength_adj_rtn  PROC SYSCALL

        ret

oem_scanlength_adj_rtn  ENDP


ati_specific_init_rtn PROC SYSCALL

;/*
;** set up separate r/w pages
;*/

        mov     dx,01CEh
        mov     al,0beh
        out     dx,al                   ;01CEh
        inc     dx
        in      al,dx                   ;01CFh
        or      al,08h
        mov     ah,0beh
        xchg    ah,al
        dec     dx
        out     dx,ax                   ;01CEh
        xor     eax,eax            ; indicate success
        ret

ati_specific_init_rtn ENDP


video7_specific_init_rtn PROC SYSCALL

        mov     dx,03c4h                ; enable ext. reg. access
        mov     ax,0ea06h
        out     dx,ax
        xor     eax,eax            ; indicate success
        ret

video7_specific_init_rtn ENDP

spdway_specific_init_rtn PROC SYSCALL

                                        ;find i/o port before calling
                                        ; restore_vram

        cmp     edx,INIT_VRAM   ;is this our first time through?
        jne     spd_reg_ok              ; if so then
        mov     dx,2100h                ; look for the register base
lp1:    in      al,dx                   ; read what's there
        mov     ah,al
        mov     al,07h                  ; write out an '07'
        out     dx,al
        in      al,dx                   ; read it back and save it
        mov     cl,al
        mov     al,ah                   ; replace what was originally there
        out     dx,al
        cmp     cl,05h                  ; did we get the right answer?
        je      foundit
        add     dx,10h                  ;  nope - room for another look?
        cmp     dx,2180h
        jb      lp1                     ;  yup - try again

        mov     eax,ERROR_DEV_NOT_EXIST ; bummer - no SPEEDWAY found
        ret

foundit:
        add     dx,8
        mov     spdway_reg,dx           ; save this location
        mov     CurData.bank_reg,dx
        mov     SM_WINDRV.wBankReg,dx           ; 
spd_reg_ok:
        xor     eax,eax            ; indicate success
        ret

spdway_specific_init_rtn ENDP


trident_specific_init_rtn PROC SYSCALL
                                        ;set 1 window on trident
        Mov     DX, 03C4H             ;    Set 64K banks (A0000..AFFFF)
        Mov     AL, 0BH               ;    Index register = 0B
        Out     DX, AL                ; 
        Inc     DX                    ; 
        In      AL, DX                ;    Change 3C5.0E's definition
        mov     dx,3ceh
        mov     al,6
        out     dx,al
        inc     dx
        mov     al,5
        out     dx,al
        Mov     DX, 03C4H             ; FOR EVEREX - Fix SR2
        mov     al,2
        out     dx,al
        inc     dx
        mov     al,0fh
        out     dx,al
        xor     eax,eax            ; indicate success

        ret

trident_specific_init_rtn ENDP

wd_specific_init_rtn    PROC SYSCALL

        Mov     DX, 03CEH
        Mov     AX, 050FH          ; Prepare to enable extentions
        Out     DX, AX             ; Registers are now accessable
        Mov     AL, 0BH            ; Register "PR1"
        Out     DX, AL             ; 
        Inc     DX                 ; 
        In      AL, DX             ; Read PR1
        And     AL, Not 8          ; Disable PR0B, forcing 1 64K window
        Out     DX, AL             ; instead of 2 32K windows.
        xor     eax,eax            ; indicate success
        ret

wd_specific_init_rtn ENDP

tseng_specific_init_rtn PROC SYSCALL

        xor     eax,eax            ; indicate success
        ret

tseng_specific_init_rtn ENDP

; start           
cirrus_specific_init_rtn PROC SYSCALL

        mov     dx,3c4h            ; enable extended registers
        mov     ax,01206h
        out     dx,ax

        mov     dx,3ceh
        mov     al,0bh             ; set single 64k page
        out     dx,al
        inc     dx
        in      al,dx
        and     al,NOT 1
        out     dx,al
        xor     eax,eax            ; indicate success
        ret

cirrus_specific_init_rtn ENDP
; end           

oem_specific_init_rtn   PROC SYSCALL

        xor     eax,eax            ; indicate success
        ret

oem_specific_init_rtn   ENDP

trident_save_textvram_rtn PROC SYSCALL
LOCAL   selTemp:DWORD

        lea     ebx,selTemp

        mov     eax,MAX_SAVE_SIZE
        mov     ecx,0

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

        mov     eax,selTemp
        mov     selTextVram,eax

        cld

st_do_save:

        mov     al,0                    ;read from plane 0
        mov     ecx,MAX_SAVE_SIZE/2
        mov     edi,selTextVram

                                        ;this board's relationship between
        mov     eax,ecx                 ;planar and liner is different than
        mov     ebx,8                   ; the other's so we must restore a
        xor     edx,edx                 ;little bit at the beginning of each
        div     ebx                     ; of the first 8 segments
        mov     ebx,eax
        mov     ecx,eax
        xor     eax,eax

@@:
        mov     esi,selDeathToUse       ;ESI  -> top of VRAM
        call    read_vram

        mov     ecx,ebx
        inc     al
        cmp     al,8
        jb      @B

st_nearly_done:

        mov     eax,0                   ;show success

save_exit:
        ret
trident_save_textvram_rtn ENDP


trident_restore_textvram_rtn PROC SYSCALL

        cld                             ;DS:ESI->ES:EDI

        cmp     edx,INIT_VRAM           ;init visible VRAM only?
        je      restore_initonly        ;init visible VRAM only

        cmp     selTextVram,0           ;any pointer there?
        jz      restore_bad             ;no

        cmp     eax,MAX_FONT_USE

        ja      restore_bad             ;count too big (too much dirtied)

        mov     ebx,MAX_FONT_USE
        shl     ebx,1                   ;account for four bytes/planes per char

        mov     al,0                    ;write to plane 0
        mov     esi,selTextVram         ;DS:SI -> top of private segment

        mov     eax,ebx                 ;planar and liner is different than
        mov     ebx,8                   ; the other's so we must restore a
        xor     edx,edx                 ;little bit at the beginning of each
        div     ebx                     ; of the first 8 segments
        mov     ebx,eax
        xor     eax,eax

@@:
        mov     edi,selDeathToUse       ;EDI  -> top of VRAM
        mov     ecx,ebx                 ; 
        call    write_vram              ; 

        inc     al
        cmp     al,8
        jb      @B

        mov     eax,0                   ;show success
        jmp     restore_exit

restore_bad:
        or      fbOffScreen,OFFSCR_TRASHED
                                        ;error: cannot restore
restore_initonly:

        pushf
        mov     BX,BANK_USE
        xor     eax,eax
        mov     dl,bh
        xor     bh,bh
buf_clr_loop:
        mov     edi,selDeathToUse
        call    set_bank_select
        mov     ecx,4000h
        rep     stosd
        inc     dl
        dec     bl
        jnz     buf_clr_loop
        popf
        je      restore_exit
        inc     eax                     ;on error, return error (AX=1)

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

        ret
trident_restore_textvram_rtn ENDP

;           Start
save_textvram_rtn PROC SYSCALL
        mov     eax,0                   ;show success
        ret
save_textvram_rtn ENDP

restore_textvram_rtn PROC SYSCALL
        cld                             ;DS:ESI->ES:EDI

        cmp     edx,INIT_VRAM           ;init visible VRAM only?
        je      restore_initonly        ;init visible VRAM only

        cmp     eax,0                   ;EAX == cbDirty
        jz      restore_exit

        or      fbOffScreen,OFFSCR_TRASHED
                                        ;error: cannot restore
restore_initonly:

        pushf
        mov     BX,BANK_USE
        xor     eax,eax
        mov     dl,bh
        xor     bh,bh
buf_clr_loop:
        mov     edi,selDeathToUse
        call    set_bank_select
        mov     ecx,4000h
        rep     stosd
        inc     dl
        dec     bl
        jnz     buf_clr_loop
        popf
        je      restore_exit
        inc     eax                     ;on error, return error (AX=1)

restore_exit:
        ret
restore_textvram_rtn ENDP
;           End

forcerepaint_restore_textvram_rtn PROC SYSCALL
        xor     eax,eax
        cmp     edx,INIT_VRAM           ;is this our first time through?
        jz      @f
        inc     eax                     ; force repaint
@@:
        ret
forcerepaint_restore_textvram_rtn ENDP


oem_save_textvram_rtn PROC SYSCALL
        mov     eax,0                   ;show success
        ret
oem_save_textvram_rtn ENDP

oem_restore_textvram_rtn PROC SYSCALL
        cld                             ;DS:ESI->ES:EDI

        cmp     edx,INIT_VRAM           ;init visible VRAM only?
        je      restore_initonly        ;init visible VRAM only

        cmp     eax,0                   ;EAX == cbDirty
        jz      restore_exit

        or      fbOffScreen,OFFSCR_TRASHED
                                        ;error: cannot restore
restore_initonly:

        pushf
        mov     BX,BANK_USE
        xor     eax,eax
        mov     dl,bh
        xor     bh,bh
buf_clr_loop:
        mov     edi,selDeathToUse
        call    set_bank_select
        mov     ecx,4000h
        rep     stosd
        inc     dl
        dec     bl
        jnz     buf_clr_loop
        popf
        je      restore_exit
        inc     eax                     ;on error, return error (AX=1)

restore_exit:
        ret
oem_restore_textvram_rtn ENDP

end
