Coherent4.2.10/i386/dmalock.c

/* $Header: /ker/i386/RCS/dmalock.c,v 2.4 93/10/29 00:56:43 nigel Exp Locker: nigel $ */
/*
 *	The  information  contained herein  is a trade secret  of INETCO
 *	Systems, Ltd, and is  confidential information.   It is provided
 *	under a license agreement,  and may be copied or disclosed  only
 *	under  the  terms  of  that  agreement.    Any  reproduction  or
 *	disclosure  of  this   material   without  the  express  written
 *	authorization of INETCO Systems, Ltd. or persuant to the license
 *	agreement is unlawful.
 *
 *	Copyright (c) 1989
 *	An unpublished work by INETCO Systems, Ltd.
 *	All rights reserved.
 *
 * Routines to lock/unlock the DMA controller chip.
 *
 * $Creation: June 21, 1989 $
 *
 * $Log:	dmalock.c,v $
 * Revision 2.4  93/10/29  00:56:43  nigel
 * R98 (aka 4.2 Beta) prior to removing System Global memory
 * 
 * Revision 2.3  93/08/19  03:40:02  nigel
 * Nigel's R83
 * 
 * Revision 2.2  93/07/26  13:55:59  nigel
 * Nigel's R80
 * 
 * Revision 1.1  93/04/14  10:26:34  root
 * r75
 * 
 * Revision 1.1	89/06/30  16:21:26 	src
 * Initial revision
 */

#include <kernel/timeout.h>
#include <coh/timeout.h>
#include <coh/dmalock.h>

/*
 * If the following variable is non-zero, DMA controller locking is enabled,
 * allowing at access to only one DMA channel at a time.
 */
int DMALCK = 1;

static TIM * dmatail = (TIM *)0;	/* DMA deferred function queue tail. */
static TIM * dmahead = (TIM *)0;	/* DMA deferred function queue head. */

/*
 * int
 * dmalock( dfp, fun, arg )
 * TIM * dfp;
 * vfp_t fun;
 * int	 arg;
 *
 *	Inputs:	dfp  = Deferred function structure pointer.
 *		fun  = Function to call if request is deferred.
 *		arg  = Argument to pass to function.
 *
 *	Action:	Either locks DMA controller immediately or defers function
 *		call until lock can be granted.
 *
 *	Return:	0 = Lock granted or -1 = Lock deferred.
 *
 *	Notes:	DMA controller locking was introduced to cure a bug on the
 *		NCR DMA controller, where overlapped DMA caused problems.
 *		No action is taken if DMA locking is disabled.
 */

int
dmalock( dfp, fun, arg )
register TIM	* dfp;
__TIMED_FN_PTR	fun;
int		arg;
{
	register int s;		/* Interrupt mask state. */

	/*
	 * If DMA locking is disabled, allow functions to proceed.
	 */
 	if ( DMALCK == 0 )
		return( 0 );

	/*
	 * Record function and argument to be invoked upon dmaunlock.
	 */

	dfp->t_func = fun;
	dfp->t_farg = arg;
	dfp->t_next = (TIM *)0;

	s = sphi();

	/*
	 * If the queue is empty, put our structure at the head.
	 */
	if ( dmahead == (TIM *)0 ) {
		dmahead = dfp;
		dmatail = dfp;
		spl( s );
		return( 0 );
	}

	/*
	 * PARANOIA:	If our structure is already at the head of the queue,
	 *		print a message and return.
	 */
	if ( dmahead == dfp ) {
		spl( s );
		printf( "dmalock: driver attempting to doubly lock DMA controller.\n" );
		return( 0 );
	}

	/*
	 * Append to tail of DMA deferred function queue.
	 */
	dmatail->t_next = dfp;
	dmatail		= dfp;
	spl( s );
	return( -1 );
}

/*
 * void
 * dmaunlock( dfp )
 * TIM * dfp;
 *
 *	Inputs:	dfp = Deferred function structure pointer.
 *
 *	Action:	Unlocks the DMA controller and calls the next deferred
 *		function, if any.
 *
 *	Notes:	No action is taken if the deferred function structure pointer
 *		is not the same as the one used to lock the DMA controller.
 */

void
dmaunlock( dfp )
register TIM * dfp;
{
	register TIM *	qp;	/* Temporary function queue pointer.	*/
	register int	s;	/* Interrupt mask state.		*/

	s = sphi();

	/*
	 * If the DMA controller is not locked, return.
	 */
	if ( dmahead == (TIM *)0 ) {
		spl( s );
		return;
	}

 	/*
	 * If our lock is not the one holding the DMA controller:
	 */
	if ( dmahead != dfp ) {

		/*
		 * Look for us in queue.
		 */
		for ( qp = dmahead; qp != dmatail; qp = qp->t_next )

			/*
			 * If found, remove us.
			 */
			if ( qp->t_next == dfp ) {
				qp->t_next = dfp->t_next;

				if ( dmatail == dfp )
					dmatail = qp;

				break;
			}

		spl( s );
		return;
	}

	/*
	 * If there are no functions waiting for us, empty queue and return.
	 */
	if ( dmahead == dmatail ) {
		dmahead = (TIM *)0;
		spl( s );
		return;
	}

	/*
	 * Remove us and execute next deferred function.
	 */
	dmahead = dmahead->t_next;
	spl( s );
/* The second arg to *t_func looks bogus - hal 94/08/19 */
#if 1
	(*dmahead->t_func)( dmahead->t_farg);
#else
	(*dmahead->t_func)( dmahead->t_farg, dmahead );
#endif
}