;COMMENT |
;== License =================================================================
;
;  Copyright (c) 1995, 1996, 2004, Robert Rothenburg Walking-Owl.
;  (Portions by Colin Plumb.)  All rights reserved.
;
;  Redistribution and use in source and binary forms, with or without
;  modification, are permitted provided that the following conditions
;  are met:
;
;    * Redistributions of source code must retain the above copyright
;      notice, this list of conditions and the following disclaimer.
;
;    * Redistributions in binary form must reproduce the above copyright
;      notice, this list of conditions and the following disclaimer in
;      the documentation and/or other materials provided with the
;      distribution.
;
;    * Neither the names of the authors nor the names of its
;      contributors may be used to endorse or promote products derived
;      from this software without specific prior written permission.
;
;  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
;  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
;  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
;  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
;  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
;  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
;  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
;  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
;  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
;  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;  POSSIBILITY OF SUCH DAMAGE.
;
;===========================================================================|

%include "printf.inc"

; --------------------------------------------------------------------------
rInitDevice:
                les     bx,[rrh] ; es:[bx] -> random response hdr
                lea     dx, EndOfDevice
                mov     WORD [es:bx+ReqHdr.Addr], dx
                mov     WORD [es:bx+ReqHdr.Addr+2], cs
                jmp     rfinished
; Note: Win95/MS-DOS 7 needs a proper value returned here.

; --------------------------------------------------------------------------
; Notes: assumes es:[di] -> urandom request hdr
InitDevice:
;;  ifdef WIN95
;;                mov     WORD PTR [STATAPI+2], cs
;;  endif
		mov	ax, 1600h	; Check	if in Windows
; We probably don't need this, but it's	better to be on	the safe side
		int	MltplxSvc
		test	al, al		; if al	!= 0, set Windows flag
		jz	SHORT @InDe0
		or	WORD [Flags],	WindowsFlag
@InDe0:

		call	DriverInit

		les	bx,[urh] ; es:[bx] -> urandom response	hdr
		lea	dx, EndOfDevice
		mov	WORD [es:bx+ReqHdr.Addr], dx
		mov	WORD [es:bx+ReqHdr.Addr+2],	cs
		jmp	finished


; --------------------------------------------------------------------------
; -----	hook interrupts	and print a small message
;	assumes	al=int,	bx=routine (save oldvec	at bx-4)

@HookListPtr:
                DW      @HookList
Install_Int:
		pushf		; save vector number and flags
		xor	ah, ah
		push	ax
		cli		; disable interrupt flag

                mov     di, [@HookListPtr]
                mov     BYTE [di], al
                mov     WORD [di+1], bx
                add     WORD [@HookListPtr], 3

		push	ax
		push	bx
		mov	ah, 35h	; get interrupt	vector and save	it
		int	DOS
		pop	ax
		xchg	ax, bx
                mov     WORD [bx+4], es
                mov     WORD [bx+2], ax
		mov	dx, bx
		pop	ax
		mov	ah, 25h	; set new vector
		int	DOS
                test    WORD [UserOptionFlags], SuppressTechie
                jnz     SHORT @iiNoTechie
		Printf	@iitext
		xor	ax, ax		  ; ax == 0, no	error
		popf			  ; restore flags
		retn
@iiRejected:
		mov	ax, -1		  ; ax == -1, an error occurred
		add	sp, 2		  ; restore stack, flags
		popf
		retn
@iiNoTechie:
		xor	ax, ax
		add	sp, 2		  ; restore stack, flags
		popf
		retn

@iitext:
	DB	' %2x',0

; --------------------------------------------------------------------------
; We first want	to set flags for selected options, do any diagnostics later

ShowLicenseFlag	equ 8000h  ; Print license when installing
SuppressTechie  equ 4000h  ; Show interrupts and other stuff when load
InitPoolFlag	equ 2000h  ; Initialize	entropy	pool when installing
SampleDiskFlag  equ 1000h  ; Install Int 13h handler (v0.5)
SampleVideoFlag equ 0800h  ; Enable video sampling
MouseFlag       equ 0400h  ; Enable mouse sampling
DriftFlag       equ 0200h  ; Enable drift sampling
;;SuppressInt13   equ 0100h  ; Don't hook Int 13h (Win95/DOS7)

FlagSets:
; /A = enable sampling of Audio	card
@EnableAudio:
  %ifn __SamplAudio
	jmp  @DisabledOption
  %else
	and  WORD [Flags], (~ NoAudioFlag)
	clc
	retn
; <----	Allow user to specify base address of sound card
  %endif
; /C = enable sampling of Clock	drift
@EnableDrift:
  %ifn __SamplDrift
	jmp  @DisabledOption
  %else
        or   WORD [UserOptionFlags], DriftFlag        
	clc
	retn
  %endif
; /I = Initialize entropy pool with random keystrokes
@InitializeOnInstall:
  %ifn __Sample09
	jmp  @DisabledOption
  %else
        or   WORD [UserOptionFlags], InitPoolFlag
        mov  WORD [SeedCount], (InitSeedCnt << FRACBITS)
; <----	Allow user to specify the number of bits to sample?
	clc
	retn
  %endif
; /K = Keep entropy pool topped	off after hashing
@EnableKeepFull:
	jmp  @DisabledOption
; /L = show License
@ShowLicense:
	or   WORD [UserOptionFlags], ShowLicenseFlag
	clc
	retn
; /M = enable sampling of mouse	Movement
@EnableMotion:
  %ifn __SamplMouse
	jmp  @DisabledOption
  %else
        xor     ax, ax                  ; test if mouse is installed
        int     33h
        test    ax, ax
        jnz     SHORT @mousOk0
        mov     al, 'M'                 ;
        jmp     @UnableOption
@mousOk0:
        or   WORD [UserOptionFlags], MouseFlag
	clc
	retn
  %endif
; /D = Install Int 13h sampler
@InstallDisk:
  %ifn __Sample13
        jmp  @DisabledOption
  %else

; Note: a call to Int 2F/AX=4A33h should return AX==0 if MS-DOS 7,
;       AX != 0 for anything else.

        cmp  BYTE [DosVersionMaj], 7    ; Check DOS version
        jge  @UnableOption
; <---- Instead print a different error message...
        or   WORD [UserOptionFlags], SampleDiskFlag
        clc
        retn
  %endif
@Quiet:
        or   WORD [UserOptionFlags], SuppressTechie
        clc
        retn
; /V = Video
@SampleVideoRetrace:
  %ifn __SamplVideo
        jmp  @DisabledOption
  %else
        or   WORD [UserOptionFlags], SampleVideoFlag
        clc
        retn
  %endif
; /O = Ignore OS version
@IgnoreOSVersion:
        mov    BYTE [DosVersionMaj], 0
        clc
        retn
@BadOption:
        MPrintf ax, msgIllegalOption
        xor    ah, ah   ; wait for keypress
        int    Keyboard
	stc
	retn
msgIllegalOption:
        DB LF, "I do not recognize that option ('%c'). Aborting installation.", CR, LF
	DB "Allowable options are:", CR, LF
  %if __SamplAudio
	DB " /A",TAB,"enable sampling of Audio card", CR, LF
  %endif
  %if __SamplDrift = 1
	DB " /C",TAB,"enable sampling of Clock drift during idle time",	CR, LF
  %endif
  %if __Sample13
        DB " /D",TAB,"enable sampling of Disk access (disabled under DOS 7+)", CR, LF
  %endif
  %if __Sample09
	DB " /I",TAB,"Initialize entropy pool with keystrokes when installing",	CR, LF
  %endif
	DB " /L",TAB,"show License", CR, LF
        DB " /O",TAB,"ignore OS version", CR, LF
        DB " /Q",TAB,"quiet installation (suppress techie messages)", CR, LF
  %if __SamplMouse
	DB " /M",TAB,"enable sampling of Mouse movement", CR, LF
  ;; during idle-time or periodic timer
  %endif
  %if __SamplVideo
        DB " /V",TAB,"Sample vertical retrace intervals from Video", CR, LF
  %endif
  DB LF
msgPressKey:
        DB "Press a key to continue....", BELL, CR, LF
        DB LF, 0
@UnableOption:
        MPrintf ax, msgUnableOption
        jmp     SHORT @waitOnKey
@DisabledOption:
        MPrintf ax, msgDisabledOption
@waitOnKey:
        MPrintf msgPressKey
        xor    ah, ah
        int    Keyboard
	stc
	retn
msgDisabledOption:
	DB LF, "Sorry, that option ('%c') is not available in this build."
        DB CR, LF, LF, 0
msgUnableOption:
        DB LF, "Sorry, unable to use that option ('%c') on this system."
        DB CR, LF, LF, 0
UserOptionFlags:
  DW 0
ArgTable:
  DB 'ACIKLMDVQO'
NumArgs	equ $ -	ArgTable
ArgHandlr:
  DW @EnableAudio
  DW @EnableDrift
  DW @InitializeOnInstall
  DW @EnableKeepFull
  DW @ShowLicense
  DW @EnableMotion
  DW @InstallDisk
  DW @SampleVideoRetrace
  DW @Quiet
  DW @IgnoreOSVersion
; --------------------------------------------------------------------------
DoOption: ; al = character to check
; MS-DOS 5.0 will convert to uppercase from CONFIG.SYS,	but some dyanmic
;   loader utilities will not convert the command line options.
	cmp	al, 'a'
	jb	SHORT @doNotLower
	cmp	al, 'z'
	ja	SHORT @doNotLower
	sub	al, 20h
@doNotLower:
        mov     bx, NumArgs-1
@doLoop:
	cmp	al, [ArgTable+bx]
	je	SHORT @doCheck
	dec	bx
	jns	SHORT @doLoop
	jmp	@BadOption
@doCheck:
	add	bx, bx
	lea	bx, [ArgHandlr+bx]
	jmp	[bx]

; --------------------------------------------------------------------------
DriverInit:	; Initialize the driver
		Printf	InitMsg ; Print header
  %if (__CPU)
		call	TestCPU		  ; Check if CPU is Ok to use
		test	ax, ax
		jz	SHORT CorrectCPU
		retn			  ; if not, return(-1)
  CorrectCPU:
  %else
    %warning "**I'd hate to see how slow this runs on an 8088 wrt Wisecrack..."
  %endif
                mov     ah, 30h           ; Get DOS version
                int     DOS
                mov     [DosVersionMaj], al

                mov     ax, cs
                mov     Word [NoiseWin+TSR_Info_Struc.TSR_PSP_Segment], ax
                mov     Word [NoiseWin+TSR_Info_Struc.TSR_ID_Block+2], ax
                mov     Word [NoiseWin+TSR_Info_Struc.TSR_ID_Block], NoiseID

; -----	check for command-line arguments passed	to driver (redone v0.4.3)
                 les     di,[es:di+18]
;@diFirstArg:    mov     al, es:[di]
;                cmp     al, ' '      ; find first space
;                je      SHORT @diArgumentLoop
;                cmp     al, CR       ; end of line?
;                je      SHORT @diArgEOL ; done...
;                inc     di
;                jmp     SHORT @diFirstArg
@diArgumentLoop:
		inc	di	     ; increment pointer
		mov	al, [es:di]  ; get character
		cmp	al, CR	     ; end of line?
		je	SHORT @diArgEOL	; done...
                cmp     al, LF       ; OS/2 DOS boxes sometimes end line w/LF
                je      SHORT @diArgEOL
		cmp	al, '/'	     ; SwitchChar?
		jne	SHORT @diArgumentLoop ;	if not,	continue...
		inc	di	     ; increment
		mov	al, [es:di]  ; get character
		cmp	al, CR	     ; end of line? then ignore...
		je	SHORT @diArgEOL
                cmp     al, LF
                je      SHORT @diArgEOL
		call	DoOption     ; check option, set any flags...
		jnc	SHORT @diArgumentLoop ;	if no error, continue...
		mov	ax, -1	     ; return(-1)
		retn
@diArgEOL:
		test	WORD [UserOptionFlags], ShowLicenseFlag
		jz	SHORT @diNoShowLic
                MPrintf LicenseText
@diNoShowLic:
                test    WORD [UserOptionFlags], SuppressTechie
                jnz     SHORT @diNoTechie
		Printf	rheader, cs, StartInstall
@diNoTechie:
; --------------------------------------------------------------------------
; Might be nifty to use a simple cipher or PRNG to fill the the bytes in
; the random and output pools.  See the comment in the TimerLatch routine.

  %if __Sample15
                InstallSampler 15h, _Multitask
  %endif
		InstallSampler MltplxSvc, _MultiplexServ
  %if __Sample09
		InstallSampler 9, _keysample
  %endif
  %if __Sample13
                cmp  BYTE [DosVersionMaj], 7
                jge  SHORT @NoDiskI
		InstallSampler 13h, _DskSample
                test WORD [UserOptionFlags], SampleDiskFlag
                jz   SHORT @NoDiskI
                or   WORD [Flags], flSamplDisk
  @NoDiskI:
  %endif
  %if __Sample08
                InstallSampler 1Ch, _timerlatch ; was Int 08 -v0.4.9
  %endif
  %if __Sample28
		InstallSampler 28h, _idlewait
  %endif
  %if __SamplExec | __DosSpinner
                InstallSampler 21h, _NewInt21
  %endif
; --------------------------------------------------------------------------
; This should be modified to search for free interrupts...

        cmp     BYTE [HookAPI], 2Dh ; find a free AMIS function
        jne     SHORT @notAMIS
; if might be better to set AL to [HookFunk] and search upwards until we
; get back to the value in [HookFunc] again, then return an error...
        xor     ax, ax
@chkAMIS:
        int     2Dh
        test    al, al
        jz      SHORT @freeAMIS
; (!) <---- check if AL=FFh, if so, no more free frunctions!
        inc     al
        jmp     SHORT @chkAMIS
@freeAMIS:
        mov     BYTE [HookFunc], al
@notAMIS:
; (!) The API should always be the LAST interrupt hook added!
        InstallSampler BYTE [HookAPI], NoiseHook
        mov     [FarCallAddr], cs

    Printf  NewLine
    xor  ax, ax
    mov  bx, ax
    mov  al, [HookAPI]
    mov  bl, [HookFunc]
    Printf bx, ax, msgAPI

  %if __SamplDrift
        test    WORD [UserOptionFlags], DriftFlag
        jz      SHORT @NoDrift1
        or      WORD [Flags], flSamplDrift
        Printf  msgDrift
@NoDrift1:
  %endif
  %if __SamplVideo
        test    WORD [UserOptionFlags], SampleVideoFlag
        jz      SHORT @NoVid1
        ; <---- We should test if proper video card exists
        or      WORD [Flags], flSamplVideo
        Printf  msgVideo
@NoVid1:
  %endif
  %if __Sample13
        test    WORD [UserOptionFlags], SampleDiskFlag
        jz      SHORT @NoDsk1
        Printf  msgDisk
@NoDsk1:
  %endif
  %ifdef __SamplMouse
        test    WORD [UserOptionFlags], MouseFlag
        jz      SHORT @NoMouse1
;        xor     ax, ax                  ; test if mouse is installed
;        int     33h
;        test    ax, ax
;        jz      SHORT @NoMouse1         ; (*) we should print an error
        or      WORD [Flags], flSamplMouse
        Printf  msgMouse
@NoMouse1:
  %endif
  %if __SamplAudio
        test    WORD [Flags], NoAudioFlag
        jnz     SHORT @diNoAudioMsg
        Printf  sbPort, AudioMsg
@diNoAudioMsg:
  %endif
        Printf  msgMethods

  %if (InitSeedCnt != 0) & (__Sample09) ;; initialize pool w/keystrks
; --------------------------------------------------------------------------
		mov	ax, WORD [SeedCount] ; seedcount set to 0?
		test	ax, ax
                jz      SHORT @NoSample
		Printf	SeedMessage	 ; if not, sample...
@Seedlings:
		mov	ax, [SeedCount]	       ; get count
		sub	ax, [FreshCount]	       ; compate to entropy (v0.4.3)
                js      SHORT @Seeded          ; if count==0, done
                mov     bx, [OutQueue]
                shl     bx, 3
  %if FRACBITS
		shr	ax, FRACBITS
  %endif
                sub     ax, bx
                js      SHORT @Seeded
		Printf	ax, DigitCount ; output	bits needed
		xor	ah, ah		       ; get keyboard character
		int	Keyboard

		cmp	ax, WORD [LastCode]  ; ignore	if triplets
		je	SHORT @IgnoreCode
		cmp	ax, WORD [LastCode+2]
		je	SHORT @IgnoreCode
		shl	DWORD [LastCode], 16 ; set last keys pressed
		mov	WORD [LastCode], ax
                call    TrackDeltas            ; add code to pool
@IgnoreCode:

		jmp	SHORT @Seedlings
@Seeded:
		Printf	OkMessage
@NoSample:
  %endif
                call    Sample ; add installation time (won't hurt)
		xor	ax, ax	     ; return 0	= ok
		retn

  %if InitSeedCnt
SeedCount:
    DW	0
LastCode:
    resw	2
SeedMessage:
    DB CR
    DB "We are going to seed the entropy pool with some truly random bits by", CR, LF
    DB "timing your keystrokes.  Please type until the counter reaches zero: ", 0
DigitCount:
    DB "%4d", 4	DUP (BackSpace), 0
OkMessage:
    times	6	DB ' '
    	DB 	 CR, LF, LF, "That's enough. Thank you.", CR, LF, 0
  %endif


msgMethods:
  %if __Sample09
    DB 254, " Sampling keystroke timings", CR, LF
  %endif
  %if (__SamplExec) & (__Sample21 == 0)
    DB 254, " Sampling DOS exec() & exit() timings", CR, LF
  %endif
  %if (__SamplFlush) & (__Sample21 == 0)
    DB 254, " Sampling DOS flush() timings", CR, LF
  %endif
  %if (__DosSpinner) | (__Sample21)
    DB 254, " Sampling access to DOS services (Int 21h)", CR, LF
  %endif
  %if (__MixAtTicks)
    DB 254, " Timer will be sampled during clock ticks", CR, LF
  %endif
    DB LF, 0
  %if __SamplDrift
msgDrift:
  DB 254, " Sampling clock drift", CR, LF, 0
  %endif
  %if __SamplVideo
msgVideo:
    DB 254, " Sampling vertical retrace intervals", CR, LF, 0
  %endif
  %if __Sample13
msgDisk:
    DB 254, " Sampling disk access timings", CR, LF, 0
  %endif
  %ifdef __SamplMouse
msgMouse:
    DB 254, " Sampling mouse movement & button-presses", CR, LF, 0
  %endif
  %if __SamplAudio
AudioMsg:
    DB 254, " Sampling audio card port %x", CR, LF, 0
  %endif

msgAPI:
    DB 254, " API installed at Int %x, Function %x", CR, LF, 0

%include "cpuid.inc"

; --------------------------------------------------------------------------
%substr date_mm_dd __?DATE?__ 6, -1
%substr date_yy __?DATE?__ 3, 2
%strcat date_mm_dd_yy date_mm_dd, "-", date_yy
InitMsg:  ; ----- Initial text messages and other stuff
        DB CR, LF, DrvName, " Version "
        DB ZChr+((NoiseVersion/256) & 15), DOT
        DB ZChr+((NoiseVersion & 255) >> 4), DOT
        DB ZChr+(NoiseVersion & 15), BetaChar
        DB " Build ", date_mm_dd_yy , " ", __?TIME?__
        DB CR, LF
        DB "by Robert Rothenburg Walking-Owl. Portions by Colin Plumb."
        DB CR, LF, "Copyright (C) 1995, 1996, 2004. All Rights Reserved.", CR, LF
        DB 0
; -----	This section is	for displaying warnings	when debug options enabled
NewLine:
  %if (NOHASH+NOMIX)
        db  CR, LF, BELL, 254, " WARNING: "
  %endif
  %if NOHASH
        db "Hashing is disabled. "
  %endif
  %if NOMIX
	db "Mixing is disabled.	"
  %endif
; -----	End warnings -----
        db CR, LF, 0
StartInstall:
        DB LF, 254, " Loaded at %4x:%4x "
	DB "Hooking interrupts:", 0
; --------------------------------------------------------------------------
LicenseText: 
     DB	LF
     DB '      Copyright (c) 1995, 1996, 2004, Robert Rothenburg Walking-Owl.', CR, LF
     DB '      (Portions by Colin Plumb.)  All rights reserved.', CR, LF
     DB '    ', CR, LF
     DB '      Redistribution and use in source and binary forms, with or without', CR, LF
     DB '      modification, are permitted provided that the following conditions', CR, LF
     DB '      are met:', CR, LF
     DB '    ', CR, LF
     DB '        * Redistributions of source code must retain the above copyright', CR, LF
     DB '          notice, this list of conditions and the following disclaimer.', CR, LF
     DB '    ', CR, LF
     DB '        * Redistributions in binary form must reproduce the above copyright', CR, LF
     DB '          notice, this list of conditions and the following disclaimer in', CR, LF
     DB '          the documentation and/or other materials provided with the', CR, LF
     DB '          distribution.', CR, LF
     DB '    ', CR, LF
     DB '        * Neither the names of the authors nor the names of its', CR, LF
     DB '          contributors may be used to endorse or promote products derived', CR, LF
     DB '          from this software without specific prior written permission.', CR, LF
     DB '    ', CR, LF
     DB '      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS', CR, LF
     DB '      "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT', CR, LF
     DB '      LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS', CR, LF
     DB '      FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE', CR, LF
     DB '      COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,', CR, LF
     DB '      INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,', CR, LF
     DB '      BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;', CR, LF
     DB '      LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER', CR, LF
     DB '      CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT', CR, LF
     DB '      LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN', CR, LF
     DB '      ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE', CR, LF
     DB '      POSSIBILITY OF SUCH DAMAGE.', CR, LF
     DB	0
