789 lines · 12.3 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" enum{	/* soft flow control chars */	CTLS= 023,	CTLQ= 021,}; extern Dev uartdevtab;extern PhysUart* physuart[]; static Uart* uartlist;static Uart** uart;static int uartnuart;static Dirtab *uartdir;static int uartndir;static Timer *uarttimer; struct Uartalloc {	Lock;	Uart *elist;	/* list of enabled interfaces */} uartalloc; static void	uartclock(void);static void	uartflow(void*); /* *  enable/disable uart and add/remove to list of enabled uarts *///staticUart*uartenable(Uart *p){	Uart **l; 	if (up == nil)		return p;		/* too soon; try again later *///		return nil; 	if(p->iq == nil){		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)			return nil;	}	else		qreopen(p->iq);	if(p->oq == nil){		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){			qfree(p->iq);			p->iq = nil;			return nil;		}	}	else		qreopen(p->oq); 	p->ir = p->istage;	p->iw = p->istage;	p->ie = &p->istage[Stagesize];	p->op = p->ostage;	p->oe = p->ostage; 	p->hup_dsr = p->hup_dcd = 0;	p->dsr = p->dcd = 0; 	/* assume we can send */	p->cts = 1;	p->ctsbackoff = 0; if (up) {	if(p->bits == 0)		uartctl(p, "l8");	if(p->stop == 0)		uartctl(p, "s1");	if(p->parity == 0)		uartctl(p, "pn");	if(p->baud == 0)		uartctl(p, "b9600");	(*p->phys->enable)(p, 1);} 	/*	 * use ilock because uartclock can otherwise interrupt here	 * and would hang on an attempt to lock uartalloc.	 */	ilock(&uartalloc);	for(l = &uartalloc.elist; *l; l = &(*l)->elist){		if(*l == p)			break;	}	if(*l == 0){		p->elist = uartalloc.elist;		uartalloc.elist = p;	}	p->enabled = 1;	iunlock(&uartalloc); 	return p;} static voiduartdisable(Uart *p){	Uart **l; 	(*p->phys->disable)(p); 	ilock(&uartalloc);	for(l = &uartalloc.elist; *l; l = &(*l)->elist){		if(*l == p){			*l = p->elist;			break;		}	}	p->enabled = 0;	iunlock(&uartalloc);} voiduartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200){	qlock(p);	if(p->opens++ == 0 && uartenable(p) == nil){		qunlock(p);		error(Enodev);	}	if(setb1200)		uartctl(p, "b1200");	p->putc = putc;	p->special = 1;	qunlock(p);} voiduartsetmouseputc(Uart* p, int (*putc)(Queue*, int)){	qlock(p);	if(p->opens == 0 || p->special == 0){		qunlock(p);		error(Enodev);	}	p->putc = putc;	qunlock(p);} 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 < uartnuart; i++){		p = uart[i];		if(p && p->opens && p->iq)			uartdir[1+3*i].length = qlen(p->iq);	}} /* *  set up the '#t' directory */static voiduartreset(void){	int i;	Dirtab *dp;	Uart *p, *tail; 	tail = nil;	for(i = 0; physuart[i] != nil; i++){		if(physuart[i]->pnp == nil)			continue;		if((p = physuart[i]->pnp()) == nil)			continue;		if(uartlist != nil)			tail->next = p;		else			uartlist = p;		for(tail = p; tail->next != nil; tail = tail->next)			uartnuart++;		uartnuart++;	} 	if(uartnuart)		uart = xalloc(uartnuart*sizeof(Uart*)); 	uartndir = 1 + 3*uartnuart;	uartdir = xalloc(uartndir * sizeof(Dirtab));	if (uart == nil || uartdir == nil)		panic("uartreset: no memory");	dp = uartdir;	strcpy(dp->name, ".");	mkqid(&dp->qid, 0, 0, QTDIR);	dp->length = 0;	dp->perm = DMDIR|0555;	dp++;	p = uartlist;	for(i = 0; i < uartnuart; i++){		/* 3 directory entries per port */		snprint(dp->name, sizeof dp->name, "eia%d", i);		dp->qid.path = NETQID(i, Ndataqid);		dp->perm = 0660;		dp++;		snprint(dp->name, sizeof dp->name, "eia%dctl", i);		dp->qid.path = NETQID(i, Nctlqid);		dp->perm = 0660;		dp++;		snprint(dp->name, sizeof dp->name, "eia%dstatus", i);		dp->qid.path = NETQID(i, Nstatqid);		dp->perm = 0444;		dp++; 		uart[i] = p;		p->dev = i;		if(p->console || p->special){			if(uartenable(p) != nil){				if(p->console && up){					kbdq = p->iq;					serialoq = p->oq;					p->putc = kbdcr2nl;				}				p->opens++;			}		}		p = p->next;	} 	if(uartnuart){		/*		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,		 * processing it every 22 ms should be fine.		 */		uarttimer = addclock0link(uartclock, 22);	}}  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, uartndir, 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, uartndir, devgen);} static Chan*uartopen(Chan *c, int omode){	Uart *p; 	c = devopen(c, omode, uartdir, uartndir, devgen); 	switch(NETTYPE(c->qid.path)){	case Nctlqid:	case Ndataqid:		p = uart[NETID(c->qid.path)];		qlock(p);		if(p->opens++ == 0 && uartenable(p) == nil){			qunlock(p);			c->flag &= ~COPEN;			error(Enodev);		}		qunlock(p);		break;	} 	c->iounit = qiomaxatomic;	return c;} static intuartdrained(void* arg){	Uart *p; 	p = arg;	return qlen(p->oq) == 0 && p->op == p->oe;} static voiduartdrainoutput(Uart *p){	if(!p->enabled || up == nil)		return; 	p->drain = 1;	if(waserror()){		p->drain = 0;		nexterror();	}	sleep(&p->r, uartdrained, p);	poperror();} 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){			qclose(p->iq);			ilock(&p->rlock);			p->ir = p->iw = p->istage;			iunlock(&p->rlock); 			/*			 */			qhangup(p->oq, nil);			if(!waserror()){				uartdrainoutput(p);				poperror();			}			qclose(p->oq);			uartdisable(p);			p->dcd = p->dsr = p->dohup = 0;		}		qunlock(p);		break;	}} static longuartread(Chan *c, void *buf, long n, vlong off){	Uart *p;	ulong offset = off; 	if(c->qid.type & QTDIR){		setlength(-1);		return devdirread(c, buf, n, uartdir, uartndir, devgen);	} 	p = uart[NETID(c->qid.path)];	switch(NETTYPE(c->qid.path)){	case Ndataqid:		return qread(p->iq, buf, n);	case Nctlqid:		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);	case Nstatqid:		return (*p->phys->status)(p, buf, n, offset);	} 	return 0;} intuartctl(Uart *p, char *cmd){	char *f[16];	int i, n, nf; 	nf = tokenize(cmd, f, nelem(f));	for(i = 0; i < nf; i++){		if(strncmp(f[i], "break", 5) == 0){			(*p->phys->dobreak)(p, 0);			continue;		} 		n = atoi(f[i]+1);		switch(*f[i]){		case 'B':		case 'b':			uartdrainoutput(p);			if((*p->phys->baud)(p, n) < 0)				return -1;			break;		case 'C':		case 'c':			p->hup_dcd = n;			break;		case 'D':		case 'd':			uartdrainoutput(p);			(*p->phys->dtr)(p, n);			break;		case 'E':		case 'e':			p->hup_dsr = n;			break;		case 'f':		case 'F':			if(p->oq != nil)				qflush(p->oq);			break;		case 'H':		case 'h':			if(p->iq != nil)				qhangup(p->iq, 0);			if(p->oq != nil)				qhangup(p->oq, 0);			break;		case 'i':		case 'I':			uartdrainoutput(p);			(*p->phys->fifo)(p, n);			break;		case 'K':		case 'k':			uartdrainoutput(p);			(*p->phys->dobreak)(p, n);			break;		case 'L':		case 'l':			uartdrainoutput(p);			if((*p->phys->bits)(p, n) < 0)				return -1;			break;		case 'm':		case 'M':			uartdrainoutput(p);			(*p->phys->modemctl)(p, n);			break;		case 'n':		case 'N':			if(p->oq != nil)				qnoblock(p->oq, n);			break;		case 'P':		case 'p':			uartdrainoutput(p);			if((*p->phys->parity)(p, *(f[i]+1)) < 0)				return -1;			break;		case 'Q':		case 'q':			if(p->iq != nil)				qsetlimit(p->iq, n);			if(p->oq != nil)				qsetlimit(p->oq, n);			break;		case 'R':		case 'r':			uartdrainoutput(p);			(*p->phys->rts)(p, n);			break;		case 'S':		case 's':			uartdrainoutput(p);			if((*p->phys->stop)(p, n) < 0)				return -1;			break;		case 'W':		case 'w':			if(uarttimer == nil || n < 1)				return -1;			uarttimer->tns = (vlong)n * 100000LL;			break;		case 'X':		case 'x':			if(p->enabled){				ilock(&p->tlock);				p->xonoff = n;				iunlock(&p->tlock);			}			break;		}	}	return 0;} static longuartwrite(Chan *c, void *buf, long n, vlong){	Uart *p;	char *cmd; 	if(c->qid.type & QTDIR)		error(Eperm);

Lines 1–500 of 789.