/*
 * Selector channel scheduling routines
 */

#include "../h/param.h"
#include "../h/buf.h"
#include "../h/selch.h"
#include "../h/inf.h"


extern char	devmap[];	/* map device address => minor device no */

/*
 * Queue of devices using each selch
 *	- top of queue is currently active device; others are waiting
 */
extern	struct	selchtab	selchtab[ ];
extern	int	nselch;


/*
 * Request use of selch with address n
 */
selchreq(n, selchq)
struct selchq *selchq;
{
	register struct selchq *s;
	register struct selchtab *st;
	register free;
	register lev;
	trace(2<<16, "schrequest", selchq);

	st = &selchtab[devmap[n]];
	/* Make sure request not already on queue */
	for (s = st->sc_actf; s; s = s->sq_forw)
		if (s == selchq)  {
			printf("selchreq: already queued %x\n", s);
			return;
			}

	(s = selchq)->sq_forw = 0;
	lev = spl7();
	if (st->sc_actf) {
		st->sc_actl->sq_forw = s;
		free = 0;
	} else {
		st->sc_actf = s;
		free = 1;
	}
	st->sc_actl = s;
	splx(lev);

	if (free)
		(*s->sq_sstart)(s->sq_param);
}

/*
 * Free selch with address n for next device
 */
selchfree(n)
{
	register struct selchq *s;
	register struct selchtab *st;

	st = &selchtab[devmap[n]];
	trace(2<<16, "schfree", st->sc_actf);
	if ((s = st->sc_actf) == 0)
		return;
	st->sc_actf = s = s->sq_forw;

	if (s)
		(*s->sq_sstart)(s->sq_param);
}

/*
 * Selector channel interrupt -- handled by currently active device
 */
selchintr(dev, stat)
{
	register struct selchq *s;
	register struct selchtab *st;
	trace(4<<16, "schint", dev);
	trace(4<<16, "status", stat);

	st = &selchtab[dev];
	if (s = st->sc_actf)
		(*s->sq_sintr)(dev, stat, s->sq_param);
}

Selchreq(inf, start, intr)
register struct inf *inf;
int	 (*start)();
int	 (*intr)();
{
	register struct selchq *q;

	q = &cntltab[inf->inf_ncntl].c_scq;
	q->sq_param  = inf;
	q->sq_sstart = start;
	q->sq_sintr  = intr;
	selchreq(inf->inf_selch, q);
}

Selchfree(inf)
register struct inf *inf;
{
	selchfree(inf->inf_selch);
}
