;-------------------------------------------------------------------------
; HIDE2.SYS - Take timer and clear screen on ticks until told not to.
;
; Note: this driver also hooks Int 19 and restores Int 1C on an Int 19
;       reboot.
;-------------------------------------------------------------------------

VEC_TWIDDLE = 1                         ; Assembles IVT/BDA/XBDA save code
COMMAND_PARAMETER = 1                   ; Scan for /X - disables screen clear

request_header struc
;----------------------
len     db      ?
unit    db      ?
command db      ?
status  dw      ?
reserve db      8 dup (?)
;----------------------
nunits  db      ?
endaddr dd      ?
pCmdLine dd     ?
;----------------------
request_header ends

cseg    segment para public 'CODE'
        assume  cs:cseg
        org     0
;--------------------------- DEVICE HEADER -------------------------------
nuldev  dd      -1              ; Link to next device
        dw      8000H           ; Character device
        dw      offset strategy ;
HackInt label   word
        dw      offset interrupt;
        db      'HIDE$   '      ;

        .386

CLRSCR  macro   DoSaves
if DoSaves
        push    eax
        push    cx
        push    di
        push    es
endif
        xor     eax, eax
        mov     cx, ((80 * 25)/2)
        mov     di, 0B800h
        mov     es, di
        xor     di, di
        cld
        rep     stosd
if DoSaves
        pop     es
        pop     di
        pop     cx
        pop     eax
endif
        endm

SweepFlag  db   4h

        align   4

;----------------------------------------------
; Timer tick trapper.
;----------------------------------------------
TimerTrap proc far
;----- This 2 byte JMP will be overwritten by the exec shell with
;----- NOP's to neutralize the screen blanking effects of this driver.
NOPhack  label   word
         jmp     short foobar

ChainIt: db     0EAh     ; Intersegment JMP w/4 byte immediate
OldTimer dd      ?       ; Filled in at init time
OldTimer8 dd     ?       ; Filled in at init time

foobar: dec     SweepFlag
        jnz     ChainIt
        mov     SweepFlag, 4
        CLRSCR  1
        jmp     short ChainIt
TimerTrap endp

req_ptr label   dword
rh_offset dw    ?
rh_seg    dw    ?


;----------------------------------------------
;           DD strat routine
;----------------------------------------------
strategy proc far
        mov     cs:rh_offset, bx  ;offset
        mov     cs:rh_seg, es     ;segment
        ret
strategy endp

MiniInt proc far
        push    ds
        push    si
        mov     word ptr NOPhack, 9090h ;
        lds     si, cs:req_ptr          ; Get RQH pointer back
        mov     ax, 0100H               ; No error + Done
        mov     ds:[si].status, ax      ;
        pop     si
        pop     ds
        ret
MiniInt endp

Int19Hook proc  far
        ;
        ; Int 19 is a one-way trip, so saving regs is unnecessary here...
        ;

ifdef VEC_TWIDDLE

SAVELEN = (1024 + 256)                  ; IVT + BDA

        push    cs
        pop     ds
        mov     si, offset VecSave
        push    0
        pop     es
        xor     di, di
        mov     cx, (SAVELEN / 4)
        cld
        rep     movsd

        lodsw                           ; AX = XBDA seg
        push    ax                      ; Save XBDA seg
        or      ax, ax                  ; Is it 0?
        lodsw                           ; AX = XBDA length (in bytes)
        jz      restore_done            ; Seg 0?

        pop     es                      ; ES:DI --> XBDA
        xor     di, di                  ;
        xchg    cx, ax                  ; CX == length
        rep     movsb                   ; Blast the XBDA back
        push    0                       ; ES --> IVT
        pop     es                      ;

restore_done:
        jmp     dword ptr es:[19h * 4]
else
        push    0                       ;
        pop     ds                      ;
        mov     eax, OldTimer8          ;
        mov     ds:[8h * 4], eax        ; Restore old Int 8 vector
        mov     eax, OldTimer           ;
        mov     ds:[1Ch * 4], eax       ; Restore old Int 1C vector
        db      0EAh                    ; Intersegment immediate JMP opcode
endif
Old19save dd    ?                       ;   ...the address for the JMP
Int19Hook endp

ifdef VEC_TWIDDLE
VecSave db      SAVELEN dup (0)
XBDAseg label word
       dw      0                       ; Segment addr of XBDA
XBDAlen label word
       dw      0                       ; Length, in bytes, to move
XBDAdata label byte
       db      8192 dup (?)            ; The XBDA data.  Up to 8K allowed
endif

;*************************************************************************
;*            Everything after this point gets thrown away               *
;*************************************************************************

        align   16

ifdef COMMAND_PARAMETER
;------------------------------------------------------------
; Look for "... /X ..." parameter on command line.
;------------------------------------------------------------
SlashX  db      1                       ; Do timer screen clearing?

ScanCommandLine proc near
        push    ds
        push    si
        push    ax
        pushf

        lds     si, cs:req_ptr          ; DS:SI-->req hdr
        lds     si, ds:[si].pCmdLine    ; DS:SI-->command line
        cld
ScanLoop:
        lodsb
        cmp     al, 13
        je      EndScan
        cmp     al, 10
        je      EndScan
        cmp     al, '/'
        jne     ScanLoop
        lodsb
        cmp     al, 'x'
        je      GotX
        cmp     al, 'X'
        jne     ScanLoop
GotX:
        mov     cs:SlashX, 0          ; Don't do timer CLS

EndScan:
        popf
        pop     ax
        pop     si
        pop     ds
        ret
ScanCommandLine endp
endif

;----------------------------------------------
;            DD interrupt routine
;----------------------------------------------
interrupt proc far

        push    ds
        push    es
        pusha

ifdef COMMAND_PARAMETER
        call    ScanCommandLine
endif

ifdef VEC_TWIDDLE
        ;
        ; Get pre-sysinit IVT from 3000:0000 and save to VecSave
        ;
        push    cs
        pop     es
        mov     di, 3000h
        mov     ds, di                  ; Src = 3000:0000
        xor     si, si
        mov     di, offset VecSave      ; Dst = VecSave
        mov     cx, (SAVELEN / 4)
        cld
        rep     movsd

        lodsw                           ; AX = XBDA addr - if any
        stosw
        or      ax, ax                  ; Zero seg?
        lodsw                           ; AX = XBDA len
        stosw                           ;
        jz      SaveDone                ; Zero means no XBDA
;
; Now move the XBDA data
;
        xchg    cx, ax                  ; CX = XBDA length
        rep     movsb                   ; Move it

SaveDone:
        add     di, 16                  ; Add some slack
        push    di                      ; Save Chop Point
endif

        ;
        ; Get old timer tick (int 1C) vector
        ;
        mov     ax, 351Ch
        int     21h
        mov     word ptr OldTimer+0, bx
        mov     word ptr OldTimer+2, es
        ;
        ; Get old timer tick 8 (int 8) vector
        ;
        mov     ax, 3508h
        int     21h
        mov     word ptr OldTimer8+0, bx
        mov     word ptr OldTimer8+2, es

ifdef COMMAND_PARAMETER
        cmp     cs:SlashX, 0
        je      SkipTimerHooking
endif
        ;
        ; Hook Timer Tick
        ;
        mov     ax, 251Ch
        push    cs
        pop     ds
        mov     dx, offset TimerTrap
        int     21h

ifdef COMMAND_PARAMETER
SkipTimerHooking:
endif
        ;
        ; Get old Int 19 vector
        ;
        mov     ax, 3519h
        int     21h
        mov     word ptr Old19save+0, bx
        mov     word ptr Old19save+2, es
        ;
        ; Hook Int 19's
        ;
        mov     ax, 2519h
        push    cs
        pop     ds
        mov     dx, offset Int19Hook
        int     21h
        ;
        ; Clear the screen
        ;
ifdef COMMAND_PARAMETER
        cmp     cs:SlashX, 0
        je      Skip2TimerHooking
endif

        CLRSCR  0

ifdef COMMAND_PARAMETER
Skip2TimerHooking:
endif
        ;
        ; Setup all the necessarr gorp for a DD's return to DOS
        ;
        lds     si, cs:req_ptr                  ; Get RQH pointer back

ifdef VEC_TWIDDLE
; Get back chop point from stack.
        pop     word ptr ds:[si].endaddr
else
        mov     word ptr ds:[si].endaddr, offset Interrupt
endif

        mov     word ptr ds:[si].endaddr+2, cs  ;
        mov     ax, 0100H                       ; No error + Done
        mov     ds:[si].status, ax
        ;
        ; Alter "interrupt" routine to be new "mini" routine.
        ;
        mov     HackInt, offset MiniInt         ; The new interrupt routine...

        popa                                    ;
        pop     es                              ;
        pop     ds                              ;
        ret                                     ;

        db      'Copyright (C) IBM 1995'

interrupt endp

cseg    ends
        end
