	NAME		HZPCSAVE
	PAGE		55,132
        TITLE           'SCREEN SAVER FOR HZ150 PC SERIES'
;
;  SCRNSAVE patched for Heath/Zenith 150 PC series
;----------------------------------------------------------------------;
;  This program was written by John Socha and published in SOFTALK for ;
;  the IBM Personal Computer, December 1983.  The program turns the    ;
;  screen display off after 3 minutes of no activity (ie: no data is   ;
;  sent to the screen).  Pressing any key will reactivate the screen   ;
;  display.							       ;
;								       ;
;  This version has been patched by Mike Berman to operate on the      ;
;  Heath/Zenith 150 PC series.	The video board on these computers     ;
;  has been enhanced to stop blinking when scrolling, but this	       ;
;  required an additional video register at port 3DA; when bit 0 of    ;
;  this register is enabled, the bit used to turn off the screen by    ;
;  the original version of this program is overriden, and nothing      ;
;  happens.							       ;
;								       ;
;  CAVEAT: Since I don't know how to find the current contents of      ;
;  the 3DA port, this program assumes that all other bits = 0, which   ;
;  apparently is the default.  If this is not true, the screen may     ;
;  be restored to a different state than when it was blanked.  This    ;
;  doesn't cause problems with the software I use, but users of this   ;
;  routine should be aware of it.				       ;
;								       ;
;  ACKNOWLEDGEMENT: Thanks to Dave Tweten for explaining it.	       ;
;----------------------------------------------------------------------;
;
;----------------------------------------------------------------------;
;  These are the interrupt vectors for the clock, keyboard and video   ;
;  io calls.							       ;
;----------------------------------------------------------------------;
;
VECTORS 		SEGMENT AT 0H
	ORG		8H*4
TIME_OF_DAY_VECTOR	LABEL	DWORD ;Clock interrupt, 18.2 per sec
	ORG		9H*4
KEYBOARD_INT_VECTOR	LABEL	DWORD
	ORG		10H*4
VIDEO_IO_VECTOR 	LABEL	DWORD
VECTORS 		ENDS
;
;----------------------------------------------------------------------;
;  This is the data area starting at 400H used by the ROM BIOS	       ;
;  routines.  ADDR_6845 contains the base address, 3x4, of the current ;
;  display adapter and CRT_MODE_SET contains the current setting of    ;
;  display mode -- the 3x8 register.  The x is B for the monochrome    ;
;  display adapter, and D for the color-graphics adapter.	       ;
;----------------------------------------------------------------------;
;
ROM_BIOS_DATA		SEGMENT AT 40H
	ORG		10H
EQUIP_FLAG		DW	?	;Used to determine display type
	ORG		60H
CURSOR_MODE		DW	?	;Current cursor mode (start, stop line)
	ORG		63H
ADDR_6845		DW	?	;Base address for active display card
CRT_MODE_SET		DB	?	;Current setting of 3x8 register
ROM_BIOS_DATA		ENDS
;
;----------------------------------------------------------------------;
;  This is the start of the local data and executable code.	       ;
;----------------------------------------------------------------------;
;
CODE_SEG		SEGMENT
	ASSUME		CS:CODE_SEG
	ORG		100H
BEGIN:	JMP		INIT_VECTORS	;Initialize vectors and attach to DOS
;
ROM_TIME_OF_DAY_INT	DD		;Addresses for ROM routines
ROM_KEYBOARD_INT	DD
ROM_VIDEO_IO_INT	DD
TIMER_DELAY		DW	0CCCH	;Delay before turning off video
THREE_MIN_COUNTER	DW	?	;Clock ticks in 3 minutes
OLD_CURSOR_TYPE 	DW	0	;Hold the old cursor type
;
;----------------------------------------------------------------------;
;  Turn the video display off after three minutes of no use.	       ;
;								       ;
;  Calls:	ROM_TIME_OF_DAY_INT				       ;
;  Reads:	ADDR-6845, CRT_MODE_SET 			       ;
;  Writes:	THREE_MIN_COUNTER, OLD_CURSOR_TYPE		       ;
;----------------------------------------------------------------------;
;
INTERCEPT_TIME_OF_DAY	PROC	NEAR
	PUSH	AX
	PUSH	DS
	MOV	AX,CS			;Set data segment to current segment
	MOV	DS,AX
	ASSUME	DS:CODE_SEG
	DEC	THREE_MIN_COUNTER	;Have 3 minutes elapsed?
	JZ	TURN_VIDEO_OFF		;Yes, turn video off
	JG	GOTO_ROM_TIME_OF_DAY	;No, keep video on
	MOV	THREE_MIN_COUNTER,0	;Video is off, reset counter to 0 again
GOTO_ROM_TIME_OF_DAY:
	POP	DS
	POP	AX
	ASSUME	DS:NOTHING
	JMP	ROM_TIME_OF_DAY_INT
TURN_VIDEO_OFF:
	ASSUME	DS:CODE_SEG
	PUSH	BX
	PUSH	CX
	PUSH	DX
	MOV	AH,3			;Get current cusor type into CX
	PUSHF				;Push flags to simulate INT with CALL
	CALL	ROM_VIDEO_IO_INT	;Must use CALL since INT 10 points here
	MOV	OLD_CURSOR_TYPE,CX	;And save it
	MOV	CH,0FH			;Now remove cursor from screen
	MOV	CL,0
	MOV	AH,1
	PUSHF				;Push flags to simulate INT with CALL
	CALL	ROM_VIDEO_IO_INT	;Must use CALL since INT 10 points here
	POP	DX
	POP	CX
	POP	BX
	PUSH	DX			;Turn the display video off
	MOV	AX,ROM_BIOS_DATA
	MOV	DS,AX
	ASSUME	DS:ROM_BIOS_DATA
	MOV	DX,ADDR_6845		;Get base address for display adapter
	ADD	DX,4			;IO address for 3x8 register
	MOV	AL,CRT_MODE_SET
	AND	AL,0F7H 		;Turn video off
	OUT	DX,AL
;----------------------------------------------------------------------;
;	  HZ 150 PC Patch Starts Here				       ;
;----------------------------------------------------------------------;
	MOV	DX,3DAH 		;Auxiliary video register on HZ309 card
	MOV	AL,0
	OUT	DX,AL			;Turn off Video Enable Override
;----------------------------------------------------------------------;
;	  END of Patch						       ;
;----------------------------------------------------------------------;
	POP	DX
	JMP	GOTO_ROM_TIME_OF_DAY
;
INTERCEPT_TIME_OF_DAY	ENDP
;
;----------------------------------------------------------------------;
;  This procedure resets the timer count to 0CCCH and turns the        ;
;  display on if it was off.					       ;
;----------------------------------------------------------------------;
;
RESET_COUNTER	PROC	NEAR
	PUSH	AX
	PUSH	DX
	PUSH	DS
	MOV	AX,CS
	MOV	DS,AX
	ASSUME	DS:CODE_SEG
	CMP	THREE_MIN_COUNTER,0	;Was the display off?
	JG	VIDEO_NOT_OFF		;No, then just reset counter
	PUSH	DS			;Yes, then turn video back on
	MOV	AX,ROM_BIOS_DATA
	MOV	DS,AX
	ASSUME	DS:ROM_BIOS_DATA
	MOV	DX,ADDR_6845		;Get base address for display adapter
	ADD	DX,4			;IO address for 3x8 register
	MOV	AL,CRT_MODE_SET
	OR	AL,8			;Turn video on again
	OUT	DX,AL
;----------------------------------------------------------------------;
;	  HZ 150 PC Patch Starts Here				       ;
;----------------------------------------------------------------------;
	MOV	DX,3DAH 		;Auxiliary video register on HZ309 card
	MOV	AL,1
	OUT	DX,AL			;Turn on Video Enable Override
;----------------------------------------------------------------------;
;	  END of Patch						       ;
;----------------------------------------------------------------------;
	POP	DS
	ASSUME	DS:CODE_SEG
	PUSH	CX			;Now restore the cursor
	MOV	CX,OLD_CURSOR_TYPE
	MOV	AH,1			;Restore the old cursor type
	PUSHF				;Push flags to simulate INT with CALL
	CALL	ROM_VIDEO_IO_INT	;Must use CALL since INT 10 points here
	POP	CX
VIDEO_NOT_OFF:
	MOV	AX,TIMER_DELAY
	MOV	THREE_MIN_COUNTER,AX
	POP	DS
	POP	DX
	POP	AX
	RET
RESET_COUNTER	ENDP
;
INTERCEPT_KEYBOARD_INT	PROC	NEAR
	ASSUME	DS:NOTHING
	CALL	RESET_COUNTER		;Reset the time out counter
	JMP	ROM_KEYBOARD_INT	;Pass control to ROM routine
INTERCEPT_KEYBOARD_INT	ENDP
;
;----------------------------------------------------------------------;
;  This procedure resets the cursor type to the default type for the   ;
;  display adapter in use: 607H for the color/graphics adapter and     ;
;  0C0BH for the monochrome display adapter.			       ;
;----------------------------------------------------------------------;
;
SET_CURSOR_MODE 	PROC	NEAR
	PUSH	AX
	PUSH	CX
	PUSH	DS
	MOV	AX,ROM_BIOS_DATA
	MOV	DS,AX			;Point to ROM BIOS data area
	ASSUME	DS:ROM_BIOS_DATA
	MOV	AX,EQUIP_FLAG		;Determine which adapter is active
	AND	AL,30H			;Isolate adapter information
	MOV	CX,607H 		;Set for color/graphics adapter
	CMP	AL,30H			;Is monochrome display adapter active?
	JNE	COLOR_ACTIVE		;No, set cursor type
	MOV	CX,0B0CH		;Cursor mode for monochrome display
COLOR_ACTIVE:
	MOV	AH,1
	PUSHF				;Simulate INT 10 with PUSHF and CALL
	CALL	ROM_VIDEO_IO_INT
	POP	DS
	POP	CX
	POP	AX
	RET
SET_CURSOR_MODE 	ENDP
;
;----------------------------------------------------------------------;
;  This procedure resets the time-out counter, and passes control on   ;
;  to the ROM VIDEO_IO routines.				       ;
;----------------------------------------------------------------------;
;
INTERCEPT_VIDEO_IO	PROC	NEAR
	ASSUME	DS:NOTHING
	CALL	RESET_COUNTER		;Reset time-out counter
	PUSHF				;Simulate INT 10 with PUSHF and CALL
	CALL	ROM_VIDEO_IO_INT	;Do VIDEO_IO function
	OR	AH,AH			;Asking for set-mode function?
	JNZ	NOT_MODE_SET		;No, then return
	CALL	SET_CURSOR_MODE 	;Yes, then set cursor mode to default
;
NOT_MODE_SET:
	IRET
;
INTERCEPT_VIDEO_IO	ENDP
;
;----------------------------------------------------------------------;
;  This procedure initializes the interrupt vectors.		       ;
;----------------------------------------------------------------------;
;
INIT_VECTORS		PROC	NEAR
	ASSUME	DS:VECTORS
	MOV	AX,VECTORS		;Set up the data segment for vectors
	MOV	DS,AX
        CLI                               ;Don't allow interrupts
	MOV	AX,word ptr TIME_OF_DAY_VECTOR	  ;Save addresses of BIOS routines
	MOV	word ptr ROM_TIME_OF_DAY_INT,AX
	MOV	AX,word ptr TIME_OF_DAY_VECTOR[2]
	MOV	word ptr ROM_TIME_OF_DAY_INT[2],AX
	MOV	word ptr TIME_OF_DAY_VECTOR,OFFSET INTERCEPT_TIME_OF_DAY
	MOV	word ptr TIME_OF_DAY_VECTOR[2],CS
;
	MOV	AX,word ptr KEYBOARD_INT_VECTOR
	MOV	word ptr ROM_KEYBOARD_INT,AX
	MOV	AX,word ptr KEYBOARD_INT_VECTOR[2]
	MOV	word ptr ROM_KEYBOARD_INT[2],AX
	MOV	word ptr KEYBOARD_INT_VECTOR,OFFSET INTERCEPT_KEYBOARD_INT
	MOV	word ptr KEYBOARD_INT_VECTOR[2],CS
;
	MOV	AX,word ptr VIDEO_IO_VECTOR
	MOV	word ptr ROM_VIDEO_IO_INT,AX
	MOV	AX,word ptr VIDEO_IO_VECTOR[2]
	MOV	word ptr ROM_VIDEO_IO_INT[2],AX
	MOV	word ptr VIDEO_IO_VECTOR,OFFSET INTERCEPT_VIDEO_IO
	MOV	word ptr VIDEO_IO_VECTOR[2],CS
;
	MOV	AX,TIMER_DELAY		;Set the delay to 3 minutes
	MOV	THREE_MIN_COUNTER,AX
;
	STI				;Allow interrupts again
	CALL	SET_CURSOR_MODE 	;Set cursor mode to default
	MOV	DX,OFFSET INIT_VECTORS	;End of resident portion
	INT	27H			;Terminate but stay resident
INIT_VECTORS		ENDP
;
CODE_SEG		ENDS
;
	END		BEGIN
