Charles.Forsyth20060303644188019 years agoHistory
719 lines · 11.5 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h"#include	"../port/error.h"#include	"../port/netif.h" /* * currently no DMA or flow control (hardware or software) */ /* * problems fixed from previous vsn: * *	- no kick on queue's, so redirections weren't getting *	  started until the clock tick * *	- lots of unnecessary overhead * *	- initialization sequencing * *	- uart[n] no longer indexed before calling uartinstall() */#define DEBUG	if(0)iprint static void uartintr(Ureg*, void*); enum{	Stagesize= 1024,	Dmabufsize=Stagesize/2,	Nuart=7,		/* max per machine */}; typedef struct Uart Uart;struct Uart{	QLock; 	int	opens; 	int	enabled; 	int	port;			/* 0 or 1 */	int	kickme;		/* for kick */	int	frame;		/* framing errors */	int	overrun;	/* rcvr overruns */	int	perror;		/* parity error */	int	bps;		/* baud rate */	uchar	bits;	char	parity;	uchar	stop; 	int	inters;		/* total interrupt count */	int	rinters;	/* interrupts due to read */	int	winters;	/* interrupts due to write */ 	int	rcount;		/* total read count */	int	wcount;		/* total output count */ 	/* buffers */	int	(*putc)(Queue*, int);	Queue	*iq;	Queue	*oq; 	UartReg	*reg; 	/* staging areas to avoid some of the per character costs */	uchar	*ip;	uchar	*ie;	uchar	*op;	uchar	*oe; 	/* put large buffers last to aid register-offset optimizations: */	char	name[KNAMELEN];	uchar	istage[Stagesize];	uchar	ostage[Stagesize];}; #define UCON_ENABLEMASK (UCON_RXMDMASK | UCON_TXMDMASK | UCON_SINTMASK)#define UCON_ENABLESET (UCON_RXMDINT | UCON_TXMDINT | UCON_SINTON)#define UCON_DISABLESET (UCON_RXMDOFF | UCON_TXMDOFF | UCON_SINTOFF) static Uart *uart[Nuart];static int nuart; static ucharreadstatus(Uart *p){	UartReg *reg = p->reg;	uchar stat = reg->stat;	if (stat & USTAT_OV)		p->overrun++;	if (stat & USTAT_PE)		p->perror++;	if (stat & USTAT_FE)		p->frame++;	return stat;}	static voiduartset(Uart *p){	UartReg *reg = p->reg;	ulong denom;	ulong brdiv;	int n;	uchar lcon; 	lcon= ULCON_CLOCKMCLK | ULCON_IROFF;	lcon |= ULCON_WL5 + (p->bits - 5);	lcon |= p->stop == 1 ? ULCON_STOP1 : ULCON_STOP2;	switch (p->parity) {	default:	case 'n':		lcon |= ULCON_PMDNONE;		break;	case 'o':		lcon |= ULCON_PMDODD;		break;	case 'e':		lcon |= ULCON_PMDEVEN;		break;	}	reg->lcon = lcon; 	/* clear the break and loopback bits; leave everything else alone */	reg->con = (reg->con & ~(UCON_BRKMASK | UCON_LOOPMASK)) | UCON_BRKOFF | UCON_LOOPOFF; 	denom = 2 * 16 * p->bps;	brdiv = (TIMER_HZ + denom / 2) / denom - 1;	reg->brdiv = brdiv << 4; 	/* set buffer length according to speed, to allow	 * at most a 200ms delay before dumping the staging buffer	 * into the input queue	 */	n = p->bps/(10*1000/200);	p->ie = &p->istage[n < Stagesize ? n : Stagesize];} /* *  send break */static voiduartbreak(Uart *p, int ms){	UartReg *reg = p->reg;	if(ms == 0)		ms = 200;	reg->con |= UCON_BRKON;	tsleep(&up->sleep, return0, 0, ms);	reg->con &= ~UCON_BRKON;} /* *  turn on a port */static voiduartenable(Uart *p){	UartReg *reg = p->reg; 	if(p->enabled)		return; 	uartset(p);	// enable receive, transmit, and receive interrupt:	reg->con = (reg->con & UCON_ENABLEMASK) | UCON_ENABLESET;	p->enabled = 1;} /* *  turn off a port */static voiduartdisable(Uart *p){	p->reg->con = (p->reg->con & UCON_ENABLEMASK) | UCON_DISABLESET;	p->enabled = 0;} /* *  put some bytes into the local queue to avoid calling *  qconsume for every character */static intstageoutput(Uart *p){	int n;	Queue *q = p->oq; 	if(!q)		return 0;	n = qconsume(q, p->ostage, Stagesize);	if(n <= 0)		return 0;	p->op = p->ostage;	p->oe = p->ostage + n;	return n;} static voiduartxmit(Uart *p){	UartReg *reg = p->reg;	ulong gag = 1;	while(p->op < p->oe || stageoutput(p)) {			if(readstatus(p) & USTAT_TBE) {			DEBUG("T");			reg->txbuf = *(p->op++);			p->wcount++;		} else {			DEBUG("F");			gag = 0;			break;		}	}	if (gag) {		DEBUG("G");		p->kickme = 1;		intrmask(UARTTXbit(p->port), 0);	}} static voiduartrecvq(Uart *p){	uchar *cp = p->istage;	int n = p->ip - cp; 	if(n == 0)		return;	if(p->putc)		while(n-- > 0) 			p->putc(p->iq, *cp++);	else if(p->iq) 		if(qproduce(p->iq, p->istage, n) < n)			print("qproduce flow control");	p->ip = p->istage;} static voiduartrecv(Uart *p){	UartReg *reg = p->reg;	uchar stat = readstatus(p); DEBUG("R");	if (stat & USTAT_RDR) {		int c;		c = reg->rxbuf;		if (c == '?') {					DEBUG("mod 0x%.8lx\n", INTREG->mod);			DEBUG("msk 0x%.8lx\n", INTREG->msk);			DEBUG("pnd 0x%.8lx\n", INTREG->pnd);		}		*p->ip++ = c;/*		if(p->ip >= p->ie) */			uartrecvq(p);		p->rcount++;	}} static voiduartkick(void *a){	Uart *p = a;	int x = splhi();	DEBUG("k");	if (p->kickme) {		p->kickme = 0;		DEBUG("K");		intrunmask(UARTTXbit(p->port), 0);	}	splx(x);} /* *  UART Interrupt Handler */static voiduarttxintr(Ureg*, void* arg){	Uart *p = arg;				intrclear(UARTTXbit(p->port), 0);	p->inters++;	p->winters++;	uartxmit(p);} static voiduartrxintr(Ureg*, void* arg){	Uart *p = arg;				intrclear(UARTRXbit(p->port), 0);	p->inters++;	p->rinters++;	uartrecv(p);}  static voiduartsetup(ulong port, char *name){	Uart *p; 	if(nuart >= Nuart)		return; 	p = xalloc(sizeof(Uart));	uart[nuart++] = p;	strcpy(p->name, name); 	p->reg = &UARTREG[port];	p->bps = 9600;	p->bits = 8;	p->parity = 'n';	p->stop = 1;	p->kickme = 0;	p->port = port; 	p->iq = qopen(4*1024, 0, 0 , p);	p->oq = qopen(4*1024, 0, uartkick, p); 	p->ip = p->istage;	p->ie = &p->istage[Stagesize];	p->op = p->ostage;	p->oe = p->ostage; 	intrenable(UARTTXbit(port), uarttxintr, p, 0); 	intrenable(UARTRXbit(port), uartrxintr, p, 0); } static voiduartinstall(void){	static int already; 	if(already)		return;	already = 1; 	uartsetup(0, "eia0");//	uartsetup(1, "eia1");} /* *  called by main() to configure a duart port as a console or a mouse */voiduartspecial(int port, int bps, char parity, Queue **in, Queue **out, int (*putc)(Queue*, int)){	Uart *p; 	uartinstall();	if(port >= nuart) 		return;	p = uart[port];	if(bps) 		p->bps = bps;	if(parity)		p->parity = parity;	uartenable(p);	p->putc = putc;	if(in)		*in = p->iq;	if(out)		*out = p->oq;	p->opens++;} Dirtab *uartdir;int ndir; static voidsetlength(int i){	Uart *p; 	if(i > 0){		p = uart[i];		if(p && p->opens && p->iq)			uartdir[1+3*i].length = qlen(p->iq);	} else for(i = 0; i < nuart; i++){		p = uart[i];		if(p && p->opens && p->iq)			uartdir[1+3*i].length = qlen(p->iq);	}} /* *  all uarts must be uartsetup() by this point or inside of uartinstall() */static voiduartreset(void){	int i;	Dirtab *dp; 	uartinstall(); 	ndir = 1+3*nuart;	uartdir = xalloc(ndir * sizeof(Dirtab));	dp = uartdir;	strcpy(dp->name, ".");	mkqid(&dp->qid, 0, 0, QTDIR);	dp->length = 0;	dp->perm = DMDIR|0555;	dp++;	for(i = 0; i < nuart; i++){		/* 3 directory entries per port */		strcpy(dp->name, uart[i]->name);		dp->qid.path = NETQID(i, Ndataqid);		dp->perm = 0660;		dp++;		sprint(dp->name, "%sctl", uart[i]->name);		dp->qid.path = NETQID(i, Nctlqid);		dp->perm = 0660;		dp++;		sprint(dp->name, "%sstatus", uart[i]->name);		dp->qid.path = NETQID(i, Nstatqid);		dp->perm = 0444;		dp++;	}} static Chan*uartattach(char *spec){	return devattach('t', spec);} static Walkqid*uartwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, uartdir, ndir, devgen);} static intuartstat(Chan *c, uchar *dp, int n){	if(NETTYPE(c->qid.path) == Ndataqid)		setlength(NETID(c->qid.path));	return devstat(c, dp, n, uartdir, ndir, devgen);} static Chan*uartopen(Chan *c, int omode){	Uart *p; 	c = devopen(c, omode, uartdir, ndir, devgen); 	switch(NETTYPE(c->qid.path)){	case Nctlqid:	case Ndataqid:		p = uart[NETID(c->qid.path)];		qlock(p);		if(p->opens++ == 0){			uartenable(p);			qreopen(p->iq);			qreopen(p->oq);		}		qunlock(p);		break;	} 	return c;} static voiduartclose(Chan *c){	Uart *p; 	if(c->qid.type & QTDIR)		return;	if((c->flag & COPEN) == 0)		return;	switch(NETTYPE(c->qid.path)){	case Ndataqid:	case Nctlqid:		p = uart[NETID(c->qid.path)];		qlock(p);		if(--(p->opens) == 0){			uartdisable(p);			qclose(p->iq);			qclose(p->oq);			p->ip = p->istage;		}		qunlock(p);		break;	}} static longuartstatus(Chan *c, Uart *p, void *buf, long n, long offset)

Lines 1–500 of 719.