xref: /plan9/sys/src/9/teg2/devuart.c (revision 696c1e60c910958ad30cdfb7404030ea707cbbf1)
13de6a9c0SDavid du Colombier #include	"u.h"
23de6a9c0SDavid du Colombier #include	"../port/lib.h"
33de6a9c0SDavid du Colombier #include	"mem.h"
43de6a9c0SDavid du Colombier #include	"dat.h"
53de6a9c0SDavid du Colombier #include	"fns.h"
63de6a9c0SDavid du Colombier #include	"io.h"
73de6a9c0SDavid du Colombier #include	"../port/error.h"
83de6a9c0SDavid du Colombier 
93de6a9c0SDavid du Colombier #include	"../port/netif.h"
103de6a9c0SDavid du Colombier 
113de6a9c0SDavid du Colombier enum
123de6a9c0SDavid du Colombier {
133de6a9c0SDavid du Colombier 	/* soft flow control chars */
143de6a9c0SDavid du Colombier 	CTLS= 023,
153de6a9c0SDavid du Colombier 	CTLQ= 021,
163de6a9c0SDavid du Colombier };
173de6a9c0SDavid du Colombier 
183de6a9c0SDavid du Colombier extern Dev uartdevtab;
193de6a9c0SDavid du Colombier extern PhysUart* physuart[];
203de6a9c0SDavid du Colombier 
213de6a9c0SDavid du Colombier static Uart* uartlist;
223de6a9c0SDavid du Colombier static Uart** uart;
233de6a9c0SDavid du Colombier static int uartnuart;
243de6a9c0SDavid du Colombier static Dirtab *uartdir;
253de6a9c0SDavid du Colombier static int uartndir;
263de6a9c0SDavid du Colombier static Timer *uarttimer;
273de6a9c0SDavid du Colombier 
283de6a9c0SDavid du Colombier struct Uartalloc {
293de6a9c0SDavid du Colombier 	Lock;
303de6a9c0SDavid du Colombier 	Uart *elist;	/* list of enabled interfaces */
313de6a9c0SDavid du Colombier } uartalloc;
323de6a9c0SDavid du Colombier 
333de6a9c0SDavid du Colombier static void	uartclock(void);
343de6a9c0SDavid du Colombier static void	uartflow(void*);
353de6a9c0SDavid du Colombier 
363de6a9c0SDavid du Colombier /*
373de6a9c0SDavid du Colombier  *  enable/disable uart and add/remove to list of enabled uarts
383de6a9c0SDavid du Colombier  */
393de6a9c0SDavid du Colombier //static
403de6a9c0SDavid du Colombier Uart*
uartenable(Uart * p)413de6a9c0SDavid du Colombier uartenable(Uart *p)
423de6a9c0SDavid du Colombier {
433de6a9c0SDavid du Colombier 	Uart **l;
443de6a9c0SDavid du Colombier 
453de6a9c0SDavid du Colombier 	if (up == nil)
463de6a9c0SDavid du Colombier 		return p;		/* too soon; try again later */
473de6a9c0SDavid du Colombier //		return nil;
483de6a9c0SDavid du Colombier 
493de6a9c0SDavid du Colombier 	if(p->iq == nil){
503de6a9c0SDavid du Colombier 		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
513de6a9c0SDavid du Colombier 			return nil;
523de6a9c0SDavid du Colombier 	}
533de6a9c0SDavid du Colombier 	else
543de6a9c0SDavid du Colombier 		qreopen(p->iq);
553de6a9c0SDavid du Colombier 	if(p->oq == nil){
563de6a9c0SDavid du Colombier 		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
573de6a9c0SDavid du Colombier 			qfree(p->iq);
583de6a9c0SDavid du Colombier 			p->iq = nil;
593de6a9c0SDavid du Colombier 			return nil;
603de6a9c0SDavid du Colombier 		}
613de6a9c0SDavid du Colombier 	}
623de6a9c0SDavid du Colombier 	else
633de6a9c0SDavid du Colombier 		qreopen(p->oq);
643de6a9c0SDavid du Colombier 
653de6a9c0SDavid du Colombier 	p->ir = p->istage;
663de6a9c0SDavid du Colombier 	p->iw = p->istage;
673de6a9c0SDavid du Colombier 	p->ie = &p->istage[Stagesize];
683de6a9c0SDavid du Colombier 	p->op = p->ostage;
693de6a9c0SDavid du Colombier 	p->oe = p->ostage;
703de6a9c0SDavid du Colombier 
713de6a9c0SDavid du Colombier 	p->hup_dsr = p->hup_dcd = 0;
723de6a9c0SDavid du Colombier 	p->dsr = p->dcd = 0;
733de6a9c0SDavid du Colombier 
743de6a9c0SDavid du Colombier 	/* assume we can send */
753de6a9c0SDavid du Colombier 	p->cts = 1;
763de6a9c0SDavid du Colombier 	p->ctsbackoff = 0;
773de6a9c0SDavid du Colombier 
783de6a9c0SDavid du Colombier 	if (up) {
793de6a9c0SDavid du Colombier 		if(p->bits == 0)
803de6a9c0SDavid du Colombier 			uartctl(p, "l8");
813de6a9c0SDavid du Colombier 		if(p->stop == 0)
823de6a9c0SDavid du Colombier 			uartctl(p, "s1");
833de6a9c0SDavid du Colombier 		if(p->parity == 0)
843de6a9c0SDavid du Colombier 			uartctl(p, "pn");
853de6a9c0SDavid du Colombier 		if(p->baud == 0)
863de6a9c0SDavid du Colombier 			uartctl(p, "b9600");
873de6a9c0SDavid du Colombier 		(*p->phys->enable)(p, 1);
883de6a9c0SDavid du Colombier 	}
893de6a9c0SDavid du Colombier 
903de6a9c0SDavid du Colombier 	/*
913de6a9c0SDavid du Colombier 	 * use ilock because uartclock can otherwise interrupt here
923de6a9c0SDavid du Colombier 	 * and would hang on an attempt to lock uartalloc.
933de6a9c0SDavid du Colombier 	 */
943de6a9c0SDavid du Colombier 	ilock(&uartalloc);
953de6a9c0SDavid du Colombier 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
963de6a9c0SDavid du Colombier 		if(*l == p)
973de6a9c0SDavid du Colombier 			break;
983de6a9c0SDavid du Colombier 	}
993de6a9c0SDavid du Colombier 	if(*l == 0){
1003de6a9c0SDavid du Colombier 		p->elist = uartalloc.elist;
1013de6a9c0SDavid du Colombier 		uartalloc.elist = p;
1023de6a9c0SDavid du Colombier 	}
1033de6a9c0SDavid du Colombier 	p->enabled = 1;
1043de6a9c0SDavid du Colombier 	iunlock(&uartalloc);
1053de6a9c0SDavid du Colombier 
1063de6a9c0SDavid du Colombier 	return p;
1073de6a9c0SDavid du Colombier }
1083de6a9c0SDavid du Colombier 
1093de6a9c0SDavid du Colombier static void
uartdisable(Uart * p)1103de6a9c0SDavid du Colombier uartdisable(Uart *p)
1113de6a9c0SDavid du Colombier {
1123de6a9c0SDavid du Colombier 	Uart **l;
1133de6a9c0SDavid du Colombier 
1143de6a9c0SDavid du Colombier 	(*p->phys->disable)(p);
1153de6a9c0SDavid du Colombier 
1163de6a9c0SDavid du Colombier 	ilock(&uartalloc);
1173de6a9c0SDavid du Colombier 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
1183de6a9c0SDavid du Colombier 		if(*l == p){
1193de6a9c0SDavid du Colombier 			*l = p->elist;
1203de6a9c0SDavid du Colombier 			break;
1213de6a9c0SDavid du Colombier 		}
1223de6a9c0SDavid du Colombier 	}
1233de6a9c0SDavid du Colombier 	p->enabled = 0;
1243de6a9c0SDavid du Colombier 	iunlock(&uartalloc);
1253de6a9c0SDavid du Colombier }
1263de6a9c0SDavid du Colombier 
1273de6a9c0SDavid du Colombier void
uartmouse(Uart * p,int (* putc)(Queue *,int),int setb1200)1283de6a9c0SDavid du Colombier uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
1293de6a9c0SDavid du Colombier {
1303de6a9c0SDavid du Colombier 	qlock(p);
1313de6a9c0SDavid du Colombier 	if(p->opens++ == 0 && uartenable(p) == nil){
1323de6a9c0SDavid du Colombier 		qunlock(p);
1333de6a9c0SDavid du Colombier 		error(Enodev);
1343de6a9c0SDavid du Colombier 	}
1353de6a9c0SDavid du Colombier 	if(setb1200)
1363de6a9c0SDavid du Colombier 		uartctl(p, "b1200");
1373de6a9c0SDavid du Colombier 	p->putc = putc;
1383de6a9c0SDavid du Colombier 	p->special = 1;
1393de6a9c0SDavid du Colombier 	qunlock(p);
1403de6a9c0SDavid du Colombier }
1413de6a9c0SDavid du Colombier 
1423de6a9c0SDavid du Colombier void
uartsetmouseputc(Uart * p,int (* putc)(Queue *,int))1433de6a9c0SDavid du Colombier uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
1443de6a9c0SDavid du Colombier {
1453de6a9c0SDavid du Colombier 	qlock(p);
1463de6a9c0SDavid du Colombier 	if(p->opens == 0 || p->special == 0){
1473de6a9c0SDavid du Colombier 		qunlock(p);
1483de6a9c0SDavid du Colombier 		error(Enodev);
1493de6a9c0SDavid du Colombier 	}
1503de6a9c0SDavid du Colombier 	p->putc = putc;
1513de6a9c0SDavid du Colombier 	qunlock(p);
1523de6a9c0SDavid du Colombier }
1533de6a9c0SDavid du Colombier 
1543de6a9c0SDavid du Colombier static void
setlength(int i)1553de6a9c0SDavid du Colombier setlength(int i)
1563de6a9c0SDavid du Colombier {
1573de6a9c0SDavid du Colombier 	Uart *p;
1583de6a9c0SDavid du Colombier 
1593de6a9c0SDavid du Colombier 	if(i > 0){
1603de6a9c0SDavid du Colombier 		p = uart[i];
1613de6a9c0SDavid du Colombier 		if(p && p->opens && p->iq)
1623de6a9c0SDavid du Colombier 			uartdir[1+3*i].length = qlen(p->iq);
1633de6a9c0SDavid du Colombier 	} else for(i = 0; i < uartnuart; i++){
1643de6a9c0SDavid du Colombier 		p = uart[i];
1653de6a9c0SDavid du Colombier 		if(p && p->opens && p->iq)
1663de6a9c0SDavid du Colombier 			uartdir[1+3*i].length = qlen(p->iq);
1673de6a9c0SDavid du Colombier 	}
1683de6a9c0SDavid du Colombier }
1693de6a9c0SDavid du Colombier 
1703de6a9c0SDavid du Colombier /*
1713de6a9c0SDavid du Colombier  *  set up the '#t' directory
1723de6a9c0SDavid du Colombier  */
1733de6a9c0SDavid du Colombier static void
uartreset(void)1743de6a9c0SDavid du Colombier uartreset(void)
1753de6a9c0SDavid du Colombier {
1763de6a9c0SDavid du Colombier 	int i;
1773de6a9c0SDavid du Colombier 	Dirtab *dp;
1783de6a9c0SDavid du Colombier 	Uart *p, *tail;
1793de6a9c0SDavid du Colombier 
1803de6a9c0SDavid du Colombier 	tail = nil;
1813de6a9c0SDavid du Colombier 	for(i = 0; physuart[i] != nil; i++){
1823de6a9c0SDavid du Colombier 		if(physuart[i]->pnp == nil)
1833de6a9c0SDavid du Colombier 			continue;
1843de6a9c0SDavid du Colombier 		if((p = physuart[i]->pnp()) == nil)
1853de6a9c0SDavid du Colombier 			continue;
1863de6a9c0SDavid du Colombier 		if(uartlist != nil)
1873de6a9c0SDavid du Colombier 			tail->next = p;
1883de6a9c0SDavid du Colombier 		else
1893de6a9c0SDavid du Colombier 			uartlist = p;
1903de6a9c0SDavid du Colombier 		for(tail = p; tail->next != nil; tail = tail->next)
1913de6a9c0SDavid du Colombier 			uartnuart++;
1923de6a9c0SDavid du Colombier 		uartnuart++;
1933de6a9c0SDavid du Colombier 	}
1943de6a9c0SDavid du Colombier 
1953de6a9c0SDavid du Colombier 	if(uartnuart)
1963de6a9c0SDavid du Colombier 		uart = xalloc(uartnuart*sizeof(Uart*));
1973de6a9c0SDavid du Colombier 
1983de6a9c0SDavid du Colombier 	uartndir = 1 + 3*uartnuart;
1993de6a9c0SDavid du Colombier 	uartdir = xalloc(uartndir * sizeof(Dirtab));
2003de6a9c0SDavid du Colombier 	if (uart == nil || uartdir == nil)
2013de6a9c0SDavid du Colombier 		panic("uartreset: no memory");
2023de6a9c0SDavid du Colombier 	dp = uartdir;
2033de6a9c0SDavid du Colombier 	strcpy(dp->name, ".");
2043de6a9c0SDavid du Colombier 	mkqid(&dp->qid, 0, 0, QTDIR);
2053de6a9c0SDavid du Colombier 	dp->length = 0;
2063de6a9c0SDavid du Colombier 	dp->perm = DMDIR|0555;
2073de6a9c0SDavid du Colombier 	dp++;
2083de6a9c0SDavid du Colombier 	p = uartlist;
2093de6a9c0SDavid du Colombier 	for(i = 0; i < uartnuart; i++){
2103de6a9c0SDavid du Colombier 		/* 3 directory entries per port */
2113de6a9c0SDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%d", i);
2123de6a9c0SDavid du Colombier 		dp->qid.path = NETQID(i, Ndataqid);
2133de6a9c0SDavid du Colombier 		dp->perm = 0660;
2143de6a9c0SDavid du Colombier 		dp++;
2153de6a9c0SDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%dctl", i);
2163de6a9c0SDavid du Colombier 		dp->qid.path = NETQID(i, Nctlqid);
2173de6a9c0SDavid du Colombier 		dp->perm = 0660;
2183de6a9c0SDavid du Colombier 		dp++;
2193de6a9c0SDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
2203de6a9c0SDavid du Colombier 		dp->qid.path = NETQID(i, Nstatqid);
2213de6a9c0SDavid du Colombier 		dp->perm = 0444;
2223de6a9c0SDavid du Colombier 		dp++;
2233de6a9c0SDavid du Colombier 
2243de6a9c0SDavid du Colombier 		uart[i] = p;
2253de6a9c0SDavid du Colombier 		p->dev = i;
2263de6a9c0SDavid du Colombier 		if(p->console || p->special){
2273de6a9c0SDavid du Colombier 			if(uartenable(p) != nil){
2283de6a9c0SDavid du Colombier 				if(p->console && up){
2293de6a9c0SDavid du Colombier 					kbdq = p->iq;
2303de6a9c0SDavid du Colombier 					serialoq = p->oq;
2313de6a9c0SDavid du Colombier 					p->putc = kbdcr2nl;
2323de6a9c0SDavid du Colombier 				}
2333de6a9c0SDavid du Colombier 				p->opens++;
2343de6a9c0SDavid du Colombier 			}
2353de6a9c0SDavid du Colombier 		}
2363de6a9c0SDavid du Colombier 		p = p->next;
2373de6a9c0SDavid du Colombier 	}
2383de6a9c0SDavid du Colombier 
2393de6a9c0SDavid du Colombier 	if(uartnuart){
2403de6a9c0SDavid du Colombier 		/*
2413de6a9c0SDavid du Colombier 		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
2423de6a9c0SDavid du Colombier 		 * processing it every 22 ms should be fine.
2433de6a9c0SDavid du Colombier 		 */
2443de6a9c0SDavid du Colombier 		uarttimer = addclock0link(uartclock, 22);
2453de6a9c0SDavid du Colombier 	}
2463de6a9c0SDavid du Colombier }
2473de6a9c0SDavid du Colombier 
2483de6a9c0SDavid du Colombier 
2493de6a9c0SDavid du Colombier static Chan*
uartattach(char * spec)2503de6a9c0SDavid du Colombier uartattach(char *spec)
2513de6a9c0SDavid du Colombier {
2523de6a9c0SDavid du Colombier 	return devattach('t', spec);
2533de6a9c0SDavid du Colombier }
2543de6a9c0SDavid du Colombier 
2553de6a9c0SDavid du Colombier static Walkqid*
uartwalk(Chan * c,Chan * nc,char ** name,int nname)2563de6a9c0SDavid du Colombier uartwalk(Chan *c, Chan *nc, char **name, int nname)
2573de6a9c0SDavid du Colombier {
2583de6a9c0SDavid du Colombier 	return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
2593de6a9c0SDavid du Colombier }
2603de6a9c0SDavid du Colombier 
2613de6a9c0SDavid du Colombier static int
uartstat(Chan * c,uchar * dp,int n)2623de6a9c0SDavid du Colombier uartstat(Chan *c, uchar *dp, int n)
2633de6a9c0SDavid du Colombier {
2643de6a9c0SDavid du Colombier 	if(NETTYPE(c->qid.path) == Ndataqid)
2653de6a9c0SDavid du Colombier 		setlength(NETID(c->qid.path));
2663de6a9c0SDavid du Colombier 	return devstat(c, dp, n, uartdir, uartndir, devgen);
2673de6a9c0SDavid du Colombier }
2683de6a9c0SDavid du Colombier 
2693de6a9c0SDavid du Colombier static Chan*
uartopen(Chan * c,int omode)2703de6a9c0SDavid du Colombier uartopen(Chan *c, int omode)
2713de6a9c0SDavid du Colombier {
2723de6a9c0SDavid du Colombier 	Uart *p;
2733de6a9c0SDavid du Colombier 
2743de6a9c0SDavid du Colombier 	c = devopen(c, omode, uartdir, uartndir, devgen);
2753de6a9c0SDavid du Colombier 
2763de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
2773de6a9c0SDavid du Colombier 	case Nctlqid:
2783de6a9c0SDavid du Colombier 	case Ndataqid:
2793de6a9c0SDavid du Colombier 		p = uart[NETID(c->qid.path)];
2803de6a9c0SDavid du Colombier 		qlock(p);
2813de6a9c0SDavid du Colombier 		if(p->opens++ == 0 && uartenable(p) == nil){
2823de6a9c0SDavid du Colombier 			qunlock(p);
2833de6a9c0SDavid du Colombier 			c->flag &= ~COPEN;
2843de6a9c0SDavid du Colombier 			error(Enodev);
2853de6a9c0SDavid du Colombier 		}
2863de6a9c0SDavid du Colombier 		qunlock(p);
2873de6a9c0SDavid du Colombier 		break;
2883de6a9c0SDavid du Colombier 	}
2893de6a9c0SDavid du Colombier 
2903de6a9c0SDavid du Colombier 	c->iounit = qiomaxatomic;
2913de6a9c0SDavid du Colombier 	return c;
2923de6a9c0SDavid du Colombier }
2933de6a9c0SDavid du Colombier 
2943de6a9c0SDavid du Colombier static int
uartdrained(void * arg)2953de6a9c0SDavid du Colombier uartdrained(void* arg)
2963de6a9c0SDavid du Colombier {
2973de6a9c0SDavid du Colombier 	Uart *p;
2983de6a9c0SDavid du Colombier 
2993de6a9c0SDavid du Colombier 	p = arg;
3003de6a9c0SDavid du Colombier 	return qlen(p->oq) == 0 && p->op == p->oe;
3013de6a9c0SDavid du Colombier }
3023de6a9c0SDavid du Colombier 
3033de6a9c0SDavid du Colombier static void
uartdrainoutput(Uart * p)3043de6a9c0SDavid du Colombier uartdrainoutput(Uart *p)
3053de6a9c0SDavid du Colombier {
3063de6a9c0SDavid du Colombier 	if(!p->enabled || up == nil)
3073de6a9c0SDavid du Colombier 		return;
3083de6a9c0SDavid du Colombier 
3093de6a9c0SDavid du Colombier 	p->drain = 1;
3103de6a9c0SDavid du Colombier 	if(waserror()){
3113de6a9c0SDavid du Colombier 		p->drain = 0;
3123de6a9c0SDavid du Colombier 		nexterror();
3133de6a9c0SDavid du Colombier 	}
3143de6a9c0SDavid du Colombier 	sleep(&p->r, uartdrained, p);
3153de6a9c0SDavid du Colombier 	poperror();
3163de6a9c0SDavid du Colombier }
3173de6a9c0SDavid du Colombier 
3183de6a9c0SDavid du Colombier static void
uartclose(Chan * c)3193de6a9c0SDavid du Colombier uartclose(Chan *c)
3203de6a9c0SDavid du Colombier {
3213de6a9c0SDavid du Colombier 	Uart *p;
3223de6a9c0SDavid du Colombier 
3233de6a9c0SDavid du Colombier 	if(c->qid.type & QTDIR)
3243de6a9c0SDavid du Colombier 		return;
3253de6a9c0SDavid du Colombier 	if((c->flag & COPEN) == 0)
3263de6a9c0SDavid du Colombier 		return;
3273de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
3283de6a9c0SDavid du Colombier 	case Ndataqid:
3293de6a9c0SDavid du Colombier 	case Nctlqid:
3303de6a9c0SDavid du Colombier 		p = uart[NETID(c->qid.path)];
3313de6a9c0SDavid du Colombier 		qlock(p);
3323de6a9c0SDavid du Colombier 		if(--(p->opens) == 0){
3333de6a9c0SDavid du Colombier 			qclose(p->iq);
3343de6a9c0SDavid du Colombier 			ilock(&p->rlock);
3353de6a9c0SDavid du Colombier 			p->ir = p->iw = p->istage;
3363de6a9c0SDavid du Colombier 			iunlock(&p->rlock);
3373de6a9c0SDavid du Colombier 
3383de6a9c0SDavid du Colombier 			/*
3393de6a9c0SDavid du Colombier 			 */
3403de6a9c0SDavid du Colombier 			qhangup(p->oq, nil);
3413de6a9c0SDavid du Colombier 			if(!waserror()){
3423de6a9c0SDavid du Colombier 				uartdrainoutput(p);
3433de6a9c0SDavid du Colombier 				poperror();
3443de6a9c0SDavid du Colombier 			}
3453de6a9c0SDavid du Colombier 			qclose(p->oq);
3463de6a9c0SDavid du Colombier 			uartdisable(p);
3473de6a9c0SDavid du Colombier 			p->dcd = p->dsr = p->dohup = 0;
3483de6a9c0SDavid du Colombier 		}
3493de6a9c0SDavid du Colombier 		qunlock(p);
3503de6a9c0SDavid du Colombier 		break;
3513de6a9c0SDavid du Colombier 	}
3523de6a9c0SDavid du Colombier }
3533de6a9c0SDavid du Colombier 
3543de6a9c0SDavid du Colombier static long
uartread(Chan * c,void * buf,long n,vlong off)3553de6a9c0SDavid du Colombier uartread(Chan *c, void *buf, long n, vlong off)
3563de6a9c0SDavid du Colombier {
3573de6a9c0SDavid du Colombier 	Uart *p;
3583de6a9c0SDavid du Colombier 	ulong offset = off;
3593de6a9c0SDavid du Colombier 
3603de6a9c0SDavid du Colombier 	if(c->qid.type & QTDIR){
3613de6a9c0SDavid du Colombier 		setlength(-1);
3623de6a9c0SDavid du Colombier 		return devdirread(c, buf, n, uartdir, uartndir, devgen);
3633de6a9c0SDavid du Colombier 	}
3643de6a9c0SDavid du Colombier 
3653de6a9c0SDavid du Colombier 	p = uart[NETID(c->qid.path)];
3663de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
3673de6a9c0SDavid du Colombier 	case Ndataqid:
3683de6a9c0SDavid du Colombier 		return qread(p->iq, buf, n);
3693de6a9c0SDavid du Colombier 	case Nctlqid:
3703de6a9c0SDavid du Colombier 		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
3713de6a9c0SDavid du Colombier 	case Nstatqid:
3723de6a9c0SDavid du Colombier 		return (*p->phys->status)(p, buf, n, offset);
3733de6a9c0SDavid du Colombier 	}
3743de6a9c0SDavid du Colombier 
3753de6a9c0SDavid du Colombier 	return 0;
3763de6a9c0SDavid du Colombier }
3773de6a9c0SDavid du Colombier 
3783de6a9c0SDavid du Colombier int
uartctl(Uart * p,char * cmd)3793de6a9c0SDavid du Colombier uartctl(Uart *p, char *cmd)
3803de6a9c0SDavid du Colombier {
3813de6a9c0SDavid du Colombier 	char *f[16];
3823de6a9c0SDavid du Colombier 	int i, n, nf;
3833de6a9c0SDavid du Colombier 
3843de6a9c0SDavid du Colombier 	nf = tokenize(cmd, f, nelem(f));
3853de6a9c0SDavid du Colombier 	for(i = 0; i < nf; i++){
3863de6a9c0SDavid du Colombier 		if(strncmp(f[i], "break", 5) == 0){
3873de6a9c0SDavid du Colombier 			(*p->phys->dobreak)(p, 0);
3883de6a9c0SDavid du Colombier 			continue;
3893de6a9c0SDavid du Colombier 		}
3903de6a9c0SDavid du Colombier 
3913de6a9c0SDavid du Colombier 		n = atoi(f[i]+1);
3923de6a9c0SDavid du Colombier 		switch(*f[i]){
3933de6a9c0SDavid du Colombier 		case 'B':
3943de6a9c0SDavid du Colombier 		case 'b':
3953de6a9c0SDavid du Colombier 			uartdrainoutput(p);
3963de6a9c0SDavid du Colombier 			if((*p->phys->baud)(p, n) < 0)
3973de6a9c0SDavid du Colombier 				return -1;
3983de6a9c0SDavid du Colombier 			break;
3993de6a9c0SDavid du Colombier 		case 'C':
4003de6a9c0SDavid du Colombier 		case 'c':
4013de6a9c0SDavid du Colombier 			p->hup_dcd = n;
4023de6a9c0SDavid du Colombier 			break;
4033de6a9c0SDavid du Colombier 		case 'D':
4043de6a9c0SDavid du Colombier 		case 'd':
4053de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4063de6a9c0SDavid du Colombier 			(*p->phys->dtr)(p, n);
4073de6a9c0SDavid du Colombier 			break;
4083de6a9c0SDavid du Colombier 		case 'E':
4093de6a9c0SDavid du Colombier 		case 'e':
4103de6a9c0SDavid du Colombier 			p->hup_dsr = n;
4113de6a9c0SDavid du Colombier 			break;
4123de6a9c0SDavid du Colombier 		case 'f':
4133de6a9c0SDavid du Colombier 		case 'F':
4143de6a9c0SDavid du Colombier 			if(p->oq != nil)
4153de6a9c0SDavid du Colombier 				qflush(p->oq);
4163de6a9c0SDavid du Colombier 			break;
4173de6a9c0SDavid du Colombier 		case 'H':
4183de6a9c0SDavid du Colombier 		case 'h':
4193de6a9c0SDavid du Colombier 			if(p->iq != nil)
4203de6a9c0SDavid du Colombier 				qhangup(p->iq, 0);
4213de6a9c0SDavid du Colombier 			if(p->oq != nil)
4223de6a9c0SDavid du Colombier 				qhangup(p->oq, 0);
4233de6a9c0SDavid du Colombier 			break;
4243de6a9c0SDavid du Colombier 		case 'i':
4253de6a9c0SDavid du Colombier 		case 'I':
4263de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4273de6a9c0SDavid du Colombier 			(*p->phys->fifo)(p, n);
4283de6a9c0SDavid du Colombier 			break;
4293de6a9c0SDavid du Colombier 		case 'K':
4303de6a9c0SDavid du Colombier 		case 'k':
4313de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4323de6a9c0SDavid du Colombier 			(*p->phys->dobreak)(p, n);
4333de6a9c0SDavid du Colombier 			break;
4343de6a9c0SDavid du Colombier 		case 'L':
4353de6a9c0SDavid du Colombier 		case 'l':
4363de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4373de6a9c0SDavid du Colombier 			if((*p->phys->bits)(p, n) < 0)
4383de6a9c0SDavid du Colombier 				return -1;
4393de6a9c0SDavid du Colombier 			break;
4403de6a9c0SDavid du Colombier 		case 'm':
4413de6a9c0SDavid du Colombier 		case 'M':
4423de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4433de6a9c0SDavid du Colombier 			(*p->phys->modemctl)(p, n);
4443de6a9c0SDavid du Colombier 			break;
4453de6a9c0SDavid du Colombier 		case 'n':
4463de6a9c0SDavid du Colombier 		case 'N':
4473de6a9c0SDavid du Colombier 			if(p->oq != nil)
4483de6a9c0SDavid du Colombier 				qnoblock(p->oq, n);
4493de6a9c0SDavid du Colombier 			break;
4503de6a9c0SDavid du Colombier 		case 'P':
4513de6a9c0SDavid du Colombier 		case 'p':
4523de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4533de6a9c0SDavid du Colombier 			if((*p->phys->parity)(p, *(f[i]+1)) < 0)
4543de6a9c0SDavid du Colombier 				return -1;
4553de6a9c0SDavid du Colombier 			break;
4563de6a9c0SDavid du Colombier 		case 'Q':
4573de6a9c0SDavid du Colombier 		case 'q':
4583de6a9c0SDavid du Colombier 			if(p->iq != nil)
4593de6a9c0SDavid du Colombier 				qsetlimit(p->iq, n);
4603de6a9c0SDavid du Colombier 			if(p->oq != nil)
4613de6a9c0SDavid du Colombier 				qsetlimit(p->oq, n);
4623de6a9c0SDavid du Colombier 			break;
4633de6a9c0SDavid du Colombier 		case 'R':
4643de6a9c0SDavid du Colombier 		case 'r':
4653de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4663de6a9c0SDavid du Colombier 			(*p->phys->rts)(p, n);
4673de6a9c0SDavid du Colombier 			break;
4683de6a9c0SDavid du Colombier 		case 'S':
4693de6a9c0SDavid du Colombier 		case 's':
4703de6a9c0SDavid du Colombier 			uartdrainoutput(p);
4713de6a9c0SDavid du Colombier 			if((*p->phys->stop)(p, n) < 0)
4723de6a9c0SDavid du Colombier 				return -1;
4733de6a9c0SDavid du Colombier 			break;
4743de6a9c0SDavid du Colombier 		case 'W':
4753de6a9c0SDavid du Colombier 		case 'w':
4763de6a9c0SDavid du Colombier 			if(uarttimer == nil || n < 1)
4773de6a9c0SDavid du Colombier 				return -1;
4783de6a9c0SDavid du Colombier 			uarttimer->tns = (vlong)n * 100000LL;
4793de6a9c0SDavid du Colombier 			break;
4803de6a9c0SDavid du Colombier 		case 'X':
4813de6a9c0SDavid du Colombier 		case 'x':
4823de6a9c0SDavid du Colombier 			if(p->enabled){
4833de6a9c0SDavid du Colombier 				ilock(&p->tlock);
4843de6a9c0SDavid du Colombier 				p->xonoff = n;
4853de6a9c0SDavid du Colombier 				iunlock(&p->tlock);
4863de6a9c0SDavid du Colombier 			}
4873de6a9c0SDavid du Colombier 			break;
4883de6a9c0SDavid du Colombier 		}
4893de6a9c0SDavid du Colombier 	}
4903de6a9c0SDavid du Colombier 	return 0;
4913de6a9c0SDavid du Colombier }
4923de6a9c0SDavid du Colombier 
4933de6a9c0SDavid du Colombier static long
uartwrite(Chan * c,void * buf,long n,vlong)4943de6a9c0SDavid du Colombier uartwrite(Chan *c, void *buf, long n, vlong)
4953de6a9c0SDavid du Colombier {
4963de6a9c0SDavid du Colombier 	Uart *p;
4973de6a9c0SDavid du Colombier 	char *cmd;
4983de6a9c0SDavid du Colombier 
4993de6a9c0SDavid du Colombier 	if(c->qid.type & QTDIR)
5003de6a9c0SDavid du Colombier 		error(Eperm);
5013de6a9c0SDavid du Colombier 
5023de6a9c0SDavid du Colombier 	p = uart[NETID(c->qid.path)];
5033de6a9c0SDavid du Colombier 
5043de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
5053de6a9c0SDavid du Colombier 	case Ndataqid:
5063de6a9c0SDavid du Colombier 		qlock(p);
5073de6a9c0SDavid du Colombier 		if(waserror()){
5083de6a9c0SDavid du Colombier 			qunlock(p);
5093de6a9c0SDavid du Colombier 			nexterror();
5103de6a9c0SDavid du Colombier 		}
5113de6a9c0SDavid du Colombier 
5123de6a9c0SDavid du Colombier 		n = qwrite(p->oq, buf, n);
5133de6a9c0SDavid du Colombier 
5143de6a9c0SDavid du Colombier 		qunlock(p);
5153de6a9c0SDavid du Colombier 		poperror();
5163de6a9c0SDavid du Colombier 		break;
5173de6a9c0SDavid du Colombier 	case Nctlqid:
5183de6a9c0SDavid du Colombier 		cmd = malloc(n+1);
5193de6a9c0SDavid du Colombier 		memmove(cmd, buf, n);
5203de6a9c0SDavid du Colombier 		cmd[n] = 0;
5213de6a9c0SDavid du Colombier 		qlock(p);
5223de6a9c0SDavid du Colombier 		if(waserror()){
5233de6a9c0SDavid du Colombier 			qunlock(p);
5243de6a9c0SDavid du Colombier 			free(cmd);
5253de6a9c0SDavid du Colombier 			nexterror();
5263de6a9c0SDavid du Colombier 		}
5273de6a9c0SDavid du Colombier 
5283de6a9c0SDavid du Colombier 		/* let output drain */
5293de6a9c0SDavid du Colombier 		if(uartctl(p, cmd) < 0)
5303de6a9c0SDavid du Colombier 			error(Ebadarg);
5313de6a9c0SDavid du Colombier 
5323de6a9c0SDavid du Colombier 		qunlock(p);
5333de6a9c0SDavid du Colombier 		poperror();
5343de6a9c0SDavid du Colombier 		free(cmd);
5353de6a9c0SDavid du Colombier 		break;
5363de6a9c0SDavid du Colombier 	}
5373de6a9c0SDavid du Colombier 
5383de6a9c0SDavid du Colombier 	return n;
5393de6a9c0SDavid du Colombier }
5403de6a9c0SDavid du Colombier 
5413de6a9c0SDavid du Colombier static int
uartwstat(Chan * c,uchar * dp,int n)5423de6a9c0SDavid du Colombier uartwstat(Chan *c, uchar *dp, int n)
5433de6a9c0SDavid du Colombier {
5443de6a9c0SDavid du Colombier 	Dir d;
5453de6a9c0SDavid du Colombier 	Dirtab *dt;
5463de6a9c0SDavid du Colombier 
5473de6a9c0SDavid du Colombier 	if(!iseve())
5483de6a9c0SDavid du Colombier 		error(Eperm);
5493de6a9c0SDavid du Colombier 	if(QTDIR & c->qid.type)
5503de6a9c0SDavid du Colombier 		error(Eperm);
5513de6a9c0SDavid du Colombier 	if(NETTYPE(c->qid.path) == Nstatqid)
5523de6a9c0SDavid du Colombier 		error(Eperm);
5533de6a9c0SDavid du Colombier 
5543de6a9c0SDavid du Colombier 	dt = &uartdir[1 + 3 * NETID(c->qid.path)];
5553de6a9c0SDavid du Colombier 	n = convM2D(dp, n, &d, nil);
5563de6a9c0SDavid du Colombier 	if(n == 0)
5573de6a9c0SDavid du Colombier 		error(Eshortstat);
5583de6a9c0SDavid du Colombier 	if(d.mode != ~0UL)
5593de6a9c0SDavid du Colombier 		dt[0].perm = dt[1].perm = d.mode;
5603de6a9c0SDavid du Colombier 	return n;
5613de6a9c0SDavid du Colombier }
5623de6a9c0SDavid du Colombier 
5633de6a9c0SDavid du Colombier void
uartpower(int on)5643de6a9c0SDavid du Colombier uartpower(int on)
5653de6a9c0SDavid du Colombier {
5663de6a9c0SDavid du Colombier 	Uart *p;
5673de6a9c0SDavid du Colombier 
5683de6a9c0SDavid du Colombier 	for(p = uartlist; p != nil; p = p->next) {
5693de6a9c0SDavid du Colombier 		if(p->phys->power)
5703de6a9c0SDavid du Colombier 			(*p->phys->power)(p, on);
5713de6a9c0SDavid du Colombier 	}
5723de6a9c0SDavid du Colombier }
5733de6a9c0SDavid du Colombier 
5743de6a9c0SDavid du Colombier Dev uartdevtab = {
5753de6a9c0SDavid du Colombier 	't',
5763de6a9c0SDavid du Colombier 	"uart",
5773de6a9c0SDavid du Colombier 
5783de6a9c0SDavid du Colombier 	uartreset,
5793de6a9c0SDavid du Colombier 	devinit,
5803de6a9c0SDavid du Colombier 	devshutdown,
5813de6a9c0SDavid du Colombier 	uartattach,
5823de6a9c0SDavid du Colombier 	uartwalk,
5833de6a9c0SDavid du Colombier 	uartstat,
5843de6a9c0SDavid du Colombier 	uartopen,
5853de6a9c0SDavid du Colombier 	devcreate,
5863de6a9c0SDavid du Colombier 	uartclose,
5873de6a9c0SDavid du Colombier 	uartread,
5883de6a9c0SDavid du Colombier 	devbread,
5893de6a9c0SDavid du Colombier 	uartwrite,
5903de6a9c0SDavid du Colombier 	devbwrite,
5913de6a9c0SDavid du Colombier 	devremove,
5923de6a9c0SDavid du Colombier 	uartwstat,
5933de6a9c0SDavid du Colombier 	uartpower,
5943de6a9c0SDavid du Colombier };
5953de6a9c0SDavid du Colombier 
5963de6a9c0SDavid du Colombier /*
5973de6a9c0SDavid du Colombier  *  restart input if it's off
5983de6a9c0SDavid du Colombier  */
5993de6a9c0SDavid du Colombier static void
uartflow(void * v)6003de6a9c0SDavid du Colombier uartflow(void *v)
6013de6a9c0SDavid du Colombier {
6023de6a9c0SDavid du Colombier 	Uart *p;
6033de6a9c0SDavid du Colombier 
6043de6a9c0SDavid du Colombier 	p = v;
6053de6a9c0SDavid du Colombier 	if(p->modem)
6063de6a9c0SDavid du Colombier 		(*p->phys->rts)(p, 1);
6073de6a9c0SDavid du Colombier }
6083de6a9c0SDavid du Colombier 
6093de6a9c0SDavid du Colombier /*
6103de6a9c0SDavid du Colombier  *  put some bytes into the local queue to avoid calling
6113de6a9c0SDavid du Colombier  *  qconsume for every character
6123de6a9c0SDavid du Colombier  */
6133de6a9c0SDavid du Colombier int
uartstageoutput(Uart * p)6143de6a9c0SDavid du Colombier uartstageoutput(Uart *p)
6153de6a9c0SDavid du Colombier {
6163de6a9c0SDavid du Colombier 	int n;
6173de6a9c0SDavid du Colombier 
6183de6a9c0SDavid du Colombier 	n = qconsume(p->oq, p->ostage, Stagesize);
6193de6a9c0SDavid du Colombier 	if(n <= 0)
6203de6a9c0SDavid du Colombier //		n = 0;			/* experiment */
6213de6a9c0SDavid du Colombier 		return 0;
6223de6a9c0SDavid du Colombier 	p->op = p->ostage;
6233de6a9c0SDavid du Colombier 	p->oe = p->ostage + n;
6243de6a9c0SDavid du Colombier 	return n;
6253de6a9c0SDavid du Colombier }
6263de6a9c0SDavid du Colombier 
6273de6a9c0SDavid du Colombier /*
6283de6a9c0SDavid du Colombier  *  restart output
6293de6a9c0SDavid du Colombier  */
6303de6a9c0SDavid du Colombier void
uartkick(void * v)6313de6a9c0SDavid du Colombier uartkick(void *v)
6323de6a9c0SDavid du Colombier {
6333de6a9c0SDavid du Colombier 	Uart *p = v;
6343de6a9c0SDavid du Colombier 
6353de6a9c0SDavid du Colombier 	if(p->blocked)
6363de6a9c0SDavid du Colombier 		return;
6373de6a9c0SDavid du Colombier 
6383de6a9c0SDavid du Colombier 	ilock(&p->tlock);
6393de6a9c0SDavid du Colombier 	(*p->phys->kick)(p);
6403de6a9c0SDavid du Colombier 	iunlock(&p->tlock);
6413de6a9c0SDavid du Colombier 
6423de6a9c0SDavid du Colombier 	if(p->drain && uartdrained(p)){
6433de6a9c0SDavid du Colombier 		p->drain = 0;
6443de6a9c0SDavid du Colombier 		wakeup(&p->r);
6453de6a9c0SDavid du Colombier 	}
6463de6a9c0SDavid du Colombier }
6473de6a9c0SDavid du Colombier 
6483de6a9c0SDavid du Colombier /*
6493de6a9c0SDavid du Colombier  * Move data from the interrupt staging area to
6503de6a9c0SDavid du Colombier  * the input Queue.
6513de6a9c0SDavid du Colombier  */
6523de6a9c0SDavid du Colombier static void
uartstageinput(Uart * p)6533de6a9c0SDavid du Colombier uartstageinput(Uart *p)
6543de6a9c0SDavid du Colombier {
6553de6a9c0SDavid du Colombier 	int n;
6563de6a9c0SDavid du Colombier 	uchar *ir, *iw;
6573de6a9c0SDavid du Colombier 
6583de6a9c0SDavid du Colombier 	while(p->ir != p->iw){
6593de6a9c0SDavid du Colombier 		ir = p->ir;
6603de6a9c0SDavid du Colombier 		if(p->ir > p->iw){
6613de6a9c0SDavid du Colombier 			iw = p->ie;
6623de6a9c0SDavid du Colombier 			p->ir = p->istage;
6633de6a9c0SDavid du Colombier 		}
6643de6a9c0SDavid du Colombier 		else{
6653de6a9c0SDavid du Colombier 			iw = p->iw;
6663de6a9c0SDavid du Colombier 			p->ir = p->iw;
6673de6a9c0SDavid du Colombier 		}
6683de6a9c0SDavid du Colombier 		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
6693de6a9c0SDavid du Colombier 			p->serr++;
6703de6a9c0SDavid du Colombier 			(*p->phys->rts)(p, 0);
6713de6a9c0SDavid du Colombier 		}
6723de6a9c0SDavid du Colombier 		else if(n == 0)
6733de6a9c0SDavid du Colombier 			p->berr++;
6743de6a9c0SDavid du Colombier 	}
6753de6a9c0SDavid du Colombier }
6763de6a9c0SDavid du Colombier 
6773de6a9c0SDavid du Colombier /*
6783de6a9c0SDavid du Colombier  *  receive a character at interrupt time
6793de6a9c0SDavid du Colombier  */
6803de6a9c0SDavid du Colombier void
uartrecv(Uart * p,char ch)6813de6a9c0SDavid du Colombier uartrecv(Uart *p,  char ch)
6823de6a9c0SDavid du Colombier {
6833de6a9c0SDavid du Colombier 	uchar *next;
6843de6a9c0SDavid du Colombier 
6853de6a9c0SDavid du Colombier 	/* software flow control */
6863de6a9c0SDavid du Colombier 	if(p->xonoff){
6873de6a9c0SDavid du Colombier 		if(ch == CTLS){
6883de6a9c0SDavid du Colombier 			p->blocked = 1;
6893de6a9c0SDavid du Colombier 		}else if(ch == CTLQ){
6903de6a9c0SDavid du Colombier 			p->blocked = 0;
6913de6a9c0SDavid du Colombier 			p->ctsbackoff = 2; /* clock gets output going again */
6923de6a9c0SDavid du Colombier 		}
6933de6a9c0SDavid du Colombier 	}
6943de6a9c0SDavid du Colombier 
6953de6a9c0SDavid du Colombier 	/* receive the character */
6963de6a9c0SDavid du Colombier 	if(p->putc)
6973de6a9c0SDavid du Colombier 		p->putc(p->iq, ch);
6983de6a9c0SDavid du Colombier 	else if (p->iw) {		/* maybe the line isn't enabled yet */
6993de6a9c0SDavid du Colombier 		ilock(&p->rlock);
7003de6a9c0SDavid du Colombier 		next = p->iw + 1;
7013de6a9c0SDavid du Colombier 		if(next == p->ie)
7023de6a9c0SDavid du Colombier 			next = p->istage;
7033de6a9c0SDavid du Colombier 		if(next == p->ir)
7043de6a9c0SDavid du Colombier 			uartstageinput(p);
7053de6a9c0SDavid du Colombier 		if(next != p->ir){
7063de6a9c0SDavid du Colombier 			*p->iw = ch;
7073de6a9c0SDavid du Colombier 			p->iw = next;
7083de6a9c0SDavid du Colombier 		}
7093de6a9c0SDavid du Colombier 		iunlock(&p->rlock);
7103de6a9c0SDavid du Colombier 	}
7113de6a9c0SDavid du Colombier }
7123de6a9c0SDavid du Colombier 
7133de6a9c0SDavid du Colombier /*
7143de6a9c0SDavid du Colombier  *  we save up input characters till clock time to reduce
7153de6a9c0SDavid du Colombier  *  per character interrupt overhead.
7163de6a9c0SDavid du Colombier  */
7173de6a9c0SDavid du Colombier static void
uartclock(void)7183de6a9c0SDavid du Colombier uartclock(void)
7193de6a9c0SDavid du Colombier {
7203de6a9c0SDavid du Colombier 	Uart *p;
7213de6a9c0SDavid du Colombier 
7223de6a9c0SDavid du Colombier 	ilock(&uartalloc);
7233de6a9c0SDavid du Colombier 	for(p = uartalloc.elist; p; p = p->elist){
7243de6a9c0SDavid du Colombier 
7253de6a9c0SDavid du Colombier 		/* this hopefully amortizes cost of qproduce to many chars */
7263de6a9c0SDavid du Colombier 		if(p->iw != p->ir){
7273de6a9c0SDavid du Colombier 			ilock(&p->rlock);
7283de6a9c0SDavid du Colombier 			uartstageinput(p);
7293de6a9c0SDavid du Colombier 			iunlock(&p->rlock);
7303de6a9c0SDavid du Colombier 		}
7313de6a9c0SDavid du Colombier 
7323de6a9c0SDavid du Colombier 		/* hang up if requested */
7333de6a9c0SDavid du Colombier 		if(p->dohup){
7343de6a9c0SDavid du Colombier 			qhangup(p->iq, 0);
7353de6a9c0SDavid du Colombier 			qhangup(p->oq, 0);
7363de6a9c0SDavid du Colombier 			p->dohup = 0;
7373de6a9c0SDavid du Colombier 		}
7383de6a9c0SDavid du Colombier 
7393de6a9c0SDavid du Colombier 		/* this adds hysteresis to hardware/software flow control */
7403de6a9c0SDavid du Colombier 		if(p->ctsbackoff){
7413de6a9c0SDavid du Colombier 			ilock(&p->tlock);
7423de6a9c0SDavid du Colombier 			if(p->ctsbackoff){
7433de6a9c0SDavid du Colombier 				if(--(p->ctsbackoff) == 0)
7443de6a9c0SDavid du Colombier 					(*p->phys->kick)(p);
7453de6a9c0SDavid du Colombier 			}
7463de6a9c0SDavid du Colombier 			iunlock(&p->tlock);
7473de6a9c0SDavid du Colombier 		}
7483de6a9c0SDavid du Colombier 		uartkick(p);		/* keep it moving */
7493de6a9c0SDavid du Colombier 	}
7503de6a9c0SDavid du Colombier 	iunlock(&uartalloc);
7513de6a9c0SDavid du Colombier }
7523de6a9c0SDavid du Colombier 
7533de6a9c0SDavid du Colombier /*
7543de6a9c0SDavid du Colombier  * polling console input, output
7553de6a9c0SDavid du Colombier  */
7563de6a9c0SDavid du Colombier 
7573de6a9c0SDavid du Colombier Uart* consuart;
7583de6a9c0SDavid du Colombier 
7593de6a9c0SDavid du Colombier int
uartgetc(void)7603de6a9c0SDavid du Colombier uartgetc(void)
7613de6a9c0SDavid du Colombier {
7623de6a9c0SDavid du Colombier 	if(consuart == nil || consuart->phys->getc == nil)
7633de6a9c0SDavid du Colombier 		return -1;
7643de6a9c0SDavid du Colombier 	return consuart->phys->getc(consuart);
7653de6a9c0SDavid du Colombier }
7663de6a9c0SDavid du Colombier 
7673de6a9c0SDavid du Colombier void
uartputc(int c)7683de6a9c0SDavid du Colombier uartputc(int c)
7693de6a9c0SDavid du Colombier {
7703de6a9c0SDavid du Colombier 	char c2;
7713de6a9c0SDavid du Colombier 
7723de6a9c0SDavid du Colombier 	if(consuart == nil || consuart->phys->putc == nil) {
7733de6a9c0SDavid du Colombier 		c2 = c;
774*696c1e60SDavid du Colombier 		if (lprint)
775*696c1e60SDavid du Colombier 			(*lprint)(&c2, 1);
7763de6a9c0SDavid du Colombier 		return;
7773de6a9c0SDavid du Colombier 	}
7783de6a9c0SDavid du Colombier 	consuart->phys->putc(consuart, c);
7793de6a9c0SDavid du Colombier }
7803de6a9c0SDavid du Colombier 
7813de6a9c0SDavid du Colombier void
uartputs(char * s,int n)7823de6a9c0SDavid du Colombier uartputs(char *s, int n)
7833de6a9c0SDavid du Colombier {
7843de6a9c0SDavid du Colombier 	char *e;
7853de6a9c0SDavid du Colombier 
7863de6a9c0SDavid du Colombier 	if(consuart == nil || consuart->phys->putc == nil) {
787*696c1e60SDavid du Colombier 		if (lprint)
788*696c1e60SDavid du Colombier 			(*lprint)(s, n);
7893de6a9c0SDavid du Colombier 		return;
7903de6a9c0SDavid du Colombier 	}
7913de6a9c0SDavid du Colombier 
7923de6a9c0SDavid du Colombier 	e = s+n;
7933de6a9c0SDavid du Colombier 	for(; s<e; s++){
7943de6a9c0SDavid du Colombier 		if(*s == '\n')
7953de6a9c0SDavid du Colombier 			consuart->phys->putc(consuart, '\r');
7963de6a9c0SDavid du Colombier 		consuart->phys->putc(consuart, *s);
7973de6a9c0SDavid du Colombier 	}
7983de6a9c0SDavid du Colombier }
799