; MyMouse, Retrace/Clock control, Copr. 1994 Matthias K”ppe

		INCLUDE	mymodef.asm

DATA		SEGMENT WORD PUBLIC

ClockCount	DW	?
MaxDelay	DD	?
ClockFlag	DB	?
YDivisor	DW	?

DATA		ENDS

CODE		SEGMENT BYTE PUBLIC

		PUBLIC	DoSetRetrace, SetRetrace, HandleRetrace, \
			WaitRetrace, DoSetClock, SetClock, \
			HandleClock, CalcYDivisor

;
; Vertical retrace interrupt processing
;

	; Switches the retracing interrupt on or off.
	; This routine keeps all adaptor register.
	;
	; In:	BL	state to be set

DoSetRetrace	PROC NEAR
		mov	dx, 03D4h		; CRTC index
		in	al, dx
		mov	ah, al			; save index
		mov	al, 11h			; end vertical retrace
		out	dx, al
		inc	dx			; CRTC data
		in	al, dx
		and	al, 11101111b		; clear bit 4
		cmp	bl, 0
		jz	SHORT @@1
		or	al, 00010000b		; set bit 4
@@1:		out	dx, al
		dec	dx
		mov	al, ah
		out	dx, al			; set former index
		retn
DoSetRetrace	ENDP

	; This is a Pascal interface to DoSetRetrace.

SetRetrace	PROC NEAR
		ARG	on: BYTE: 2 = ArgSize
		push	bp
		mov	bp, sp
		mov	bl, on
		call	DoSetRetrace
		pop	bp
		retn	ArgSize
SetRetrace	ENDP

	; This is the Vertical Retrace interrupt handler.

HandleRetrace	PROC FAR
		push	ds ax bx dx
		MOV	AX, SEG DATA
		MOV	DS, AX

		MOV	DX, 03C2H		; input state #0
		IN	AL, DX
		TEST	AL, 80H
		JZ	SHORT @@1		; no adaptor request

		mov	bl, 0
		call	DoSetRetrace
		cmp	Update, 0
		jz	SHORT @@1

		mov	ax, YEnd
		or	ax, ax
		jz	SHORT @@1

		add	ax, 100

		push	es cx si di bp
		xor	dx, dx
		div	YDivisor
		mov	ClockCount, ax
		mov	bl, 1			; start clock
		call	DoSetClock

;		call	DoUpdateMouse		; that would be the direct way

		pop	bp di si cx es

@@1:		pop	dx bx ax
		PUSHF
		CALL	SavedRetrace
		POP	DS
		IRET
HandleRetrace	ENDP

	; Waits for the vertical retrace period.

WaitRetrace	PROC NEAR
		mov	dx, 03DAh
@@0:		in	al, dx
		test	al, 8			; wait for low
		jnz	@@0
@@1:		in	al, dx
		test	al, 8			; wait for high
		jz	@@1
		retn
WaitRetrace	ENDP

;
; Real-time clock interrupt processing
;

	; Switches the real-time clock interrupt on or off.
	;
	; In:	BL	state to be set

DoSetClock	PROC NEAR
		push	bx
		mov	ax, 8301h
		int	15h
		pop	ax
		xor	al, 1
		jnz	@@1
		mov	ah, 83h
		mov	cx, WORD PTR MaxDelay[2]
		mov	dx, WORD PTR MaxDelay[0]
		mov	bx, ds
		mov	es, bx
		mov	bx, OFFSET ClockFlag
		mov	BYTE PTR [bx], 0
		int	15h
@@1:		retn
DoSetClock	ENDP

	; This is a Pascal interface to DoSetClock.

SetClock	PROC NEAR
		ARG	on: BYTE: 2 = ArgSize
		push	bp
		mov	bp, sp
		mov	bl, on
		call	DoSetClock
		pop	bp
		retn	ArgSize
SetClock	ENDP

	; This is the clock interrupt handler.

HandleClock     PROC FAR
		push	ds
		push	SEG DATA
		pop	ds
		dec	ClockCount
		jne	SHORT @@1
		push	es
		pusha
		mov	bl, 0
		call	DoSetClock		; switch clock off
		call	DoUpdateMouse		; update the mouse
		popa
		pop	es
@@1:            pushf
		call	SavedClock
		pop	ds
		iret
HandleClock	ENDP

;
; Vertical retrace interval measurement
;

MaxCount	EQU	128			; half a second
Loops		EQU	4

MeasureRetrace	PROC NEAR
		mov	WORD PTR MaxDelay[0], 0
		mov	WORD PTR MaxDelay[2], 2
		mov	ClockCount, MaxCount
		call	WaitRetrace
		mov	bl, 1
		call	DoSetClock
		mov	cx, Loops
@@1:		call	WaitRetrace
		loop	@@1
		mov	bl, 0
		call	DoSetClock
		mov	ax, MaxCount
		sub	ax, ClockCount
		retn
MeasureRetrace	ENDP

CalcYDivisor	PROC NEAR
		call	MeasureRetrace
		or	ax, ax
		jnz	SHORT @@0
@@1:		mov	TimingState, 0		; timing not functionable
		retn
@@0:            mov	si, SizeY
		FASTIMUL si, si, Loops		; SizeY is a close approx
		xchg	ax, si
		mov	dx, 0
		div	si
		mov	YDivisor, ax
		or	ax, ax
		jz	@@1
		retn
CalcYDivisor	ENDP

CODE		ENDS

		END
