/*
 * wait.S86  -  waiting routines
 *
 * Copyright (C) 2003-2007 Gero Kuhlmann   <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: wait.S86,v 1.5 2007/01/06 18:30:51 gkminix Exp $
 *
 *====================================================================
 */


#include <common.i86>

.file __FILE__
.line __LINE__



/*
 *====================================================================
 *
 * Some definitions which are local to this module
 */


/*
 * Definitions to access the PC hardware timer
 */
#define TIMER_0		0x40		/* Timer 0 port number */
#define TIMER_MODE	0x43		/* Timer mode port number */

#define TIMER_INT	10		/* Number of microseconds per tick */
#define TIMER_TICKS	4		/* Number of timer counts for a tick */




.line __LINE__
/*
 *====================================================================
 *
 * Start the text segment and define all public entry points
 */

	.text

	.global	wait_usec



/*
 *====================================================================
 *
 * Wait a number of microseconds (granularity of 10)
 * Input:  AX     -  Number of microseconds to wait
 * Output: none
 * Registers changed: AX
 */
wait_usec:

	pushf
	push	bx
	push	cx
	push	dx
	add	ax,TIMER_INT / 2	# round up to next multiple of 10
	xor	dx,dx
	mov	bx,TIMER_INT		# compute number of 10 microsecond
	div	bx			# intervalls
	or	ax,ax
	jz	9f			# check if we have to wait at all
	mov	bx,ax

1:	cli
	mov	dx,TIMER_MODE
	xor	al,al
	out	dx,al			# write timer 0 count mode
	jcxz	2f			# wait a little bit to avoid a bug
2:	jcxz	3f			# in certain Neptune chipsets
3:	mov	dx,TIMER_0
	in	al,dx			# read timer LSB
	mov	cl,al
	in	al,dx			# read timer MSB
	mov	ch,al
	sti

4:	cli
	mov	dx,TIMER_MODE
	xor	al,al
	out	dx,al			# write timer 0 count mode
	jcxz	5f
5:	jcxz	6f
6:	mov	dx,TIMER_0
	in	al,dx			# read timer LSB
	mov	ah,al
	in	al,dx			# read timer MSB
	xchg	ah,al
	sti

	neg	ax
	add	ax,cx			# check if timeout value reached
	cmp	ax,TIMER_TICKS
	jb	4b			# no, read timer again
	dec	bx
	jnz	1b			# check if number of loops reached
9:	pop	dx
	pop	cx
	pop	bx
	popf
	ret




/*
 *====================================================================
 */
	.end

