home *** CD-ROM | disk | FTP | other *** search
- page ,132
- title scrnsav2 : Screen Saver for PS/2
- ;
- ; Copyright (c) 1988 Alan Ballard
- ;
- ; This program is a TSR (Terminate and Stay Resident) utility
- ; "screen saver". It turns off the video after a specified period
- ; of inactivity (no keyboard or mouse action). Touching the keyboard or
- ; the mouse will reactivate the screen.
- ;
- ; A VGA monitor and the PS/2 extended bios are required.
- ;
- ; The program stays resident only the first time it is run. It may be reexecuted
- ; to disable blanking or to change the interval.
- ;
- ; Options are:
- ; integer - blanking time in minutes (default 5 minutes)
- ; \d - disable blanking
- ; \e - enable blanking (default)
- ; \m integer - set the "multiplex number" to use for communicating
- ; with the loaded version.
- ;
-
- ; Interrupt numbers
- Keyboard@ equ 09h
- Video_Io@ equ 10h
- System_Services@ equ 15h
- Timer@ equ 1ch
- Dos@ equ 21h
- Multiplex@ equ 2fh
- Mouse@ equ 74h
-
- ; Video I/O function numbers
- Read_Display_Combination_Code equ 1a00h
-
- ; System services function numbers
- Keyboard_Intercept equ 4fh
-
- ; Multiplex function numbers
- Get_Installed_State equ 0
-
- ; Scrnsav2 multiplex functions
- Scrnsav_Multiplex_Number equ 150 ; random choice
- Scrnsav_Disable equ 10h
- Scrnsav_Enable equ 11h
- Scrnsav_Set_Interval equ 12h
-
- ; DOS function numbers
- Print_String equ 09h
- Print_Char equ 02h
- Set_Int equ 25h
- Get_Int equ 35h
- TSR equ 31h
- Terminate equ 4ch
-
- ; Miscellaneous constants
- Ticks_Per_Minute equ 1092 ; 60*18.2
- Default_Time equ 5 ; five minute default
- Max_Time equ 30 ; 30 minute maximum (30*1092=32760)
-
- Cr equ 0dh
- Lf equ 0ah
-
- True equ 0ffh
- False equ 00h
-
- ; VGA adaptor constants
- SAR equ 03c4h ; Sequencer Address Register
- SDR equ 03c5h ; Sequencer Data Register
- Clocking_Mode_Index equ 01 ; SAR index for clocking mode reg
- Screen_Mask equ 20h ; Mask for screen off bit.
-
- Scrnsav2 segment para 'code'
- assume cs:Scrnsav2,ds:nothing,es:nothing
- ;
- ; Overlay permanent data on PSP.
- ;
- org 05ch ; not supposed to change anything before this
- Old_Mouse dd ? ; save old int 74 (mouse)
- Old_Timer dd ? ; save old timer tick
- Old_Ss dd ? ; save old system services
- Old_Multiplex dd ? ; save old multiplex
- ;
- Idle_Count dw ? ; Ticks till we shutdown
- Idle_Max dw ? ; Initial ticks
-
- Save_Reg db ? ; Place to save CRT register value
- Multiplex_No db ? ; Multiplex number we're using
- Disabled db ? ; enable/disable flag
-
- ;
- ; Define command line in PSP...
- ;
- org 080h
- Cmdline label byte
- page
- ; Code starts at offset 0100h for COM file.
- org 0100h ; beginning for .com programs
- Start: jmp Initialize ; initialization code is at end.
-
- ;
- ; int 15 (system services) enters here. Checks for keyboard intercept
- ; which shows some activity. Passed on to old interrupt routine in all
- ; cases.
- ;
- System_Services proc far
- cmp ah,Keyboard_Intercept
- jne NotKey
- call Action ; record something happenned
- NotKey: jmp Old_Ss ; pass it on to old routine
- System_Services endp
-
- ;
- ; int 74h (mouse) enters here. This also shows there is user activity.
- ;
- Mouse proc far
- call Action ; record something happenned
- jmp Old_Mouse ; pass it on
- Mouse endp
-
- ;
- ; Common processing for keyboard and mouse action.
- ; Reset timeout interval; turn screen back on if it was off.
- ;
- Action proc near
- push ax ; save a register
- cmp Idle_Count,0 ; have we reached zero
- jne Reset ; no, just reset count
-
- ; Count had reached zero, so we would have disabled the screen.
- ; Need to turn it back on here.
- push dx
- mov dx,SAR ; Get the current SDR index
- in al,dx ; ... value and save it
- push ax ; ...
- mov al,Clocking_Mode_Index ; Then point it to clocking mode
- out dx,al ; ... register.
- mov dx,SDR ; Set the clocking mode register
- mov al,Save_Reg ; ... back to what it was
- out dx,al
- mov dx,SAR ; Reset SAR to what it was
- pop ax ; ...
- out dx,al ; ...
- pop dx
-
- Reset: mov ax,Idle_Max ; reset count to max
- mov Idle_Count,ax ; ...
-
- pop ax ; restore
- ret ; return
-
- Action endp
-
- ;
- ; int 1ch (timer tick) enters here. If blanking enabled, decrement count
- ; and see if time to blank screen.
- ;
- Timer proc far
-
- cmp Disabled,True ; are we active?
- je Done ; no, quit
- cmp Idle_Count,0 ; already turned off?
- je Done ; ok, nothing to do
-
- dec Idle_Count ; subtract one...
- jnz Done ; quit if still nonzero
-
- ; Count has reached zero. Turn off the display.
- push dx
- push ax
- mov dx,SAR ; Get the current SDR index
- in al,dx ; ... value and save it
- push ax ; ...
- mov al,Clocking_Mode_Index ; Then point it to clocking mode
- out dx,al ; ... register.
- mov dx,SDR ; Get the clocking mode register
- in al,dx ; ...
- mov Save_Reg,al ; Save it away for later
- or al,Screen_Mask ; set the video off bit
- out dx,al ; ...
- mov dx,SAR ; Reset SAR to what it was
- pop ax ; ...
- out dx,al ; ...
- pop ax
- pop dx
-
- Done: jmp Old_Timer ; continue with other int routine.
- Timer endp
- page
- ;
- ; int 2fh (Multiplex) enters here. This is used for communication from
- ; later runs of Scrnsav2 program.
- ;
- Multiplex proc far
- cmp ah,Multiplex_No ; is this our number?
- je Mine ; yes,...
- jmp Old_Multiplex ; no, pass it on.
-
- Mine: cmp al,Get_Installed_State ; are we just testing?
- jne Mine2 ; work to do
-
- ; Set result to indicate installed. Also, pass back our name as further
- ; check for someone else using the number.
- mov al,0ffh ; code to say we're here
- push ds ; copy ds to es
- pop es ; ...
- lea di,es:Scrnsav_Str ; offset for our name
- iret ; return it to caller.
-
- ; Look for other function requests
- Mine2: cmp al,Scrnsav_Enable
- jne Mine3
- mov Disabled,False ; set enabled
- jmp Valid
-
- Mine3: cmp al,Scrnsav_Disable
- jne Mine4
- mov Disabled,True ; set disabled
- jmp Valid
-
- Mine4: cmp al,Scrnsav_Set_Interval
- jne Invalid
- mov Idle_Max,bx ; reset interval
-
- Valid: mov al,0 ; set success code
- iret
-
- Invalid: mov al,1 ; return error code
- iret
-
- Scrnsav_Str db "SCRNSAV2"
-
- Multiplex endp
- page
- ;
- ; Initialization. Print a greeting, process the parameters, determine
- ; whether already loaded, then either stay resident or communicate
- ; with resident version.
- ;
- Initialize proc near
- assume ds:Scrnsav2
- push bx ; save registers we use
- push cx
- push si
- push di
- push ds
- push es
- push dx
-
- push cs ; copy cs to ds.
- pop ds
-
- cld ; always want to increment
-
- mov dx,offset Greeting ; message address
- mov ah,Print_String ; function code
- int Dos@ ; write the message
-
- ; Determine if this will work on the machine we're running on.
- mov ax,Read_Display_Combination_Code ; function code
- int Video_Io@ ; Bios call
- cmp al,1ah ; is it supported?
- jne NoVGA ; nope; so wrong machine
- cmp bl,07h ; VGA mono?
- je HaveVGA ; ...
- cmp bl,08h ; VGA color?
- je HaveVGA ; ...
-
- NoVGA: mov dx,offset VGA_Message
- mov ah,Print_String ; function code
- int Dos@ ; write the message
- jmp Unload
-
- ;
- ; Process the parameters. Should be integer number of minutes,
- ; and/or /d (disable), /e (enable), /m <int>
- ;
- HaveVGA:
- mov si,offset Cmdline ; index of parameters
- lodsb ; pick up count and step
- mov ah,0 ; extend
- mov cx,ax ; copy to count register
- Next_Par:
- call Skipblanks ; find first character
- jnz Have_Par ; count reached zero
- jmp End_Pars
- Have_Par:
- cmp byte ptr [si],'/' ; option flag?
- jne Try_Int
- inc si ; step to flag char
- dec cx ; decrement count
- jz Bad_Flag ; missing flag spec
-
- cmp byte ptr [si],'d' ; test for disable flag
- je Disable
- cmp byte ptr [si],'D'
- jne Try_E ; not disable
- Disable: mov Par_Disable,True ; set the flag
- inc si ; step over it
- dec cx ; adjust count
- jmp Next_Par ; and look for more pars
-
- Try_E: cmp byte ptr [si],'e' ; test for enable flag
- je Disable
- cmp byte ptr [si],'E'
- jne Try_M ; not enable
- Enable: mov Par_Disable,False ; set the flag
- inc si ; step over it
- dec cx ; adjust count
- jmp Next_Par ; and look for more pars
-
- Try_M: cmp byte ptr [si],'m' ; test for m flag
- je M_Flag
- cmp byte ptr [si],'M'
- jne Bad_Flag ; invalid flag
- M_Flag: inc si ; step over it
- dec cx ; adjust count
- call Skipblanks ; need a following integer par
- jz Bad_M_Flag ; no following par
- call GetI ; find a number
- jo Bad_M_Flag ; it overflows
- jz Bad_M_Flag ; it wasn't there
- cmp ax,80h ; check the range
- jl Bad_M_Flag ; ... too small
- cmp ax,0ffh ; ...
- ja Bad_M_Flag ; ... too big
- mov Par_Multiplex_No,al ; just right
- jmp Next_Par ; look for more
-
- ; Not a flag; should be integer number of minutes.
- Try_Int:
- call GetI ; find a number
- jo Too_Big ; it overflowed
- jz Bad_Par ; not found
- cmp ax,Max_Time ; is it too big?
- ja Too_Big ; yes, don't allow.
- mov Par_Minutes,ax ; save it away
- mov Par_Set_Interval,True ; remember it was specified
- jmp Next_Par ; look for more
-
- ; Invalid flag; back up to the / character before echoing it.
- Bad_Flag:
- dec si ; back up one pos
- inc cx ; increase count
- Bad_Par: mov dx,offset Bad_Par_Message
- mov ah,Print_String ; function code
- int Dos@ ; write the message
- Echo: lodsb ; get next character
- cmp al,' ' ; stop at a blank
- je End_Echo
- mov dl,al ; and echo it
- mov ah,Print_Char ; ...
- int Dos@ ; ...
- loop Echo
- End_Echo:
- mov dx,offset Bad_Par_Message2
- mov ah,Print_String ; function code
- int Dos@ ; write the end of the message
- jmp Unload
-
- Too_Big: mov dx,offset Too_Big_Message
- mov ah,Print_String ; function code
- int Dos@ ; write the message
- jmp Unload
-
- Bad_M_Flag:
- mov dx,offset Bad_M_Flag_Message
- mov ah,Print_String ; function code
- int Dos@ ; write the message
- jmp Unload
-
- page
- ;
- ; Parameter processing finished.
- ;
- End_Pars:
- mov ax,Par_Minutes ; compute ticks required
- mul Ticks ; ...
- mov Par_Ticks,ax ; ...
-
- ;
- ; Determine whether already installed.
- ;
- mov ah,Par_Multiplex_No ; ask if already installed...
- mov al,Get_Installed_State ; ...
- int Multiplex@ ; ...?
- cmp al,0 ; is it installed?
- je Install ; no, go do it
- cmp al,0ffh ; seems to be, make sure
- jne Cant_Install ; something wrong
- ; Last test: if it is installed, should get back es:di pointing to
- ; our name.
- lea si,Scrnsav_Str
- mov cx,size Scrnsav_Str
- repnz cmpsb ; compare the bytes
- jne Cant_Install
-
- ;
- ; Seems to be already installed, so pass across requested state.
- ;
- mov ah,Par_Multiplex_No ; First set enabled/disabled.
- mov al,Scrnsav_Enable ; assume enabling
- cmp Par_Disable,True ; are we really?
- jne Send_Enable ; ...
- mov al,Scrnsav_Disable ; ... nope
- Send_Enable:
- int Multiplex@ ; Send it to resident copy.
- cmp al,0 ; check for problems
- jne Cant_Change
-
- cmp Par_Set_Interval,True ; Do we want to change interval?
- jne No_Change
- mov ah,Par_Multiplex_No ; yes, set up parameters
- mov al,Scrnsav_Set_Interval ; ...
- mov bx,Par_Ticks ;...
- int Multiplex@ ; Send it to resident copy.
- cmp al,0 ; check for problems
- jne Cant_Change
-
- ;
- ; Write out what we did.
- ;
- No_Change:
- mov ax,offset Null_Message ; no "installed and" part
- call Write_Status ; call common routine
- jmp Unload_Ok ; and terminate
-
- ;
- ; Problems
- ;
- Cant_Install:
- mov dx,offset Cant_Install_Message
- mov ah,Print_String ; function code
- int Dos@ ; write the message
- jmp Unload
-
- Cant_Change:
- mov dx,offset Cant_Change_Message
- mov ah,Print_String ; function code
- int Dos@ ; write the message
- jmp Unload
-
- page
-
- ;
- ; Appears to be OK to install, so lets do so.
- ;
- Install:
- mov al,Par_Disable ; Set enable/disable state
- mov Disabled,al ; ...
- mov ax,Par_Ticks ; And interval
- mov Idle_Count,ax ; ...
- mov Idle_Max,ax ; ...
- mov al,Par_Multiplex_No ; and multiplex number
- mov Multiplex_No,al ; ...
-
- ;
- ; Set up the interrupt vectors
- ;
- mov ah,Get_Int
- mov al,System_Services@ ; Get int 15.
- int Dos@
- mov Old_Ss,bx ; Save it away
- mov Old_Ss+2,es
- mov ah,Set_Int
- mov al,System_Services@ ; Set new int 15.
- mov dx,offset System_Services
- int Dos@ ; ...
-
- mov ah,Get_Int
- mov al,Mouse@ ; Get int 74.
- int Dos@
- mov Old_Mouse,bx ; Save it away
- mov Old_Mouse+2,es
- mov ah,Set_Int
- mov al,Mouse@ ; Set new int 74
- mov dx,offset Mouse
- int Dos@ ; ...
-
- mov ah,Get_Int
- mov al,Multiplex@ ; Get int 2f.
- int Dos@
- mov Old_Multiplex,bx ; Save it away
- mov Old_Multiplex+2,es
- mov ah,Set_Int
- mov al,Multiplex@ ; Set new int 2f
- mov dx,offset Multiplex
- int Dos@ ; ...
-
- mov ah,Get_Int
- mov al,Timer@ ; Get int 1c
- int Dos@
- mov Old_Timer,bx ; Save it away
- mov Old_Timer+2,es
- mov ah,Set_Int
- mov al,Timer@ ; Set new int 1c.
- mov dx,offset Timer
- int Dos@ ; ...
-
- ;
- ; Put out a message saying what we did.
- ;
- mov Par_Set_Interval,True ; always include the interval
- mov ax,offset Installed_Message
- call Write_Status ; call common code
-
- ;
- ; Terminate and stay resident.
- ;
- mov ah,TSR ; terminate/stay resident
- mov al,0 ; ... with exit code 0
- pop dx ; pop this off here... we don't restore it
- mov dx,((offset Initialize - offset Scrnsav2) + 15)/16
- jmp Return
-
- ; Terminate and unload (OK)
- Unload_Ok:
- mov al,00h ; Error code 0
- jmp Unload2 ; merge
-
- ; Terminate and unload with error code.
- Unload: mov al,01h ; with error code 1
- Unload2: mov ah,Terminate ; terminate
- pop dx ; restore dx
-
- Return:
- pop es
- pop ds
- pop di
- pop si
- pop cx ; restore registers
- pop bx
- int Dos@ ; back to DOS.
- Initialize endp
- page
- ;
- ; Write_Status writes a message saying what we did.
- ;
- ; At entry: ax = message "installed and" if required.
- ;
- Write_Status proc near
- push dx ; save reg we clobber
- push ax ; save parameter
- mov dx,offset Status_Message ; "Screen saver "
- mov ah,Print_String
- int Dos@
-
- pop dx ; "installed and "
- mov ah,Print_String
- int Dos@
-
- mov dx,offset Enabled_Message ; "enabled"
- cmp Par_Disable,True
- jne Ws_Enable
- mov dx,offset Disabled_Message ; "disabled"
- Ws_Enable:
- mov ah,Print_String
- int Dos@
-
- cmp Par_Set_Interval,True
- jne Ws_Done
-
- mov dx,offset Lpar_Message ; " ("
- mov ah,Print_String
- int Dos@
-
- mov ax,Par_Minutes ; <integer>
- call WriteI
-
- mov dx,offset Rpar_Message ; " minutes)"
- mov ah,Print_String
- int Dos@
-
- Ws_Done:
- mov dx,offset End_Message ; "."
- mov ah,Print_String
- int Dos@
-
- pop dx ; restore reg
- ret
-
- Write_Status endp
-
- page
- ;
- ; Skipblanks skips over blanks and returns at non blank.
- ;
- ; At entry: si = index of first byte to check
- ; cx = count of characters in string
- ;
- ; At return: si = index of non blank
- ; cx = remaining characters
- ; z bit = clear if non blank found
- ; = set if no nonblanks
- ;
- ; (Could do this with a rep scsb instruction, but setting it up
- ; is more hassle than its worth...)
- ;
- Skipblanks proc near
-
- Sb_Loop:
- cmp cx,0 ; any charaters left?
- je Sb_Ret ; nope
- cmp byte ptr [si],' ' ; is it blank?
- jne Sb_Ret ; nope, found something
- inc si ; step to next
- dec cx ; decrement count
- jmp Sb_Loop ; ... and continue
- Sb_Ret:
- ret
- Skipblanks endp
- page
- ;
- ; GetI converts an ascii string to an integer. It returns
- ; on encountering a non-digit.
- ;
- ; At entry: si = index of first byte to convert
- ; cx = count of characters in string
- ;
- ; At return: si = index of first non digit
- ; cx = remaining characters
- ; ax = converted integer
- ; o bit is set if result overflows a single register
- ; z bit = clear if integer found
- ; = set if no integer
- ;
- GetI proc near
- push bx
- push dx
- push cx ; copy cx for testing at end
- cmp cx,0 ; see if we have any characters
- jz Gi_Ret ; ... and return if not.
-
- mov ax,0 ; initialize result in ax
- Gi_Loop: mov bl,[si] ; pick up a byte
- cmp bl,'0' ; check it is in range
- jb Gi_Ret ; ...
- cmp bl,'9' ; ...
- ja Gi_Ret ; ...
- inc si ; step to next character
-
- mul Ten ; accumulate result in ax/dx
- jo Gi_RetO ; overflowed
- sub bl,'0' ; convert digit to 0 ... 9
- mov bh,0 ; ... word value
- add ax,bx ; add to result so far
- jo Gi_RetO ; overflowed
- loop Gi_Loop ; decrement count and continue
- jmp Gi_Ret ; merge below
-
- Gi_RetO: pop bx ; pop off saved cx
- jmp Gi_Ret2 ; merge below
-
- Gi_Ret: pop bx ; pop back saved cx
- cmp bx,cx ; and set z bit to whether we found num
- Gi_Ret2: pop dx ; restore regs (z or o bits set)
- pop bx ; ...
- ret
- GetI endp
-
- page
- ;
- ; WriteI converts a positive, word, integer to characters and writes
- ; them to stdout. It uses recursion to emit the digits in the
- ; right order.
- ;
- ; At entry: ax = number to convert
- ;
- WriteI proc near
- push dx ; save reg we use
- cmp ax,10 ; more than one digit?
- jb Wi_Digit ; nope, just do the digit
-
- mov dx,0 ; extend the dividend
- div Ten ; quot-> ax, rem-> dx
- call WriteI ; handle the quotient
- mov ax,dx ; followed by the remainder
-
- Wi_Digit:
- add al,'0' ; convert digit to char
- mov dl,al ; and write it out...
- mov ah,Print_Char
- int Dos@
-
- pop dx ; restore
- ret ; and return
-
- WriteI endp
- page
- ;
- ; Data area used during option parsing.
- ;
- Par_Disable db False ; Flags for options ...
- Par_Set_Interval db False ; ... specified
- Par_Multiplex_No db Scrnsav_Multiplex_Number ; default number to use
- Par_Minutes dw Default_Time ; interval in minutes
- Par_Ticks dw ? ; interval in ticks
-
- ; Constants for mul/div instructions
- Ticks dw Ticks_Per_Minute
- Ten dw 10
-
- ; Message emitted
- Greeting db 'Scrnsav2 version 2.0. (c) Alan Ballard 1988.',Cr,Lf,'$'
- VGA_Message db Cr,Lf,'PS/2 with VGA adaptor is required.',Cr,Lf,'$'
- Bad_Par_Message db Cr,Lf,'Invalid command parameter: "$'
- Bad_Par_Message2 db '".',Cr,Lf
- db ' Parameters are',Cr,Lf
- db ' integer (number of minutes till blanking)',Cr,Lf
- db ' /d (disable blanking)',Cr,Lf
- db ' /e (enable blanking)',Cr,Lf
- db ' /m integer (change multiplex number used)',Cr,Lf
- db '$'
- Too_Big_Message db Cr,Lf,'Blanking time too big. Maximum is 30.',Cr,Lf, '$'
- Bad_M_Flag_Message db Cr,Lf,'Invalid /m option. Must be followed by '
- db 'number between 128 and 255.',Cr,Lf,'$'
- Cant_Install_Message db Cr,Lf,"Can't install SCRNSAV2. "
- db 'Try a different "multiplex number" (/m option).',Cr,Lf,'$'
- Cant_Change_Message db Cr,Lf,"Problems communicating with installed SCRNSAV2. "
- db 'Try a different "multiplex number" (/m option).',Cr,Lf,'$'
-
- Status_Message db 'Screen saver $'
- Installed_Message db 'installed and $'
- Null_Message db '$'
- Enabled_Message db 'enabled$'
- Disabled_Message db 'disabled$'
- Lpar_Message db ' ($'
- Rpar_Message db ' minutes)$'
- End_Message db '.',Cr,Lf,'$'
-
- Scrnsav2 ends
-
-
- end Start