xref: /plan9-contrib/sys/src/9k/port/devuart.c (revision 45e6af3b6d7025ef7184352bb3f6852edd8de07e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"io.h"
79ef1f84bSDavid du Colombier #include	"../port/error.h"
89ef1f84bSDavid du Colombier 
99ef1f84bSDavid du Colombier enum {
109ef1f84bSDavid du Colombier 	Qdir		= 0,
119ef1f84bSDavid du Colombier 	Qdata,
129ef1f84bSDavid du Colombier 	Qctl,
139ef1f84bSDavid du Colombier 	Qstat,
149ef1f84bSDavid du Colombier };
159ef1f84bSDavid du Colombier 
169ef1f84bSDavid du Colombier #define UARTTYPE(x)	(((unsigned)x)&0x1f)
179ef1f84bSDavid du Colombier #define UARTID(x)	((((unsigned)x))>>5)
189ef1f84bSDavid du Colombier #define UARTQID(i, t)	((((unsigned)i)<<5)|(t))
199ef1f84bSDavid du Colombier 
209ef1f84bSDavid du Colombier enum
219ef1f84bSDavid du Colombier {
229ef1f84bSDavid du Colombier 	/* soft flow control chars */
239ef1f84bSDavid du Colombier 	CTLS= 023,
249ef1f84bSDavid du Colombier 	CTLQ= 021,
259ef1f84bSDavid du Colombier };
269ef1f84bSDavid du Colombier 
279ef1f84bSDavid du Colombier extern Dev uartdevtab;
289ef1f84bSDavid du Colombier extern PhysUart* physuart[];
299ef1f84bSDavid du Colombier 
309ef1f84bSDavid du Colombier static Uart* uartlist;
319ef1f84bSDavid du Colombier static Uart** uart;
329ef1f84bSDavid du Colombier static int uartnuart;
339ef1f84bSDavid du Colombier static Dirtab *uartdir;
349ef1f84bSDavid du Colombier static int uartndir;
359ef1f84bSDavid du Colombier static Timer *uarttimer;
369ef1f84bSDavid du Colombier 
379ef1f84bSDavid du Colombier struct Uartalloc {
389ef1f84bSDavid du Colombier 	Lock;
399ef1f84bSDavid du Colombier 	Uart *elist;	/* list of enabled interfaces */
409ef1f84bSDavid du Colombier } uartalloc;
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier static void	uartclock(void);
439ef1f84bSDavid du Colombier static void	uartflow(void*);
449ef1f84bSDavid du Colombier 
459ef1f84bSDavid du Colombier /*
469ef1f84bSDavid du Colombier  *  enable/disable uart and add/remove to list of enabled uarts
479ef1f84bSDavid du Colombier  */
48406c76faSDavid du Colombier Uart*
uartenable(Uart * p)499ef1f84bSDavid du Colombier uartenable(Uart *p)
509ef1f84bSDavid du Colombier {
519ef1f84bSDavid du Colombier 	Uart **l;
529ef1f84bSDavid du Colombier 
53406c76faSDavid du Colombier 	if(p->enabled)
54406c76faSDavid du Colombier 		return p;
559ef1f84bSDavid du Colombier 	if(p->iq == nil){
569ef1f84bSDavid du Colombier 		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
579ef1f84bSDavid du Colombier 			return nil;
589ef1f84bSDavid du Colombier 	}
599ef1f84bSDavid du Colombier 	else
609ef1f84bSDavid du Colombier 		qreopen(p->iq);
619ef1f84bSDavid du Colombier 	if(p->oq == nil){
629ef1f84bSDavid du Colombier 		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
639ef1f84bSDavid du Colombier 			qfree(p->iq);
649ef1f84bSDavid du Colombier 			p->iq = nil;
659ef1f84bSDavid du Colombier 			return nil;
669ef1f84bSDavid du Colombier 		}
679ef1f84bSDavid du Colombier 	}
689ef1f84bSDavid du Colombier 	else
699ef1f84bSDavid du Colombier 		qreopen(p->oq);
709ef1f84bSDavid du Colombier 
719ef1f84bSDavid du Colombier 	p->ir = p->istage;
729ef1f84bSDavid du Colombier 	p->iw = p->istage;
739ef1f84bSDavid du Colombier 	p->ie = &p->istage[Stagesize];
749ef1f84bSDavid du Colombier 	p->op = p->ostage;
759ef1f84bSDavid du Colombier 	p->oe = p->ostage;
769ef1f84bSDavid du Colombier 
779ef1f84bSDavid du Colombier 	p->hup_dsr = p->hup_dcd = 0;
789ef1f84bSDavid du Colombier 	p->dsr = p->dcd = 0;
799ef1f84bSDavid du Colombier 
809ef1f84bSDavid du Colombier 	/* assume we can send */
819ef1f84bSDavid du Colombier 	p->cts = 1;
829ef1f84bSDavid du Colombier 	p->ctsbackoff = 0;
839ef1f84bSDavid du Colombier 
849ef1f84bSDavid du Colombier 	if(p->bits == 0)
859ef1f84bSDavid du Colombier 		uartctl(p, "l8");
869ef1f84bSDavid du Colombier 	if(p->stop == 0)
879ef1f84bSDavid du Colombier 		uartctl(p, "s1");
889ef1f84bSDavid du Colombier 	if(p->parity == 0)
899ef1f84bSDavid du Colombier 		uartctl(p, "pn");
909ef1f84bSDavid du Colombier 	if(p->baud == 0)
919ef1f84bSDavid du Colombier 		uartctl(p, "b9600");
929ef1f84bSDavid du Colombier 	(*p->phys->enable)(p, 1);
939ef1f84bSDavid du Colombier 
94406c76faSDavid du Colombier 	/*
95406c76faSDavid du Colombier 	 * use ilock because uartclock can otherwise interrupt here
96406c76faSDavid du Colombier 	 * and would hang on an attempt to lock uartalloc.
97406c76faSDavid du Colombier 	 */
98406c76faSDavid du Colombier 	ilock(&uartalloc);
999ef1f84bSDavid du Colombier 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
1009ef1f84bSDavid du Colombier 		if(*l == p)
1019ef1f84bSDavid du Colombier 			break;
1029ef1f84bSDavid du Colombier 	}
1039ef1f84bSDavid du Colombier 	if(*l == 0){
1049ef1f84bSDavid du Colombier 		p->elist = uartalloc.elist;
1059ef1f84bSDavid du Colombier 		uartalloc.elist = p;
1069ef1f84bSDavid du Colombier 	}
1079ef1f84bSDavid du Colombier 	p->enabled = 1;
108406c76faSDavid du Colombier 	iunlock(&uartalloc);
1099ef1f84bSDavid du Colombier 
1109ef1f84bSDavid du Colombier 	return p;
1119ef1f84bSDavid du Colombier }
1129ef1f84bSDavid du Colombier 
1139ef1f84bSDavid du Colombier static void
uartdisable(Uart * p)1149ef1f84bSDavid du Colombier uartdisable(Uart *p)
1159ef1f84bSDavid du Colombier {
1169ef1f84bSDavid du Colombier 	Uart **l;
1179ef1f84bSDavid du Colombier 
118406c76faSDavid du Colombier 	if(!p->enabled)
119406c76faSDavid du Colombier 		return;
1209ef1f84bSDavid du Colombier 	(*p->phys->disable)(p);
1219ef1f84bSDavid du Colombier 
122406c76faSDavid du Colombier 	ilock(&uartalloc);
1239ef1f84bSDavid du Colombier 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
1249ef1f84bSDavid du Colombier 		if(*l == p){
1259ef1f84bSDavid du Colombier 			*l = p->elist;
1269ef1f84bSDavid du Colombier 			break;
1279ef1f84bSDavid du Colombier 		}
1289ef1f84bSDavid du Colombier 	}
1299ef1f84bSDavid du Colombier 	p->enabled = 0;
130406c76faSDavid du Colombier 	iunlock(&uartalloc);
1319ef1f84bSDavid du Colombier }
1329ef1f84bSDavid du Colombier 
1339ef1f84bSDavid du Colombier Uart*
uartconsole(int i,char * cmd)1349ef1f84bSDavid du Colombier uartconsole(int i, char *cmd)
1359ef1f84bSDavid du Colombier {
1369ef1f84bSDavid du Colombier 	Uart *p;
1379ef1f84bSDavid du Colombier 
1389ef1f84bSDavid du Colombier 	if(i >= uartnuart || (p = uart[i]) == nil)
1399ef1f84bSDavid du Colombier 		return nil;
1409ef1f84bSDavid du Colombier 
1419ef1f84bSDavid du Colombier 	qlock(p);
1429ef1f84bSDavid du Colombier 	if(!p->console){
1439ef1f84bSDavid du Colombier 		if(p->opens == 0 && uartenable(p) == nil){
1449ef1f84bSDavid du Colombier 			qunlock(p);
1459ef1f84bSDavid du Colombier 			return nil;
1469ef1f84bSDavid du Colombier 		}
1479ef1f84bSDavid du Colombier 		p->opens++;
1489ef1f84bSDavid du Colombier 
1499ef1f84bSDavid du Colombier 		addkbdq(p->iq, -1);
1509ef1f84bSDavid du Colombier 		addconsdev(p->oq, uartputs, 2, 0);
1519ef1f84bSDavid du Colombier 		p->putc = kbdcr2nl;
1529ef1f84bSDavid du Colombier 		if(cmd != nil && *cmd != '\0')
1539ef1f84bSDavid du Colombier 			uartctl(p, cmd);
1549ef1f84bSDavid du Colombier 
1559ef1f84bSDavid du Colombier 		p->console = 1;
1569ef1f84bSDavid du Colombier 	}
1579ef1f84bSDavid du Colombier 	qunlock(p);
1589ef1f84bSDavid du Colombier 
1599ef1f84bSDavid du Colombier 	return p;
1609ef1f84bSDavid du Colombier }
1619ef1f84bSDavid du Colombier 
162*45e6af3bSDavid du Colombier void
uartmouse(Uart * p,int (* putc)(Queue *,int),int setb1200)163*45e6af3bSDavid du Colombier uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
164*45e6af3bSDavid du Colombier {
165*45e6af3bSDavid du Colombier 	qlock(p);
166*45e6af3bSDavid du Colombier 	if(p->opens++ == 0 && uartenable(p) == nil){
167*45e6af3bSDavid du Colombier 		qunlock(p);
168*45e6af3bSDavid du Colombier 		error(Enodev);
169*45e6af3bSDavid du Colombier 	}
170*45e6af3bSDavid du Colombier 	if(setb1200)
171*45e6af3bSDavid du Colombier 		uartctl(p, "b1200");
172*45e6af3bSDavid du Colombier 	p->putc = putc;
173*45e6af3bSDavid du Colombier 	p->special = 1;
174*45e6af3bSDavid du Colombier 	qunlock(p);
175*45e6af3bSDavid du Colombier }
176*45e6af3bSDavid du Colombier 
177*45e6af3bSDavid du Colombier void
uartsetmouseputc(Uart * p,int (* putc)(Queue *,int))178*45e6af3bSDavid du Colombier uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
179*45e6af3bSDavid du Colombier {
180*45e6af3bSDavid du Colombier 	qlock(p);
181*45e6af3bSDavid du Colombier 	if(p->opens == 0 || p->special == 0){
182*45e6af3bSDavid du Colombier 		qunlock(p);
183*45e6af3bSDavid du Colombier 		error(Enodev);
184*45e6af3bSDavid du Colombier 	}
185*45e6af3bSDavid du Colombier 	p->putc = putc;
186*45e6af3bSDavid du Colombier 	qunlock(p);
187*45e6af3bSDavid du Colombier }
188*45e6af3bSDavid du Colombier 
1899ef1f84bSDavid du Colombier static void
uartsetlength(int i)1909ef1f84bSDavid du Colombier uartsetlength(int i)
1919ef1f84bSDavid du Colombier {
1929ef1f84bSDavid du Colombier 	Uart *p;
1939ef1f84bSDavid du Colombier 
1949ef1f84bSDavid du Colombier 	if(i > 0){
1959ef1f84bSDavid du Colombier 		p = uart[i];
1969ef1f84bSDavid du Colombier 		if(p && p->opens && p->iq)
1979ef1f84bSDavid du Colombier 			uartdir[1+3*i].length = qlen(p->iq);
1989ef1f84bSDavid du Colombier 	} else for(i = 0; i < uartnuart; i++){
1999ef1f84bSDavid du Colombier 		p = uart[i];
2009ef1f84bSDavid du Colombier 		if(p && p->opens && p->iq)
2019ef1f84bSDavid du Colombier 			uartdir[1+3*i].length = qlen(p->iq);
2029ef1f84bSDavid du Colombier 	}
2039ef1f84bSDavid du Colombier }
2049ef1f84bSDavid du Colombier 
2059ef1f84bSDavid du Colombier /*
2069ef1f84bSDavid du Colombier  *  set up the '#t' directory
2079ef1f84bSDavid du Colombier  */
2089ef1f84bSDavid du Colombier static void
uartreset(void)2099ef1f84bSDavid du Colombier uartreset(void)
2109ef1f84bSDavid du Colombier {
2119ef1f84bSDavid du Colombier 	int i;
2129ef1f84bSDavid du Colombier 	Dirtab *dp;
2139ef1f84bSDavid du Colombier 	Uart *p, *tail;
2149ef1f84bSDavid du Colombier 
2159ef1f84bSDavid du Colombier 	tail = nil;
2169ef1f84bSDavid du Colombier 	for(i = 0; physuart[i] != nil; i++){
2179ef1f84bSDavid du Colombier 		if(physuart[i]->pnp == nil)
2189ef1f84bSDavid du Colombier 			continue;
2199ef1f84bSDavid du Colombier 		if((p = physuart[i]->pnp()) == nil)
2209ef1f84bSDavid du Colombier 			continue;
2219ef1f84bSDavid du Colombier 		if(uartlist != nil)
2229ef1f84bSDavid du Colombier 			tail->next = p;
2239ef1f84bSDavid du Colombier 		else
2249ef1f84bSDavid du Colombier 			uartlist = p;
2259ef1f84bSDavid du Colombier 		for(tail = p; tail->next != nil; tail = tail->next)
2269ef1f84bSDavid du Colombier 			uartnuart++;
2279ef1f84bSDavid du Colombier 		uartnuart++;
2289ef1f84bSDavid du Colombier 	}
2299ef1f84bSDavid du Colombier 
2309ef1f84bSDavid du Colombier //fix the case of uartnuart == 0, will panic below
2319ef1f84bSDavid du Colombier 	if(uartnuart)
2329ef1f84bSDavid du Colombier 		uart = malloc(uartnuart*sizeof(Uart*));
2339ef1f84bSDavid du Colombier 
2349ef1f84bSDavid du Colombier 	uartndir = 1 + 3*uartnuart;
2359ef1f84bSDavid du Colombier 	uartdir = malloc(uartndir * sizeof(Dirtab));
2369ef1f84bSDavid du Colombier 	if(uart == nil || uartdir == nil){
2379ef1f84bSDavid du Colombier 		panic("uartreset: no memory %#p (%ud) %#p (%ud)",
2389ef1f84bSDavid du Colombier 			uart, uartnuart*sizeof(Uart*),
2399ef1f84bSDavid du Colombier 			uartdir, uartndir * sizeof(Dirtab));
2409ef1f84bSDavid du Colombier 	}
2419ef1f84bSDavid du Colombier 	dp = uartdir;
2429ef1f84bSDavid du Colombier 	strcpy(dp->name, ".");
2439ef1f84bSDavid du Colombier 	mkqid(&dp->qid, 0, 0, QTDIR);
2449ef1f84bSDavid du Colombier 	dp->length = 0;
2459ef1f84bSDavid du Colombier 	dp->perm = DMDIR|0555;
2469ef1f84bSDavid du Colombier 	dp++;
2479ef1f84bSDavid du Colombier 	p = uartlist;
2489ef1f84bSDavid du Colombier 	for(i = 0; i < uartnuart; i++){
2499ef1f84bSDavid du Colombier 		/* 3 directory entries per port */
250406c76faSDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%d", i);
2519ef1f84bSDavid du Colombier 		dp->qid.path = UARTQID(i, Qdata);
2529ef1f84bSDavid du Colombier 		dp->perm = 0660;
2539ef1f84bSDavid du Colombier 		dp++;
254406c76faSDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%dctl", i);
2559ef1f84bSDavid du Colombier 		dp->qid.path = UARTQID(i, Qctl);
2569ef1f84bSDavid du Colombier 		dp->perm = 0660;
2579ef1f84bSDavid du Colombier 		dp++;
258406c76faSDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
2599ef1f84bSDavid du Colombier 		dp->qid.path = UARTQID(i, Qstat);
2609ef1f84bSDavid du Colombier 		dp->perm = 0444;
2619ef1f84bSDavid du Colombier 		dp++;
2629ef1f84bSDavid du Colombier 
2639ef1f84bSDavid du Colombier 		uart[i] = p;
2649ef1f84bSDavid du Colombier 		p->dev = i;
2659ef1f84bSDavid du Colombier 		if(p->console || p->special){
2669ef1f84bSDavid du Colombier 			/*
2679ef1f84bSDavid du Colombier 			 * No qlock here, only called at boot time.
2689ef1f84bSDavid du Colombier 			 */
2699ef1f84bSDavid du Colombier 			if(uartenable(p) != nil){
2709ef1f84bSDavid du Colombier 				if(p->console){
2719ef1f84bSDavid du Colombier 					addkbdq(p->iq, -1);
2729ef1f84bSDavid du Colombier 					addconsdev(p->oq, uartputs, 2, 0);
2739ef1f84bSDavid du Colombier 					p->putc = kbdcr2nl;
2749ef1f84bSDavid du Colombier 				}
2759ef1f84bSDavid du Colombier 				p->opens++;
2769ef1f84bSDavid du Colombier 			}
2779ef1f84bSDavid du Colombier 		}
2789ef1f84bSDavid du Colombier 		p = p->next;
2799ef1f84bSDavid du Colombier 	}
2809ef1f84bSDavid du Colombier 
2819ef1f84bSDavid du Colombier 	if(uartnuart){
2829ef1f84bSDavid du Colombier 		/*
2839ef1f84bSDavid du Colombier 		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
2849ef1f84bSDavid du Colombier 		 * processing it every 22 ms should be fine.
2859ef1f84bSDavid du Colombier 		 */
2869ef1f84bSDavid du Colombier 		uarttimer = addclock0link(uartclock, 22);
2879ef1f84bSDavid du Colombier 	}
2889ef1f84bSDavid du Colombier }
2899ef1f84bSDavid du Colombier 
2909ef1f84bSDavid du Colombier 
2919ef1f84bSDavid du Colombier static Chan*
uartattach(char * spec)2929ef1f84bSDavid du Colombier uartattach(char *spec)
2939ef1f84bSDavid du Colombier {
2949ef1f84bSDavid du Colombier 	return devattach('t', spec);
2959ef1f84bSDavid du Colombier }
2969ef1f84bSDavid du Colombier 
2979ef1f84bSDavid du Colombier static Walkqid*
uartwalk(Chan * c,Chan * nc,char ** name,int nname)2989ef1f84bSDavid du Colombier uartwalk(Chan *c, Chan *nc, char **name, int nname)
2999ef1f84bSDavid du Colombier {
3009ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier 
3039ef1f84bSDavid du Colombier static long
uartstat(Chan * c,uchar * dp,long n)3049ef1f84bSDavid du Colombier uartstat(Chan *c, uchar *dp, long n)
3059ef1f84bSDavid du Colombier {
3069ef1f84bSDavid du Colombier 	if(UARTTYPE(c->qid.path) == Qdata)
3079ef1f84bSDavid du Colombier 		uartsetlength(UARTID(c->qid.path));
3089ef1f84bSDavid du Colombier 	return devstat(c, dp, n, uartdir, uartndir, devgen);
3099ef1f84bSDavid du Colombier }
3109ef1f84bSDavid du Colombier 
3119ef1f84bSDavid du Colombier static Chan*
uartopen(Chan * c,int omode)3129ef1f84bSDavid du Colombier uartopen(Chan *c, int omode)
3139ef1f84bSDavid du Colombier {
3149ef1f84bSDavid du Colombier 	Uart *p;
3159ef1f84bSDavid du Colombier 
3169ef1f84bSDavid du Colombier 	c = devopen(c, omode, uartdir, uartndir, devgen);
3179ef1f84bSDavid du Colombier 
3189ef1f84bSDavid du Colombier 	switch(UARTTYPE(c->qid.path)){
3199ef1f84bSDavid du Colombier 	case Qctl:
3209ef1f84bSDavid du Colombier 	case Qdata:
3219ef1f84bSDavid du Colombier 		p = uart[UARTID(c->qid.path)];
3229ef1f84bSDavid du Colombier 		qlock(p);
3239ef1f84bSDavid du Colombier 		if(p->opens == 0 && uartenable(p) == nil){
3249ef1f84bSDavid du Colombier 			qunlock(p);
3259ef1f84bSDavid du Colombier 			c->flag &= ~COPEN;
3269ef1f84bSDavid du Colombier 			error(Enodev);
3279ef1f84bSDavid du Colombier 		}
3289ef1f84bSDavid du Colombier 		p->opens++;
3299ef1f84bSDavid du Colombier 		qunlock(p);
3309ef1f84bSDavid du Colombier 		break;
3319ef1f84bSDavid du Colombier 	}
3329ef1f84bSDavid du Colombier 
3339ef1f84bSDavid du Colombier 	c->iounit = qiomaxatomic;
3349ef1f84bSDavid du Colombier 	return c;
3359ef1f84bSDavid du Colombier }
3369ef1f84bSDavid du Colombier 
3379ef1f84bSDavid du Colombier static int
uartdrained(void * arg)3389ef1f84bSDavid du Colombier uartdrained(void* arg)
3399ef1f84bSDavid du Colombier {
3409ef1f84bSDavid du Colombier 	Uart *p;
3419ef1f84bSDavid du Colombier 
3429ef1f84bSDavid du Colombier 	p = arg;
3439ef1f84bSDavid du Colombier 	return qlen(p->oq) == 0 && p->op == p->oe;
3449ef1f84bSDavid du Colombier }
3459ef1f84bSDavid du Colombier 
3469ef1f84bSDavid du Colombier static void
uartdrainoutput(Uart * p)3479ef1f84bSDavid du Colombier uartdrainoutput(Uart *p)
3489ef1f84bSDavid du Colombier {
3499ef1f84bSDavid du Colombier 	if(!p->enabled)
3509ef1f84bSDavid du Colombier 		return;
3519ef1f84bSDavid du Colombier 
3529ef1f84bSDavid du Colombier 	p->drain = 1;
3539ef1f84bSDavid du Colombier 	if(waserror()){
3549ef1f84bSDavid du Colombier 		p->drain = 0;
3559ef1f84bSDavid du Colombier 		nexterror();
3569ef1f84bSDavid du Colombier 	}
3579ef1f84bSDavid du Colombier 	sleep(&p->r, uartdrained, p);
3589ef1f84bSDavid du Colombier 	poperror();
3599ef1f84bSDavid du Colombier }
3609ef1f84bSDavid du Colombier 
3619ef1f84bSDavid du Colombier static void
uartclose(Chan * c)3629ef1f84bSDavid du Colombier uartclose(Chan *c)
3639ef1f84bSDavid du Colombier {
3649ef1f84bSDavid du Colombier 	Uart *p;
3659ef1f84bSDavid du Colombier 
3669ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
3679ef1f84bSDavid du Colombier 		return;
3689ef1f84bSDavid du Colombier 	if((c->flag & COPEN) == 0)
3699ef1f84bSDavid du Colombier 		return;
3709ef1f84bSDavid du Colombier 	switch(UARTTYPE(c->qid.path)){
3719ef1f84bSDavid du Colombier 	case Qdata:
3729ef1f84bSDavid du Colombier 	case Qctl:
3739ef1f84bSDavid du Colombier 		p = uart[UARTID(c->qid.path)];
3749ef1f84bSDavid du Colombier 		qlock(p);
3759ef1f84bSDavid du Colombier 		if(--(p->opens) == 0){
3769ef1f84bSDavid du Colombier 			qclose(p->iq);
3779ef1f84bSDavid du Colombier 			ilock(&p->rlock);
3789ef1f84bSDavid du Colombier 			p->ir = p->iw = p->istage;
3799ef1f84bSDavid du Colombier 			iunlock(&p->rlock);
3809ef1f84bSDavid du Colombier 
3819ef1f84bSDavid du Colombier 			/*
3829ef1f84bSDavid du Colombier 			 */
3839ef1f84bSDavid du Colombier 			qhangup(p->oq, nil);
3849ef1f84bSDavid du Colombier 			if(!waserror()){
3859ef1f84bSDavid du Colombier 				uartdrainoutput(p);
3869ef1f84bSDavid du Colombier 				poperror();
3879ef1f84bSDavid du Colombier 			}
3889ef1f84bSDavid du Colombier 			qclose(p->oq);
3899ef1f84bSDavid du Colombier 			uartdisable(p);
3909ef1f84bSDavid du Colombier 			p->dcd = p->dsr = p->dohup = 0;
3919ef1f84bSDavid du Colombier 		}
3929ef1f84bSDavid du Colombier 		qunlock(p);
3939ef1f84bSDavid du Colombier 		break;
3949ef1f84bSDavid du Colombier 	}
3959ef1f84bSDavid du Colombier }
3969ef1f84bSDavid du Colombier 
3979ef1f84bSDavid du Colombier static long
uartread(Chan * c,void * buf,long n,vlong off)3989ef1f84bSDavid du Colombier uartread(Chan *c, void *buf, long n, vlong off)
3999ef1f84bSDavid du Colombier {
4009ef1f84bSDavid du Colombier 	Uart *p;
4019ef1f84bSDavid du Colombier 	ulong offset = off;
4029ef1f84bSDavid du Colombier 
4039ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR){
4049ef1f84bSDavid du Colombier 		uartsetlength(-1);
4059ef1f84bSDavid du Colombier 		return devdirread(c, buf, n, uartdir, uartndir, devgen);
4069ef1f84bSDavid du Colombier 	}
4079ef1f84bSDavid du Colombier 
4089ef1f84bSDavid du Colombier 	p = uart[UARTID(c->qid.path)];
4099ef1f84bSDavid du Colombier 	switch(UARTTYPE(c->qid.path)){
4109ef1f84bSDavid du Colombier 	case Qdata:
4119ef1f84bSDavid du Colombier 		return qread(p->iq, buf, n);
4129ef1f84bSDavid du Colombier 	case Qctl:
4139ef1f84bSDavid du Colombier 		return readnum(offset, buf, n, UARTID(c->qid.path), NUMSIZE);
4149ef1f84bSDavid du Colombier 	case Qstat:
4159ef1f84bSDavid du Colombier 		return (*p->phys->status)(p, buf, n, offset);
4169ef1f84bSDavid du Colombier 	}
4179ef1f84bSDavid du Colombier 
4189ef1f84bSDavid du Colombier 	return 0;
4199ef1f84bSDavid du Colombier }
4209ef1f84bSDavid du Colombier 
4219ef1f84bSDavid du Colombier int
uartctl(Uart * p,char * cmd)4229ef1f84bSDavid du Colombier uartctl(Uart *p, char *cmd)
4239ef1f84bSDavid du Colombier {
4249ef1f84bSDavid du Colombier 	char *f[16];
4259ef1f84bSDavid du Colombier 	int i, n, nf;
4269ef1f84bSDavid du Colombier 
4279ef1f84bSDavid du Colombier 	nf = tokenize(cmd, f, nelem(f));
4289ef1f84bSDavid du Colombier 	for(i = 0; i < nf; i++){
4299ef1f84bSDavid du Colombier 		if(strncmp(f[i], "break", 5) == 0){
4309ef1f84bSDavid du Colombier 			(*p->phys->dobreak)(p, 0);
4319ef1f84bSDavid du Colombier 			continue;
4329ef1f84bSDavid du Colombier 		}
4339ef1f84bSDavid du Colombier 
4349ef1f84bSDavid du Colombier 		n = atoi(f[i]+1);
4359ef1f84bSDavid du Colombier 		switch(*f[i]){
4369ef1f84bSDavid du Colombier 		case 'B':
4379ef1f84bSDavid du Colombier 		case 'b':
4389ef1f84bSDavid du Colombier 			uartdrainoutput(p);
4399ef1f84bSDavid du Colombier 			if((*p->phys->baud)(p, n) < 0)
4409ef1f84bSDavid du Colombier 				return -1;
4419ef1f84bSDavid du Colombier 			break;
4429ef1f84bSDavid du Colombier 		case 'C':
4439ef1f84bSDavid du Colombier 		case 'c':
4449ef1f84bSDavid du Colombier 			p->hup_dcd = n;
4459ef1f84bSDavid du Colombier 			break;
4469ef1f84bSDavid du Colombier 		case 'D':
4479ef1f84bSDavid du Colombier 		case 'd':
4489ef1f84bSDavid du Colombier 			uartdrainoutput(p);
4499ef1f84bSDavid du Colombier 			(*p->phys->dtr)(p, n);
4509ef1f84bSDavid du Colombier 			break;
4519ef1f84bSDavid du Colombier 		case 'E':
4529ef1f84bSDavid du Colombier 		case 'e':
4539ef1f84bSDavid du Colombier 			p->hup_dsr = n;
4549ef1f84bSDavid du Colombier 			break;
4559ef1f84bSDavid du Colombier 		case 'F':
4569ef1f84bSDavid du Colombier 		case 'f':
4579ef1f84bSDavid du Colombier 			if(p->oq != nil)
4589ef1f84bSDavid du Colombier 				qflush(p->oq);
4599ef1f84bSDavid du Colombier 			break;
4609ef1f84bSDavid du Colombier 		case 'H':
4619ef1f84bSDavid du Colombier 		case 'h':
4629ef1f84bSDavid du Colombier 			if(p->iq != nil)
4639ef1f84bSDavid du Colombier 				qhangup(p->iq, 0);
4649ef1f84bSDavid du Colombier 			if(p->oq != nil)
4659ef1f84bSDavid du Colombier 				qhangup(p->oq, 0);
4669ef1f84bSDavid du Colombier 			break;
4679ef1f84bSDavid du Colombier 		case 'I':
4689ef1f84bSDavid du Colombier 		case 'i':
4699ef1f84bSDavid du Colombier 			uartdrainoutput(p);
4709ef1f84bSDavid du Colombier 			(*p->phys->fifo)(p, n);
4719ef1f84bSDavid du Colombier 			break;
4729ef1f84bSDavid du Colombier 		case 'K':
4739ef1f84bSDavid du Colombier 		case 'k':
4749ef1f84bSDavid du Colombier 			uartdrainoutput(p);
4759ef1f84bSDavid du Colombier 			(*p->phys->dobreak)(p, n);
4769ef1f84bSDavid du Colombier 			break;
4779ef1f84bSDavid du Colombier 		case 'L':
4789ef1f84bSDavid du Colombier 		case 'l':
4799ef1f84bSDavid du Colombier 			uartdrainoutput(p);
4809ef1f84bSDavid du Colombier 			if((*p->phys->bits)(p, n) < 0)
4819ef1f84bSDavid du Colombier 				return -1;
4829ef1f84bSDavid du Colombier 			break;
4839ef1f84bSDavid du Colombier 		case 'M':
4849ef1f84bSDavid du Colombier 		case 'm':
4859ef1f84bSDavid du Colombier 			uartdrainoutput(p);
4869ef1f84bSDavid du Colombier 			(*p->phys->modemctl)(p, n);
4879ef1f84bSDavid du Colombier 			break;
4889ef1f84bSDavid du Colombier 		case 'N':
4899ef1f84bSDavid du Colombier 		case 'n':
4909ef1f84bSDavid du Colombier 			if(p->oq != nil)
4919ef1f84bSDavid du Colombier 				qnoblock(p->oq, n);
4929ef1f84bSDavid du Colombier 			break;
4939ef1f84bSDavid du Colombier 		case 'P':
4949ef1f84bSDavid du Colombier 		case 'p':
4959ef1f84bSDavid du Colombier 			uartdrainoutput(p);
4969ef1f84bSDavid du Colombier 			if((*p->phys->parity)(p, *(f[i]+1)) < 0)
4979ef1f84bSDavid du Colombier 				return -1;
4989ef1f84bSDavid du Colombier 			break;
4999ef1f84bSDavid du Colombier 		case 'Q':
5009ef1f84bSDavid du Colombier 		case 'q':
5019ef1f84bSDavid du Colombier 			if(p->iq != nil)
5029ef1f84bSDavid du Colombier 				qsetlimit(p->iq, n);
5039ef1f84bSDavid du Colombier 			if(p->oq != nil)
5049ef1f84bSDavid du Colombier 				qsetlimit(p->oq, n);
5059ef1f84bSDavid du Colombier 			break;
5069ef1f84bSDavid du Colombier 		case 'R':
5079ef1f84bSDavid du Colombier 		case 'r':
5089ef1f84bSDavid du Colombier 			uartdrainoutput(p);
5099ef1f84bSDavid du Colombier 			(*p->phys->rts)(p, n);
5109ef1f84bSDavid du Colombier 			break;
5119ef1f84bSDavid du Colombier 		case 'S':
5129ef1f84bSDavid du Colombier 		case 's':
5139ef1f84bSDavid du Colombier 			uartdrainoutput(p);
5149ef1f84bSDavid du Colombier 			if((*p->phys->stop)(p, n) < 0)
5159ef1f84bSDavid du Colombier 				return -1;
5169ef1f84bSDavid du Colombier 			break;
5179ef1f84bSDavid du Colombier 		case 'W':
5189ef1f84bSDavid du Colombier 		case 'w':
5199ef1f84bSDavid du Colombier 			if(uarttimer == nil || n < 1)
5209ef1f84bSDavid du Colombier 				return -1;
5219ef1f84bSDavid du Colombier 			uarttimer->tns = (vlong)n * 100000LL;
5229ef1f84bSDavid du Colombier 			break;
5239ef1f84bSDavid du Colombier 		case 'X':
5249ef1f84bSDavid du Colombier 		case 'x':
5259ef1f84bSDavid du Colombier 			if(p->enabled){
5269ef1f84bSDavid du Colombier 				ilock(&p->tlock);
5279ef1f84bSDavid du Colombier 				p->xonoff = n;
5289ef1f84bSDavid du Colombier 				iunlock(&p->tlock);
5299ef1f84bSDavid du Colombier 			}
5309ef1f84bSDavid du Colombier 			break;
5319ef1f84bSDavid du Colombier 		}
5329ef1f84bSDavid du Colombier 	}
5339ef1f84bSDavid du Colombier 	return 0;
5349ef1f84bSDavid du Colombier }
5359ef1f84bSDavid du Colombier 
5369ef1f84bSDavid du Colombier static long
uartwrite(Chan * c,void * buf,long n,vlong)5379ef1f84bSDavid du Colombier uartwrite(Chan *c, void *buf, long n, vlong)
5389ef1f84bSDavid du Colombier {
5399ef1f84bSDavid du Colombier 	Uart *p;
5409ef1f84bSDavid du Colombier 	char *cmd;
5419ef1f84bSDavid du Colombier 
5429ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
5439ef1f84bSDavid du Colombier 		error(Eperm);
5449ef1f84bSDavid du Colombier 
5459ef1f84bSDavid du Colombier 	p = uart[UARTID(c->qid.path)];
5469ef1f84bSDavid du Colombier 
5479ef1f84bSDavid du Colombier 	switch(UARTTYPE(c->qid.path)){
5489ef1f84bSDavid du Colombier 	case Qdata:
5499ef1f84bSDavid du Colombier 		qlock(p);
5509ef1f84bSDavid du Colombier 		if(waserror()){
5519ef1f84bSDavid du Colombier 			qunlock(p);
5529ef1f84bSDavid du Colombier 			nexterror();
5539ef1f84bSDavid du Colombier 		}
5549ef1f84bSDavid du Colombier 
5559ef1f84bSDavid du Colombier 		n = qwrite(p->oq, buf, n);
5569ef1f84bSDavid du Colombier 
5579ef1f84bSDavid du Colombier 		qunlock(p);
5589ef1f84bSDavid du Colombier 		poperror();
5599ef1f84bSDavid du Colombier 		break;
5609ef1f84bSDavid du Colombier 	case Qctl:
5619ef1f84bSDavid du Colombier 		cmd = malloc(n+1);
562406c76faSDavid du Colombier 		if(cmd == nil)
563406c76faSDavid du Colombier 			error(Enomem);
5649ef1f84bSDavid du Colombier 		memmove(cmd, buf, n);
5659ef1f84bSDavid du Colombier 		cmd[n] = 0;
5669ef1f84bSDavid du Colombier 		qlock(p);
5679ef1f84bSDavid du Colombier 		if(waserror()){
5689ef1f84bSDavid du Colombier 			qunlock(p);
5699ef1f84bSDavid du Colombier 			free(cmd);
5709ef1f84bSDavid du Colombier 			nexterror();
5719ef1f84bSDavid du Colombier 		}
5729ef1f84bSDavid du Colombier 
5739ef1f84bSDavid du Colombier 		/* let output drain */
5749ef1f84bSDavid du Colombier 		if(uartctl(p, cmd) < 0)
5759ef1f84bSDavid du Colombier 			error(Ebadarg);
5769ef1f84bSDavid du Colombier 
5779ef1f84bSDavid du Colombier 		qunlock(p);
5789ef1f84bSDavid du Colombier 		poperror();
5799ef1f84bSDavid du Colombier 		free(cmd);
5809ef1f84bSDavid du Colombier 		break;
5819ef1f84bSDavid du Colombier 	}
5829ef1f84bSDavid du Colombier 
5839ef1f84bSDavid du Colombier 	return n;
5849ef1f84bSDavid du Colombier }
5859ef1f84bSDavid du Colombier 
5869ef1f84bSDavid du Colombier static long
uartwstat(Chan * c,uchar * dp,long n)5879ef1f84bSDavid du Colombier uartwstat(Chan *c, uchar *dp, long n)
5889ef1f84bSDavid du Colombier {
5899ef1f84bSDavid du Colombier 	Dir d;
5909ef1f84bSDavid du Colombier 	Dirtab *dt;
5919ef1f84bSDavid du Colombier 
5929ef1f84bSDavid du Colombier 	if(!iseve())
5939ef1f84bSDavid du Colombier 		error(Eperm);
5949ef1f84bSDavid du Colombier 	if(QTDIR & c->qid.type)
5959ef1f84bSDavid du Colombier 		error(Eperm);
5969ef1f84bSDavid du Colombier 	if(UARTTYPE(c->qid.path) == Qstat)
5979ef1f84bSDavid du Colombier 		error(Eperm);
5989ef1f84bSDavid du Colombier 
5999ef1f84bSDavid du Colombier 	dt = &uartdir[1 + 3 * UARTID(c->qid.path)];
6009ef1f84bSDavid du Colombier 	n = convM2D(dp, n, &d, nil);
6019ef1f84bSDavid du Colombier 	if(n == 0)
6029ef1f84bSDavid du Colombier 		error(Eshortstat);
6039ef1f84bSDavid du Colombier 	if(d.mode != ~0UL)
6049ef1f84bSDavid du Colombier 		dt[0].perm = dt[1].perm = d.mode;
6059ef1f84bSDavid du Colombier 	return n;
6069ef1f84bSDavid du Colombier }
6079ef1f84bSDavid du Colombier 
6089ef1f84bSDavid du Colombier void
uartpower(int on)6099ef1f84bSDavid du Colombier uartpower(int on)
6109ef1f84bSDavid du Colombier {
6119ef1f84bSDavid du Colombier 	Uart *p;
6129ef1f84bSDavid du Colombier 
6139ef1f84bSDavid du Colombier 	for(p = uartlist; p != nil; p = p->next) {
6149ef1f84bSDavid du Colombier 		if(p->phys->power)
6159ef1f84bSDavid du Colombier 			(*p->phys->power)(p, on);
6169ef1f84bSDavid du Colombier 	}
6179ef1f84bSDavid du Colombier }
6189ef1f84bSDavid du Colombier 
6199ef1f84bSDavid du Colombier Dev uartdevtab = {
6209ef1f84bSDavid du Colombier 	't',
6219ef1f84bSDavid du Colombier 	"uart",
6229ef1f84bSDavid du Colombier 
6239ef1f84bSDavid du Colombier 	uartreset,
6249ef1f84bSDavid du Colombier 	devinit,
6259ef1f84bSDavid du Colombier 	devshutdown,
6269ef1f84bSDavid du Colombier 	uartattach,
6279ef1f84bSDavid du Colombier 	uartwalk,
6289ef1f84bSDavid du Colombier 	uartstat,
6299ef1f84bSDavid du Colombier 	uartopen,
6309ef1f84bSDavid du Colombier 	devcreate,
6319ef1f84bSDavid du Colombier 	uartclose,
6329ef1f84bSDavid du Colombier 	uartread,
6339ef1f84bSDavid du Colombier 	devbread,
6349ef1f84bSDavid du Colombier 	uartwrite,
6359ef1f84bSDavid du Colombier 	devbwrite,
6369ef1f84bSDavid du Colombier 	devremove,
6379ef1f84bSDavid du Colombier 	uartwstat,
6389ef1f84bSDavid du Colombier 	uartpower,
6399ef1f84bSDavid du Colombier };
6409ef1f84bSDavid du Colombier 
6419ef1f84bSDavid du Colombier /*
6429ef1f84bSDavid du Colombier  *  restart input if it's off
6439ef1f84bSDavid du Colombier  */
6449ef1f84bSDavid du Colombier static void
uartflow(void * v)6459ef1f84bSDavid du Colombier uartflow(void *v)
6469ef1f84bSDavid du Colombier {
6479ef1f84bSDavid du Colombier 	Uart *p;
6489ef1f84bSDavid du Colombier 
6499ef1f84bSDavid du Colombier 	p = v;
6509ef1f84bSDavid du Colombier 	if(p->modem)
6519ef1f84bSDavid du Colombier 		(*p->phys->rts)(p, 1);
6529ef1f84bSDavid du Colombier }
6539ef1f84bSDavid du Colombier 
6549ef1f84bSDavid du Colombier /*
6559ef1f84bSDavid du Colombier  *  put some bytes into the local queue to avoid calling
6569ef1f84bSDavid du Colombier  *  qconsume for every character
6579ef1f84bSDavid du Colombier  */
6589ef1f84bSDavid du Colombier int
uartstageoutput(Uart * p)6599ef1f84bSDavid du Colombier uartstageoutput(Uart *p)
6609ef1f84bSDavid du Colombier {
6619ef1f84bSDavid du Colombier 	int n;
6629ef1f84bSDavid du Colombier 
6639ef1f84bSDavid du Colombier 	n = qconsume(p->oq, p->ostage, Stagesize);
6649ef1f84bSDavid du Colombier 	if(n <= 0)
6659ef1f84bSDavid du Colombier 		return 0;
6669ef1f84bSDavid du Colombier 	p->op = p->ostage;
6679ef1f84bSDavid du Colombier 	p->oe = p->ostage + n;
6689ef1f84bSDavid du Colombier 	return n;
6699ef1f84bSDavid du Colombier }
6709ef1f84bSDavid du Colombier 
6719ef1f84bSDavid du Colombier /*
6729ef1f84bSDavid du Colombier  *  restart output
6739ef1f84bSDavid du Colombier  */
6749ef1f84bSDavid du Colombier void
uartkick(void * v)6759ef1f84bSDavid du Colombier uartkick(void *v)
6769ef1f84bSDavid du Colombier {
6779ef1f84bSDavid du Colombier 	Uart *p = v;
6789ef1f84bSDavid du Colombier 
6799ef1f84bSDavid du Colombier 	if(p->blocked)
6809ef1f84bSDavid du Colombier 		return;
6819ef1f84bSDavid du Colombier 
6829ef1f84bSDavid du Colombier 	ilock(&p->tlock);
6839ef1f84bSDavid du Colombier 	(*p->phys->kick)(p);
6849ef1f84bSDavid du Colombier 	iunlock(&p->tlock);
6859ef1f84bSDavid du Colombier 
6869ef1f84bSDavid du Colombier 	if(p->drain && uartdrained(p)){
6879ef1f84bSDavid du Colombier 		p->drain = 0;
6889ef1f84bSDavid du Colombier 		wakeup(&p->r);
6899ef1f84bSDavid du Colombier 	}
6909ef1f84bSDavid du Colombier }
6919ef1f84bSDavid du Colombier 
6929ef1f84bSDavid du Colombier /*
6939ef1f84bSDavid du Colombier  * Move data from the interrupt staging area to
6949ef1f84bSDavid du Colombier  * the input Queue.
6959ef1f84bSDavid du Colombier  */
6969ef1f84bSDavid du Colombier static void
uartstageinput(Uart * p)6979ef1f84bSDavid du Colombier uartstageinput(Uart *p)
6989ef1f84bSDavid du Colombier {
6999ef1f84bSDavid du Colombier 	int n;
7009ef1f84bSDavid du Colombier 	uchar *ir, *iw;
7019ef1f84bSDavid du Colombier 
7029ef1f84bSDavid du Colombier 	while(p->ir != p->iw){
7039ef1f84bSDavid du Colombier 		ir = p->ir;
7049ef1f84bSDavid du Colombier 		if(p->ir > p->iw){
7059ef1f84bSDavid du Colombier 			iw = p->ie;
7069ef1f84bSDavid du Colombier 			p->ir = p->istage;
7079ef1f84bSDavid du Colombier 		}
7089ef1f84bSDavid du Colombier 		else{
7099ef1f84bSDavid du Colombier 			iw = p->iw;
7109ef1f84bSDavid du Colombier 			p->ir = p->iw;
7119ef1f84bSDavid du Colombier 		}
7129ef1f84bSDavid du Colombier 		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
7139ef1f84bSDavid du Colombier 			p->serr++;
7149ef1f84bSDavid du Colombier 			(*p->phys->rts)(p, 0);
7159ef1f84bSDavid du Colombier 		}
7169ef1f84bSDavid du Colombier 		else if(n == 0)
7179ef1f84bSDavid du Colombier 			p->berr++;
7189ef1f84bSDavid du Colombier 	}
7199ef1f84bSDavid du Colombier }
7209ef1f84bSDavid du Colombier 
7219ef1f84bSDavid du Colombier /*
7229ef1f84bSDavid du Colombier  *  receive a character at interrupt time
7239ef1f84bSDavid du Colombier  */
7249ef1f84bSDavid du Colombier void
uartrecv(Uart * p,char ch)7259ef1f84bSDavid du Colombier uartrecv(Uart *p,  char ch)
7269ef1f84bSDavid du Colombier {
7279ef1f84bSDavid du Colombier 	uchar *next;
7289ef1f84bSDavid du Colombier 
7299ef1f84bSDavid du Colombier 	/* software flow control */
7309ef1f84bSDavid du Colombier 	if(p->xonoff){
7319ef1f84bSDavid du Colombier 		if(ch == CTLS){
7329ef1f84bSDavid du Colombier 			p->blocked = 1;
7339ef1f84bSDavid du Colombier 		}else if(ch == CTLQ){
7349ef1f84bSDavid du Colombier 			p->blocked = 0;
7359ef1f84bSDavid du Colombier 			p->ctsbackoff = 2; /* clock gets output going again */
7369ef1f84bSDavid du Colombier 		}
7379ef1f84bSDavid du Colombier 	}
7389ef1f84bSDavid du Colombier 
7399ef1f84bSDavid du Colombier 	/* receive the character */
7409ef1f84bSDavid du Colombier 	if(p->putc)
7419ef1f84bSDavid du Colombier 		p->putc(p->iq, ch);
742406c76faSDavid du Colombier 	else if (p->iw) {		/* maybe the line isn't enabled yet */
7439ef1f84bSDavid du Colombier 		ilock(&p->rlock);
7449ef1f84bSDavid du Colombier 		next = p->iw + 1;
7459ef1f84bSDavid du Colombier 		if(next == p->ie)
7469ef1f84bSDavid du Colombier 			next = p->istage;
7479ef1f84bSDavid du Colombier 		if(next == p->ir)
7489ef1f84bSDavid du Colombier 			uartstageinput(p);
7499ef1f84bSDavid du Colombier 		if(next != p->ir){
7509ef1f84bSDavid du Colombier 			*p->iw = ch;
7519ef1f84bSDavid du Colombier 			p->iw = next;
7529ef1f84bSDavid du Colombier 		}
7539ef1f84bSDavid du Colombier 		iunlock(&p->rlock);
7549ef1f84bSDavid du Colombier 	}
7559ef1f84bSDavid du Colombier }
7569ef1f84bSDavid du Colombier 
7579ef1f84bSDavid du Colombier /*
7589ef1f84bSDavid du Colombier  *  we save up input characters till clock time to reduce
7599ef1f84bSDavid du Colombier  *  per character interrupt overhead.
7609ef1f84bSDavid du Colombier  */
7619ef1f84bSDavid du Colombier static void
uartclock(void)7629ef1f84bSDavid du Colombier uartclock(void)
7639ef1f84bSDavid du Colombier {
7649ef1f84bSDavid du Colombier 	Uart *p;
7659ef1f84bSDavid du Colombier 
7669ef1f84bSDavid du Colombier 	ilock(&uartalloc);
7679ef1f84bSDavid du Colombier 	for(p = uartalloc.elist; p; p = p->elist){
7689ef1f84bSDavid du Colombier 
7699ef1f84bSDavid du Colombier 		if(p->phys->poll != nil)
7709ef1f84bSDavid du Colombier 			(*p->phys->poll)(p);
7719ef1f84bSDavid du Colombier 
7729ef1f84bSDavid du Colombier 		/* this hopefully amortizes cost of qproduce to many chars */
7739ef1f84bSDavid du Colombier 		if(p->iw != p->ir){
7749ef1f84bSDavid du Colombier 			ilock(&p->rlock);
7759ef1f84bSDavid du Colombier 			uartstageinput(p);
7769ef1f84bSDavid du Colombier 			iunlock(&p->rlock);
7779ef1f84bSDavid du Colombier 		}
7789ef1f84bSDavid du Colombier 
7799ef1f84bSDavid du Colombier 		/* hang up if requested */
7809ef1f84bSDavid du Colombier 		if(p->dohup){
7819ef1f84bSDavid du Colombier 			qhangup(p->iq, 0);
7829ef1f84bSDavid du Colombier 			qhangup(p->oq, 0);
7839ef1f84bSDavid du Colombier 			p->dohup = 0;
7849ef1f84bSDavid du Colombier 		}
7859ef1f84bSDavid du Colombier 
7869ef1f84bSDavid du Colombier 		/* this adds hysteresis to hardware/software flow control */
7879ef1f84bSDavid du Colombier 		if(p->ctsbackoff){
7889ef1f84bSDavid du Colombier 			ilock(&p->tlock);
7899ef1f84bSDavid du Colombier 			if(p->ctsbackoff){
7909ef1f84bSDavid du Colombier 				if(--(p->ctsbackoff) == 0)
7919ef1f84bSDavid du Colombier 					(*p->phys->kick)(p);
7929ef1f84bSDavid du Colombier 			}
7939ef1f84bSDavid du Colombier 			iunlock(&p->tlock);
7949ef1f84bSDavid du Colombier 		}
7959ef1f84bSDavid du Colombier 	}
7969ef1f84bSDavid du Colombier 	iunlock(&uartalloc);
7979ef1f84bSDavid du Colombier }
7989ef1f84bSDavid du Colombier 
7999ef1f84bSDavid du Colombier /*
8009ef1f84bSDavid du Colombier  * polling console input, output
8019ef1f84bSDavid du Colombier  */
8029ef1f84bSDavid du Colombier 
8039ef1f84bSDavid du Colombier Uart* consuart;
8049ef1f84bSDavid du Colombier 
8059ef1f84bSDavid du Colombier int
uartgetc(void)8069ef1f84bSDavid du Colombier uartgetc(void)
8079ef1f84bSDavid du Colombier {
8089ef1f84bSDavid du Colombier 	if(consuart == nil || consuart->phys->getc == nil)
8099ef1f84bSDavid du Colombier 		return -1;
8109ef1f84bSDavid du Colombier 	return consuart->phys->getc(consuart);
8119ef1f84bSDavid du Colombier }
8129ef1f84bSDavid du Colombier 
8139ef1f84bSDavid du Colombier void
uartputc(int c)8149ef1f84bSDavid du Colombier uartputc(int c)
8159ef1f84bSDavid du Colombier {
816406c76faSDavid du Colombier 	char c2;
817406c76faSDavid du Colombier 
818406c76faSDavid du Colombier 	if(consuart == nil || consuart->phys->putc == nil) {
819406c76faSDavid du Colombier 		c2 = c;
820406c76faSDavid du Colombier 		if (lprint)
821406c76faSDavid du Colombier 			(*lprint)(&c2, 1);
8229ef1f84bSDavid du Colombier 		return;
823406c76faSDavid du Colombier 	}
8249ef1f84bSDavid du Colombier 	consuart->phys->putc(consuart, c);
8259ef1f84bSDavid du Colombier }
8269ef1f84bSDavid du Colombier 
8279ef1f84bSDavid du Colombier void
uartputs(char * s,int n)8289ef1f84bSDavid du Colombier uartputs(char *s, int n)
8299ef1f84bSDavid du Colombier {
8309ef1f84bSDavid du Colombier 	char *e;
8319ef1f84bSDavid du Colombier 
832406c76faSDavid du Colombier 	if(consuart == nil || consuart->phys->putc == nil) {
833406c76faSDavid du Colombier 		if (lprint)
834406c76faSDavid du Colombier 			(*lprint)(s, n);
8359ef1f84bSDavid du Colombier 		return;
836406c76faSDavid du Colombier 	}
8379ef1f84bSDavid du Colombier 	e = s+n;
8389ef1f84bSDavid du Colombier 	for(; s<e; s++){
8399ef1f84bSDavid du Colombier 		if(*s == '\n')
8409ef1f84bSDavid du Colombier 			consuart->phys->putc(consuart, '\r');
8419ef1f84bSDavid du Colombier 		consuart->phys->putc(consuart, *s);
8429ef1f84bSDavid du Colombier 	}
8439ef1f84bSDavid du Colombier }
844