	.xlist
	include mdef
	page	63,132
	.ilist
; MSWAIT: Wait up to 30000 milliseconds
; July 1992, Steve D. @ Vertrauen 714 529-9547

	setmod	%mm			;set memory model
	public	_mswait,_mswtyp

	.data
_mswtyp	db	0			;system type for idle loop
dosidl	equ	1			;use int 28h
os2idl	equ	2			;use int 2fh function 1680h
	.code
clkvct	dd	0			;saved int 1ch vector
brkvct	dd	0			;saved int 1bh vector
waitct	dw	0			;local 8254 tick count
cbrk	db	0			;ctrl-break key pressed

clkisr	proc				;interrupt 1ch (55ms tick) service routine
	dec	mw cs:waitct
	jmp	ml cs:clkvct		;exec prior service routine
clkisr	endp

brkisr	proc				;interrupt 1bh (ctrl-break) service routine
	mov	mb cs:cbrk,-1		;ctrl-break depressed, set abort flag
	jmp	ml cs:brkvct		;exec prior service routine
brkisr	endp

_mswait	proc
	push	bp
	mov	bp,sp

	mov	al,mb _mswtyp
	push	ax			;wait type flag at [bp-2]

	push	es
	push	ds

	mov	ax,351bh
	int	21h			;get ctrl-break vector
	mov	mw cs:brkvct,bx
	mov	mw cs:brkvct+2,es	;save old service routine address

	mov	mb cs:cbrk,0		;clear abort flag
	mov	ah,25h
	push	cs
	pop	ds			;data segment is now inaccessible
	mov	dx,os brkisr
	int	21h			;set new interrupt service routine

	mov	ax,30000		;maximal wait
	mov	dx,pb[bp]		;wait time in milliseconds
	cmp	ax,dx
	jc	@f
	xchg	ax,dx			;within range, use specification
@@:	xor	dx,dx			;milliseconds in dx:ax
	sub	ax,10			;0-64 yields 55
	ja	@f
	mov	ax,dx			;must be at least 0
@@:	mov	cx,55			;milliseconds per ctc interrupt
	div	cx
	mov	mw cs:waitct,ax		;number of ctc interrupts to wait

	pushf				;detect cpu type
	mov	ax,4000h
	push	ax
	popf
	pushf
	pop	ax
	popf
	and	ah,0c0h
	js	msxt			;80186 or earlier
	jz	msxt			;80286

	.386				;80386
	pushad
	mov	ax,2b01h		;set date (get desqview version)
	mov	cx,4445h		;DE
	mov	dx,5351h		;SQ
	int	21h
	not	al			;zero if desqview not running
	mov	mb -1[bp],al

	xor	cx,cx			;running count in cx
	mov	ax,40h
	mov	es,ax
	mov	bx,6ch			;address bios clock

stwt:	mov	edx,ml es:[bx]
lpwt:	test	cs:cbrk,-1
	jnz	s mabt			;exit on ctrl-break
	push	edx
	test	mb -1[bp],-1
	jz	s @f			;not under desqview
	mov	ax,1000h
	int	15h			;surrender time slice, desqview
	jmp	s ckwt			;continue
@@:	test	mb -2[bp],os2idl
	jz	s ckwt			;no int 2fh call
	mov	ax,1680h
	int	2fh			;surrender time slice, os/2
ckwt:	test	mb -2[bp],dosidl
	jz	s @f			;no int 28h call
	int	28h			;idle
@@:	pop	edx
	mov	eax,ml es:[bx]
	mov	esi,eax			;save latest clock value
	sub	eax,edx
	jz	lpwt			;wait for clock change
	jc	stwt			;crossed midnight, reset
	mov	edx,esi			;set most current value
	cmp	eax,7fh
	jnc	s mabt			;swapped out more than 7 seconds
	add	cx,ax			;add to running total
	cmp	cx,cs:waitct		;static maximal value
	jna	lpwt			;not expired, continue

mabt:	popad
	mov	ax,386			;for test purposes
	test	mb -1[bp],-1
	jz	s msex
	mov	ax,10386
	jmp	s msex

msxt:	.8086
	mov	ax,351ch
	int	21h			;get int 1ch vector
	mov	mw cs:clkvct,bx
	mov	mw cs:clkvct+2,es	;save old service routine address

	mov	ah,25h
	push	cs
	pop	ds
	mov	dx,os clkisr
	int	21h			;set new interrupt service routine

mswl:	test	cs:cbrk,-1
	jnz	@f			;exit on ctrl-break
	mov	ax,cs:waitct
	or	ax,ax
	jns	mswl			;wait for negative count

@@:	mov	ax,251ch
	lds	dx,cs:clkvct
	int	21h			;restore old clock sr vector
	xor	ax,ax			;return zero
msex:	push	ax
	mov	ax,251bh
	lds	dx,cs:brkvct
	int	21h			;restore old ctrl-break sr vector
	pop	ax
	pop	ds
	pop	es
	pop	bx			;wait type flag
	pop	bp
	ret
_mswait	endp
	end
