henesyinit from p9fce6d0435 years agoHistory
595 lines · 9.2 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h"#include	"devtab.h" #include	"io.h" typedef struct Hs	Hs; enum {	Maxburst=	1023,		/* maximum transmit burst size */	Intvec=		0xd0,		/* vme vector for interrupts */	Intlevel=	5,		/* level to interrupt on */	Nhs=		1, 	/*	 * csr flags	 */	ALIVE		= 0x0001,	IENABLE		= 0x0004,	EXOFLOW		= 0x0008,	IRQ		= 0x0010,	EMUTE		= 0x0020,	EPARITY		= 0x0040,	EFRAME		= 0x0080,	EROFLOW		= 0x0100,	REF		= 0x0800,	XFF		= 0x4000,	XHF		= 0x8000, 	/*	 * csr reset flags	 */	FORCEW		= 0x0008,	NORESET		= 0xFF00,	RESET		= 0x0000, 	/*	 * data flags	 */	CTL		= 0x0100,	CHNO		= 0x0200,	TXEOD		= 0x0400,	NND		= 0x8000,}; #define NOW (MACHP(0)->ticks*MS2HZ)#define IPL(x)		((x)<<5) struct Hs {	QLock; 	QLock	xmit;	HSdev	*addr;	int	vec;		/* interupt vector */	Rendez	r;		/* output process */	Rendez	kr;		/* input kernel process */	int	chan;		/* current input channel */	Queue	*rq;		/* read queue */	uchar	buf[1024];	/* bytes being collected */	uchar	*wptr;		/* pointer into buf */	ulong	time;		/* time byte in buf[0] arrived */	int	kstarted;	/* true if kernel process started */	int	started; 	/* statistics */ 	ulong	parity;		/* parity errors */	ulong	rintr;		/* rcv interrupts */	ulong	tintr;		/* transmit interrupts */	ulong	in;		/* bytes in */	ulong	out;		/* bytes out */}; Hs hs[Nhs]; static void hsintr(int);static void hskproc(void*); /* *  hs stream module definition */static void hsoput(Queue*, Block*);static void hsstopen(Queue*, Stream*);static void hsstclose(Queue*);Qinfo hsinfo ={	nullput,	hsoput,	hsstopen,	hsstclose,	"hs"}; voidhsrestart(Hs *hp){	HSdev *addr; 	addr = hp->addr; 	addr->csr = RESET;	wbflush();	delay(20); 	/*	 *  set interrupt vector	 *  turn on device	 *  set forcew to a known value	 *  interrupt on level `Intlevel'	 */	addr->vector = hp->vec;	addr->csr = NORESET|IPL(Intlevel)|IENABLE|ALIVE;	wbflush();	delay(1);	addr->csr = NORESET|IPL(Intlevel)|FORCEW|IENABLE|ALIVE;	wbflush();	delay(1);	hp->started = 1;} /* *  reset all vme boards */voidhsreset(void){	int i;	Hs *hp; 	for(i=0; i<Nhs; i++){		hp = &hs[i];		hp->addr = HSDEV+i;		hp->vec = Intvec+i;		hp->addr->csr = RESET;		setvmevec(hp->vec, hsintr);	}		wbflush();	delay(20);} voidhsinit(void){} /* *  enable the device for interrupts, spec is the device number */Chan*hsattach(char *spec){	Hs *hp;	int i;	Chan *c; 	i = strtoul(spec, 0, 0);	if(i >= Nhs)		error(Ebadarg);	hp = &hs[i];	if(!hp->started)		hsrestart(hp); 	c = devattach('h', spec);	c->dev = i;	c->qid.path = CHDIR;	return c;} Chan*hsclone(Chan *c, Chan *nc){	return devclone(c, nc);} int	 hswalk(Chan *c, char *name){	return devwalk(c, name, 0, 0, streamgen);} void	 hsstat(Chan *c, char *dp){	devstat(c, dp, 0, 0, streamgen);} Chan*hsopen(Chan *c, int omode){	if(c->qid.path == CHDIR){		if(omode != OREAD)			error(Eperm);	}else		streamopen(c, &hsinfo);	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} void	 hscreate(Chan *c, char *name, int omode, ulong perm){	USED(c);	USED(name);	USED(omode);	USED(perm);	error(Eperm);} void	 hsclose(Chan *c){	if(c->qid.path != CHDIR)		streamclose(c);} long	 hsread(Chan *c, void *buf, long n, ulong offset){	USED(offset);	return streamread(c, buf, n);} long	 hswrite(Chan *c, void *buf, long n, ulong offset){	USED(offset);	return streamwrite(c, buf, n, 0);} void	 hsremove(Chan *c){	USED(c);	error(Eperm);} void	 hswstat(Chan *c, char *dp){	USED(c);	USED(dp);	error(Eperm);} /* *	the stream routines */ /* *  create the kernel process for input */static voidhsstopen(Queue *q, Stream *s){	Hs *hp;	char name[32]; 	hp = &hs[s->dev];	sprint(name, "hs%d", s->dev);	q->ptr = q->other->ptr = hp;	hp->rq = q;	kproc(name, hskproc, hp);} /* *  ask kproc to die and wait till it happens */static intkdead(void *arg){	Hs *hp; 	hp = (Hs *)arg;	return hp->kstarted == 0;}static voidhsstclose(Queue * q){	Hs *hp; 	hp = (Hs *)q->ptr;	qlock(hp);	hp->rq = 0;	qunlock(hp);	while(waserror())		;	while(hp->kstarted){		wakeup(&hp->kr);		sleep(&hp->r, kdead, hp);	}	poperror();} /* *  free all blocks of a message in `q', `bp' is the first block *  of the message */static voidfreemsg(Queue *q, Block *bp){	for(; bp; bp = getq(q)){		if(bp->flags & S_DELIM){			freeb(bp);			return;		}		freeb(bp);	}} /* *  return true if the output fifo is at least half empty. *  the implication is that it can take at least another 1000 byte burst. */static inthalfempty(void *arg){	HSdev *addr; 	addr = (HSdev*)arg;	return addr->csr & XHF;} /* *  output a block * *  the first 2 bytes of every message are the channel number, *  low order byte first.  the third is a possible trailing control *  character. */voidhsoput(Queue *q, Block *bp){	HSdev *addr;	Hs *hp;	int burst;	int chan;	int ctl;	int n; 	if(bp->type != M_DATA){		freeb(bp);		return;	}	if(BLEN(bp) < 3){		bp = pullup(bp, 3);		if(bp == 0){			print("hsoput pullup failed\n");			return;		}	} 	/*	 *  get a whole message before handing bytes to the device	 */	if(!putq(q, bp))		return; 	/*	 *  one transmitter at a time	 */	hp = (Hs *)q->ptr;	qlock(&hp->xmit);	if(waserror()){		qunlock(&hp->xmit);		nexterror();	}	addr = hp->addr; 	/*	 *  parse message	 */	bp = getq(q);	chan = CHNO | bp->rptr[0] | (bp->rptr[1]<<8);	ctl = bp->rptr[2];	bp->rptr += 3; 	/*	 *  send the 8 bit data, burst are up to Maxburst (9-bit) bytes long	 */	if(!(addr->csr & XHF))		sleep(&hp->r, halfempty, addr);/*	print("->%.2uo\n", CHNO|chan);/**/	addr->data = CHNO|chan;	burst = Maxburst;	while(bp){		if(burst == 0){			addr->data = TXEOD;/*			print("->%.2uo\n", TXEOD); /**/			if(!(addr->csr & XHF))				sleep(&hp->r, halfempty, addr);/*			print("->%.2uo\n", CHNO|chan); /**/			addr->data = CHNO|chan;			burst = Maxburst;		}		n = bp->wptr - bp->rptr;		if(n > burst)			n = burst;		burst -= n;		while(n--){/*			print("->%.2uo\n", *bp->rptr); /**/			addr->data = *bp->rptr++;		}		if(bp->rptr >= bp->wptr){			if(bp->flags & S_DELIM){				freeb(bp);				break;			}			freeb(bp);			bp = getq(q);		}	} 	/*	 *  send the control byte if there is one	 */	if(ctl){/*		print("->%.2uo\n", CTL|ctl); /**/		addr->data = CTL|ctl;	} 	/*	 *  start the fifo emptying	 *//*	print("->%.2uo\n", TXEOD); /**/	addr->data = TXEOD; 	qunlock(&hp->xmit);	poperror();} /* *  return true if the input fifo is non-empty */static intnotempty(void *arg){	HSdev *addr; 	addr = (HSdev *)arg;	return addr->csr & REF;} /* *  fill a block with what is currently buffered and send it upstream */static voidupstream(Hs *hp, unsigned int ctl){	int n;	Block *bp; 	n = hp->wptr - hp->buf;	bp = allocb(3 + n);	bp->wptr[0] = hp->chan;	bp->wptr[1] = hp->chan>>8;	bp->wptr[2] = ctl;	if(n)		memmove(&bp->wptr[3], hp->buf, n);	bp->wptr += 3 + n;	bp->flags |= S_DELIM;	PUTNEXT(hp->rq, bp);	hp->wptr = hp->buf;	hp->time = 0;} /* *  Read bytes from the input fifo.  Since we take an interrupt every *  time the fifo goes non-empty, we need to waste time to let the *  fifo fill up. */static voidhskproc(void *arg){	Hs *hp;	HSdev *addr;	unsigned int c;	int locked; 	hp = (Hs *)arg;	addr = hp->addr;	hp->kstarted = 1;	hp->wptr = hp->buf; 	locked = 0;	if(waserror()){		if(locked)			qunlock(hp);		hp->kstarted = 0;		wakeup(&hp->r);		return;	} 	for(;;){		/*

Lines 1–500 of 595.