;
                 page 66,132
;
;SCRNOFF3.ASM for the IBM PC/XT & PCJR - 1987 by Ocean
;
;This is part 1 of a 2 part utilities set consisting of -----------------------
;SCRNOFF3.ASM & KYLOCK.ASM.  --------------------- THEY MUST BE USED TOGETHER!
;                                                       -----------------------
;
eoi                 equ 20h                     ;end-of-interrupt signal
int_ctrl_port       equ 20h                     ;8259 interrupt controller port
;
code             segment para public 'code'
                 assume cs:code
                 org 0
seg_org             equ $
;
bios_data        segment at 40h                 ;bios data area
                 org 063h
addr_6845        dw ?                           ;define location that holds
                                                ;word address of active display
                 org 065h
crt_mode_set     db ?                           ;define location that holds
                                                ;byte loaded into pc active
                                                ;display port or pcjr's vga
bios_data        ends
;
                 org 0100h
begin:           jmp initialize                 ;goto initialization routine
;
adapter          db 0                           ;0 = EGA, 1 = CGA or MDA, and
                                                ;2 = PCJR
pcjr_mode        db ?                           ;current setting of PCJR video
pc_mode          db ?                           ;current setting of 6845 mode
                                                ;control register of the pc
count            dw 0cc8h                       ;initial 3 min. to blank screen
timer_stat       db 01h                         ;initialize timer - on
msr_address      dw ?                           ;address of mode select register
pcjr_signature   db 0fdh                        ;PCJR BIOS signature
ibm_signature    db 'IBM'                       ;EGA BIOS signature
errmsg           db 13,10,'SCRNOFF3 ALREADY LOADED!',13,10,'$'
;
old_int_1ch      label dword                    ;holding area for INT 8h vector
int_1ch_ptr       dw 2 dup (?)
old_int_16h      label dword                    ;holding area for INT 16h vector
int_16h_ptr      dw 2 dup (?)
;
;------------------------------------------------------------------------------
;All calls to INT 16h will henceforth be routed thru here.  If ah = 255 on
;entry, bh is set to 255 to signal the caller that this routine was indeed
;invoked.
;------------------------------------------------------------------------------
new_int_16h      proc near
                 cmp ah,127                     ;ah = 127?
                 jne switch                     ;no, then jump
                 mov bh,ah                      ;yes, set bh to 255 and exit
                 iret
switch:          cmp ah,158                     ;INT called by ALT O keypress?
                 jne newint1                    ;no, then jump
                 add timer_stat,01h             ;yes, toggle timer on/off
                 iret
newint1:         jmp old_int_16h                ;goto normal 16h handler
new_int_16h      endp
;
;------------------------------------------------------------------------------
;User timer INT 1Ch is now routed through here.
;------------------------------------------------------------------------------
;
countdown3       proc near
                 test timer_stat,01h            ;timer activated?
                 jz do_nothing                  ;no, exit
                 cmp count,00                   ;yes, check if count has zeroed
                 jz do_nothing                  ;already zero, exit
                 dec count                      ;active & not zero, tick & ...
                 jnz do_nothing                 ;not zero, exit ... else ...
;
;Time has run out, call the video_disable routine to blank the screen only.
;The rest of the program is still ready to lock the keyboard with a password if
;desired.
;
                 push ax                        ;save ax register
                 push dx                        ;save dx register
                 cli                            ;disable all interrupts
                 call video_disable             ;time is up - disable the video
                 mov al,eoi                     ;get eoi value
                 out int_ctrl_port,al           ;send eoi signal to the 8259
                 pop dx                         ;restore dx register
                 pop ax                         ;restore ax register
                 sti
do_nothing:      jmp old_int_1ch                ;iret thru old_int_1Ch
countdown3       endp
;
;------------------------------------------------------------------------------
;This routine is user vector interrupt 4dh!
;------------------------------------------------------------------------------
unblank          proc near
                 cmp count,00                   ;if timer is not 0 the screen
                                                ;is still visible - jump to
                 jnz reset_count                ;reset count to 3 min., since
                                                ;a keypress has occured
                 push ax                        ;save ax register
                 push dx                        ;save dx register
                 call video_enable              ;timer was 0 when a keypress
                                                ;occured, so make the screen
                                                ;visible
                 pop dx                         ;restore dx register
                 pop ax                         ;restore ax register
reset_count:     mov count,0cc8h                ;reset timer to 3 min. then 
                                                ;return to caller (KYLOCK.COM)
                 iret
unblank          endp

;
;------------------------------------------------------------------------------
;VIDEO ENABLE and VIDEO DISABLE enable and disable the VIDEO output to the
;screen of the PCJR
;------------------------------------------------------------------------------
;
video_disable    proc near                      ;disable the video display
                 cmp adapter,0                  ;is video adapter an EGA?
                 je ega_disable                 ;yes, then jump
                 test adapter,2                 ;is computer a PCJR?
                 jnz jr_disable                 ;yes, then jump
;
;Disable video of PC with CGA or MDA adapter.
;
                 push ds                        ;save ds
                 mov ax,bios_data               ;set es to bios data area
                 mov ds,ax
                 assume ds:bios_data
                 mov al,crt_mode_set            ;get current value (dynamic) of
                                                ;6845 mode control register
                 mov pc_mode,al                 ;save it
                 mov ax,addr_6845               ;get active display address
                 add ax,4                       ;add 4 to get MSR address
                 mov msr_address,ax             ;save address
                 mov al,0ah                     ;out 6845 index register...
                 mov dx,03b4h                   ;points to 6845 data reg. 10
                 out dx,al
                 mov al,2bh                     ;value to turn off cursor
                 mov dx,03b5h                   ;6845 data registers port
                 out dx,al                      ;disable cursor
                 mov dx,msr_address             ;6845 mode control register
                 mov al,pc_mode                 ;get current value of 6845 mode
                 and al,37h                     ;strip enable bit
                 out dx,al                      ;disable video display
                 pop ds                         ;restore ds
                 ret
;
;disable video of PC with an EGA card.
;
ega_disable:     xor al,al                      ;zero al (clear bit 5)
                 call set_ega                   ;disable EGA
                 ret
;
;Disable video of PCJR.
;
jr_disable:      push ds                        ;save ds register
                 mov ax,bios_data               ;set es to bios data area
                 mov ds,ax                      ;                              
                 assume ds:bios_data            ;                              
                 mov al,crt_mode_set            ;get current value (dynamic) of
                                                ;PCJR VGA mode control register
                 mov pcjr_mode,al               ;store current value, VGA mode
                 mov dx,03dah                   ;PCJR VGA I/O port 
                 in  al,dx                      ;addr/data f/f to proper state
                 mov al,02h                     ;VGA border color register
                 out dx,al                      ;set VGA to border color cont.
                 mov al,00h                     ;color black
                 out dx,al                      ;set border color black
                 mov al,00                      ;VGA mode control 1 register
                 out dx,al                      ;set VGA to mode control 1
                 mov al,pcjr_mode               ;get current value of VGA mode
                 and al,0f7h                    ;strip enable bit
                 out dx,al                      ;disable video display
                 pop ds                         ;restore ds register
                 ret
video_disable    endp
;
video_enable     proc near                      ;enable the video display
                 cmp adapter,0                  ;is video adapter an EGA?
                 je ega_enable                  ;yes,then jump
                 test adapter,2                 ;is the computer a PCJR?
                 jnz jr_enable                  ;yes, then jump
;
;Enable video of PC with CGA or MDA adapter card.
;
                 mov al,0ah                     ;out 6845 index register...
                 mov dx,03b4h                   ;points to 6845 data reg. 10
                 out dx,al
                 mov al,0bh                     ;value to turn cursor on
                 mov dx,03b5h                   ;6845 data registers port
                 out dx,al                      ;enable cursor
                 mov dx,msr_address             ;6845 mode control register
                 mov al,pc_mode                 ;get stored value 6845 mode
                 out dx,al                      ;enable pc display
                 ret
;
;Enable video of PC with an EGA adapter card.
;
ega_enable:      mov al,20h                     ;set bit 5 of al
                 call set_ega                   ;enable EGA video
                 ret
;
;Enable video of PCJR.
;
jr_enable:       mov dx,03dah                   ;set PCJR VGA address
                 in al,dx                       ;addr/data f/f to proper state
                 mov al,00h                     ;VGA mode control 1 register
                 out dx,al                      ;set VGA to mode control 1
                 mov al,pcjr_mode               ;get stored value VGA mode
                 out dx,al                      ;enable PCJR video display ...
                                                ;border remains black
                 ret
video_enable     endp
;
;-----------------------------------------------------------------------------
;SET_EGA is called by VIDEO_ENABLE and VIDEO_DISABLE routines to selectively
;set or clear bit 5 of the EGA Attribute Address Register.
;Entry:  AL - value to OUT to Attribute Address Register
;-----------------------------------------------------------------------------
;
set_ega          proc near
                 push ax                        ;save AL
                 mov dx,3bah                    ;reset monochrome flip-flop...
                 in al,dx                       ;for write to Address Register
                 mov dx,3dah                    ;reset color flip-flop
                 in al,dx
                 mov dx,3c0h                    ;set DX to Attr Addr Register
                 pop ax                         ;retrieve entry value of AL
                 out dx,al                      ;write value to register
                 ret
set_ega          endp
;
;------------------------------------------------------------------------------
;INITIALIZE routine checks if SCRNOFF3 has already been loaded.  If it has,
;execution aborts with an error message.  If it hasn't, then the value of 
;ADAPTER is set according to the type of display adapter present in the system
;and the vectors in low memory pointing to the INT 9h and 16h routines are set
;to point to our own newly installed code.
;------------------------------------------------------------------------------
;
initialize       proc near
;
;See if SCRNOFF3 has been previously loaded by calling INT 16h with AH set to
;254 and BH set to 0.  If BH comes back unchanged, then SCRNOFF3 is NOT
;currently resident in memory; if BH = 255, then SCRNOFF3 has been loaded.
;
                 mov ah,127                     ;set AH and BH
                 xor bh,bh
                 int 16h                        ;call interrupt routine
                 or bh,bh                       ;is BH = 0?
                 je init1                       ;yes, then continue
                 lea dx,errmsg                  ;no, print error message & exit
                 mov ah,09h
                 int 21h
                 ret
;
;Check the computer's ID to see if its a PC or PCJR.
;
init1:           mov ax,0f000h                  ;es to BIOS segment holding
                 mov es,ax                      ;computer ID value
                 mov al,byte ptr es:[0fffeh]    ;offset address and load to al
                 sub al,0fch                    ;
                 or al,al                       ;al = 0?
                 jz pc                          ;AT, try the pc routine...
                 dec al                         ;al = 1?
                 jz pcjr                        ;yes, then computer is a PCJR
                 dec al                         ;al = 2?
                 jz pc                          ;XT, try the PC routine...
                 dec al                         ;al = 3?
                 jz pc                          ;PC
                 jnz pc                         ;unidentified computer, try PC
                 ret
;
;The computer is a PCJR.
;
pcjr:            mov adapter,2                  ;set adapter to PCJR
                 jmp init2                      ;jump to install program
;
;The computer is a PC.  Check for the presence of an Enhanced Graphics Adapter
;by looking for an 'IBM'signature in the EGA Bios area.
;
pc:              mov ax,0c000h                  ;set ES to EGA BIOS segment
                 mov es,ax
                 mov di,1eh                     ;starting address of signature
                 lea si,ibm_signature           ;point si to 'IBM' text
                 mov cx,3                       ;three characters to check
                 cld                            ;clear df
                 repe cmpsb                     ;compare the three bytes
                 je init2                       ;signature found - EGA present
;
;The computer is a PC, but the display adapter is not an EGA.  It must be
;either a CGA or an MDA.
;
                 mov adapter,1                  ;set ADAPTER for CGA or MDA
;
;Save the current interrupt 1Ch vector and replace it with a new routine.
;
init2:           mov ah,35h                     ;DOS function - get vector
                 mov al,1ch                     ;interrupt 1ch
                 int 21h                        ;get the vector
                 mov int_1ch_ptr,bx             ;save offset of vector
                 mov int_1ch_ptr[2],es          ;save segment of vector
                 mov ah,25h                     ;DOS function - set vector
                 mov al,1ch                     ;interrupt 1ch
                 lea dx,countdown3              ;point - countdown3 routine
                 int 21h                        ;set vector
;                                               
;Save the current interrupt 16h vector and replace it with a new routine.
;
                 mov ah,35h                     ;DOS function - get vector
                 mov al,16h                     ;interrupt 16h
                 int 21h                        ;get the vector
                 mov int_16h_ptr,bx             ;save offset of vector
                 mov int_16h_ptr[2],es          ;save segment of vector
                 mov ah,25h                     ;DOS function - set vector
                 mov al,16h                     ;interrupt 16h
                 lea dx,new_int_16h             ;pointer to new routine
                 int 21h                        ;set vector
;
;Set user vector interrupt 4dh to unblank routine.
;
                 mov ah,25h                     ;DOS function - set vector
                 mov al,4dh                     ;interrupt 4dh
                 lea dx,unblank                 ;point to unblank routine
                 int 21h                        ;set vector
                 mov dx,(offset initialize - seg_org + 15) shr 4     ;...
                                                ;prepare DX for exit
                 mov ah,31h                     ;terminate-but-stay-resident
                 int 21h                        ;dos function call
initialize       endp
;
code             ends
                 end begin
                            
