xref: /plan9/sys/src/9/teg2/devuart.c (revision 3de6a9c0b3d5cf34fc4090d0bf1930d83799a7fd)
1*3de6a9c0SDavid du Colombier #include	"u.h"
2*3de6a9c0SDavid du Colombier #include	"../port/lib.h"
3*3de6a9c0SDavid du Colombier #include	"mem.h"
4*3de6a9c0SDavid du Colombier #include	"dat.h"
5*3de6a9c0SDavid du Colombier #include	"fns.h"
6*3de6a9c0SDavid du Colombier #include	"io.h"
7*3de6a9c0SDavid du Colombier #include	"../port/error.h"
8*3de6a9c0SDavid du Colombier 
9*3de6a9c0SDavid du Colombier #include	"../port/netif.h"
10*3de6a9c0SDavid du Colombier 
11*3de6a9c0SDavid du Colombier enum
12*3de6a9c0SDavid du Colombier {
13*3de6a9c0SDavid du Colombier 	/* soft flow control chars */
14*3de6a9c0SDavid du Colombier 	CTLS= 023,
15*3de6a9c0SDavid du Colombier 	CTLQ= 021,
16*3de6a9c0SDavid du Colombier };
17*3de6a9c0SDavid du Colombier 
18*3de6a9c0SDavid du Colombier extern Dev uartdevtab;
19*3de6a9c0SDavid du Colombier extern PhysUart* physuart[];
20*3de6a9c0SDavid du Colombier 
21*3de6a9c0SDavid du Colombier static Uart* uartlist;
22*3de6a9c0SDavid du Colombier static Uart** uart;
23*3de6a9c0SDavid du Colombier static int uartnuart;
24*3de6a9c0SDavid du Colombier static Dirtab *uartdir;
25*3de6a9c0SDavid du Colombier static int uartndir;
26*3de6a9c0SDavid du Colombier static Timer *uarttimer;
27*3de6a9c0SDavid du Colombier 
28*3de6a9c0SDavid du Colombier struct Uartalloc {
29*3de6a9c0SDavid du Colombier 	Lock;
30*3de6a9c0SDavid du Colombier 	Uart *elist;	/* list of enabled interfaces */
31*3de6a9c0SDavid du Colombier } uartalloc;
32*3de6a9c0SDavid du Colombier 
33*3de6a9c0SDavid du Colombier static void	uartclock(void);
34*3de6a9c0SDavid du Colombier static void	uartflow(void*);
35*3de6a9c0SDavid du Colombier 
36*3de6a9c0SDavid du Colombier /*
37*3de6a9c0SDavid du Colombier  *  enable/disable uart and add/remove to list of enabled uarts
38*3de6a9c0SDavid du Colombier  */
39*3de6a9c0SDavid du Colombier //static
40*3de6a9c0SDavid du Colombier Uart*
41*3de6a9c0SDavid du Colombier uartenable(Uart *p)
42*3de6a9c0SDavid du Colombier {
43*3de6a9c0SDavid du Colombier 	Uart **l;
44*3de6a9c0SDavid du Colombier 
45*3de6a9c0SDavid du Colombier 	if (up == nil)
46*3de6a9c0SDavid du Colombier 		return p;		/* too soon; try again later */
47*3de6a9c0SDavid du Colombier //		return nil;
48*3de6a9c0SDavid du Colombier 
49*3de6a9c0SDavid du Colombier 	if(p->iq == nil){
50*3de6a9c0SDavid du Colombier 		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
51*3de6a9c0SDavid du Colombier 			return nil;
52*3de6a9c0SDavid du Colombier 	}
53*3de6a9c0SDavid du Colombier 	else
54*3de6a9c0SDavid du Colombier 		qreopen(p->iq);
55*3de6a9c0SDavid du Colombier 	if(p->oq == nil){
56*3de6a9c0SDavid du Colombier 		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
57*3de6a9c0SDavid du Colombier 			qfree(p->iq);
58*3de6a9c0SDavid du Colombier 			p->iq = nil;
59*3de6a9c0SDavid du Colombier 			return nil;
60*3de6a9c0SDavid du Colombier 		}
61*3de6a9c0SDavid du Colombier 	}
62*3de6a9c0SDavid du Colombier 	else
63*3de6a9c0SDavid du Colombier 		qreopen(p->oq);
64*3de6a9c0SDavid du Colombier 
65*3de6a9c0SDavid du Colombier 	p->ir = p->istage;
66*3de6a9c0SDavid du Colombier 	p->iw = p->istage;
67*3de6a9c0SDavid du Colombier 	p->ie = &p->istage[Stagesize];
68*3de6a9c0SDavid du Colombier 	p->op = p->ostage;
69*3de6a9c0SDavid du Colombier 	p->oe = p->ostage;
70*3de6a9c0SDavid du Colombier 
71*3de6a9c0SDavid du Colombier 	p->hup_dsr = p->hup_dcd = 0;
72*3de6a9c0SDavid du Colombier 	p->dsr = p->dcd = 0;
73*3de6a9c0SDavid du Colombier 
74*3de6a9c0SDavid du Colombier 	/* assume we can send */
75*3de6a9c0SDavid du Colombier 	p->cts = 1;
76*3de6a9c0SDavid du Colombier 	p->ctsbackoff = 0;
77*3de6a9c0SDavid du Colombier 
78*3de6a9c0SDavid du Colombier 	if (up) {
79*3de6a9c0SDavid du Colombier 		if(p->bits == 0)
80*3de6a9c0SDavid du Colombier 			uartctl(p, "l8");
81*3de6a9c0SDavid du Colombier 		if(p->stop == 0)
82*3de6a9c0SDavid du Colombier 			uartctl(p, "s1");
83*3de6a9c0SDavid du Colombier 		if(p->parity == 0)
84*3de6a9c0SDavid du Colombier 			uartctl(p, "pn");
85*3de6a9c0SDavid du Colombier 		if(p->baud == 0)
86*3de6a9c0SDavid du Colombier 			uartctl(p, "b9600");
87*3de6a9c0SDavid du Colombier 		(*p->phys->enable)(p, 1);
88*3de6a9c0SDavid du Colombier 	}
89*3de6a9c0SDavid du Colombier 
90*3de6a9c0SDavid du Colombier 	/*
91*3de6a9c0SDavid du Colombier 	 * use ilock because uartclock can otherwise interrupt here
92*3de6a9c0SDavid du Colombier 	 * and would hang on an attempt to lock uartalloc.
93*3de6a9c0SDavid du Colombier 	 */
94*3de6a9c0SDavid du Colombier 	ilock(&uartalloc);
95*3de6a9c0SDavid du Colombier 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
96*3de6a9c0SDavid du Colombier 		if(*l == p)
97*3de6a9c0SDavid du Colombier 			break;
98*3de6a9c0SDavid du Colombier 	}
99*3de6a9c0SDavid du Colombier 	if(*l == 0){
100*3de6a9c0SDavid du Colombier 		p->elist = uartalloc.elist;
101*3de6a9c0SDavid du Colombier 		uartalloc.elist = p;
102*3de6a9c0SDavid du Colombier 	}
103*3de6a9c0SDavid du Colombier 	p->enabled = 1;
104*3de6a9c0SDavid du Colombier 	iunlock(&uartalloc);
105*3de6a9c0SDavid du Colombier 
106*3de6a9c0SDavid du Colombier 	return p;
107*3de6a9c0SDavid du Colombier }
108*3de6a9c0SDavid du Colombier 
109*3de6a9c0SDavid du Colombier static void
110*3de6a9c0SDavid du Colombier uartdisable(Uart *p)
111*3de6a9c0SDavid du Colombier {
112*3de6a9c0SDavid du Colombier 	Uart **l;
113*3de6a9c0SDavid du Colombier 
114*3de6a9c0SDavid du Colombier 	(*p->phys->disable)(p);
115*3de6a9c0SDavid du Colombier 
116*3de6a9c0SDavid du Colombier 	ilock(&uartalloc);
117*3de6a9c0SDavid du Colombier 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
118*3de6a9c0SDavid du Colombier 		if(*l == p){
119*3de6a9c0SDavid du Colombier 			*l = p->elist;
120*3de6a9c0SDavid du Colombier 			break;
121*3de6a9c0SDavid du Colombier 		}
122*3de6a9c0SDavid du Colombier 	}
123*3de6a9c0SDavid du Colombier 	p->enabled = 0;
124*3de6a9c0SDavid du Colombier 	iunlock(&uartalloc);
125*3de6a9c0SDavid du Colombier }
126*3de6a9c0SDavid du Colombier 
127*3de6a9c0SDavid du Colombier void
128*3de6a9c0SDavid du Colombier uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
129*3de6a9c0SDavid du Colombier {
130*3de6a9c0SDavid du Colombier 	qlock(p);
131*3de6a9c0SDavid du Colombier 	if(p->opens++ == 0 && uartenable(p) == nil){
132*3de6a9c0SDavid du Colombier 		qunlock(p);
133*3de6a9c0SDavid du Colombier 		error(Enodev);
134*3de6a9c0SDavid du Colombier 	}
135*3de6a9c0SDavid du Colombier 	if(setb1200)
136*3de6a9c0SDavid du Colombier 		uartctl(p, "b1200");
137*3de6a9c0SDavid du Colombier 	p->putc = putc;
138*3de6a9c0SDavid du Colombier 	p->special = 1;
139*3de6a9c0SDavid du Colombier 	qunlock(p);
140*3de6a9c0SDavid du Colombier }
141*3de6a9c0SDavid du Colombier 
142*3de6a9c0SDavid du Colombier void
143*3de6a9c0SDavid du Colombier uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
144*3de6a9c0SDavid du Colombier {
145*3de6a9c0SDavid du Colombier 	qlock(p);
146*3de6a9c0SDavid du Colombier 	if(p->opens == 0 || p->special == 0){
147*3de6a9c0SDavid du Colombier 		qunlock(p);
148*3de6a9c0SDavid du Colombier 		error(Enodev);
149*3de6a9c0SDavid du Colombier 	}
150*3de6a9c0SDavid du Colombier 	p->putc = putc;
151*3de6a9c0SDavid du Colombier 	qunlock(p);
152*3de6a9c0SDavid du Colombier }
153*3de6a9c0SDavid du Colombier 
154*3de6a9c0SDavid du Colombier static void
155*3de6a9c0SDavid du Colombier setlength(int i)
156*3de6a9c0SDavid du Colombier {
157*3de6a9c0SDavid du Colombier 	Uart *p;
158*3de6a9c0SDavid du Colombier 
159*3de6a9c0SDavid du Colombier 	if(i > 0){
160*3de6a9c0SDavid du Colombier 		p = uart[i];
161*3de6a9c0SDavid du Colombier 		if(p && p->opens && p->iq)
162*3de6a9c0SDavid du Colombier 			uartdir[1+3*i].length = qlen(p->iq);
163*3de6a9c0SDavid du Colombier 	} else for(i = 0; i < uartnuart; i++){
164*3de6a9c0SDavid du Colombier 		p = uart[i];
165*3de6a9c0SDavid du Colombier 		if(p && p->opens && p->iq)
166*3de6a9c0SDavid du Colombier 			uartdir[1+3*i].length = qlen(p->iq);
167*3de6a9c0SDavid du Colombier 	}
168*3de6a9c0SDavid du Colombier }
169*3de6a9c0SDavid du Colombier 
170*3de6a9c0SDavid du Colombier /*
171*3de6a9c0SDavid du Colombier  *  set up the '#t' directory
172*3de6a9c0SDavid du Colombier  */
173*3de6a9c0SDavid du Colombier static void
174*3de6a9c0SDavid du Colombier uartreset(void)
175*3de6a9c0SDavid du Colombier {
176*3de6a9c0SDavid du Colombier 	int i;
177*3de6a9c0SDavid du Colombier 	Dirtab *dp;
178*3de6a9c0SDavid du Colombier 	Uart *p, *tail;
179*3de6a9c0SDavid du Colombier 
180*3de6a9c0SDavid du Colombier 	tail = nil;
181*3de6a9c0SDavid du Colombier 	for(i = 0; physuart[i] != nil; i++){
182*3de6a9c0SDavid du Colombier 		if(physuart[i]->pnp == nil)
183*3de6a9c0SDavid du Colombier 			continue;
184*3de6a9c0SDavid du Colombier 		if((p = physuart[i]->pnp()) == nil)
185*3de6a9c0SDavid du Colombier 			continue;
186*3de6a9c0SDavid du Colombier 		if(uartlist != nil)
187*3de6a9c0SDavid du Colombier 			tail->next = p;
188*3de6a9c0SDavid du Colombier 		else
189*3de6a9c0SDavid du Colombier 			uartlist = p;
190*3de6a9c0SDavid du Colombier 		for(tail = p; tail->next != nil; tail = tail->next)
191*3de6a9c0SDavid du Colombier 			uartnuart++;
192*3de6a9c0SDavid du Colombier 		uartnuart++;
193*3de6a9c0SDavid du Colombier 	}
194*3de6a9c0SDavid du Colombier 
195*3de6a9c0SDavid du Colombier 	if(uartnuart)
196*3de6a9c0SDavid du Colombier 		uart = xalloc(uartnuart*sizeof(Uart*));
197*3de6a9c0SDavid du Colombier 
198*3de6a9c0SDavid du Colombier 	uartndir = 1 + 3*uartnuart;
199*3de6a9c0SDavid du Colombier 	uartdir = xalloc(uartndir * sizeof(Dirtab));
200*3de6a9c0SDavid du Colombier 	if (uart == nil || uartdir == nil)
201*3de6a9c0SDavid du Colombier 		panic("uartreset: no memory");
202*3de6a9c0SDavid du Colombier 	dp = uartdir;
203*3de6a9c0SDavid du Colombier 	strcpy(dp->name, ".");
204*3de6a9c0SDavid du Colombier 	mkqid(&dp->qid, 0, 0, QTDIR);
205*3de6a9c0SDavid du Colombier 	dp->length = 0;
206*3de6a9c0SDavid du Colombier 	dp->perm = DMDIR|0555;
207*3de6a9c0SDavid du Colombier 	dp++;
208*3de6a9c0SDavid du Colombier 	p = uartlist;
209*3de6a9c0SDavid du Colombier 	for(i = 0; i < uartnuart; i++){
210*3de6a9c0SDavid du Colombier 		/* 3 directory entries per port */
211*3de6a9c0SDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%d", i);
212*3de6a9c0SDavid du Colombier 		dp->qid.path = NETQID(i, Ndataqid);
213*3de6a9c0SDavid du Colombier 		dp->perm = 0660;
214*3de6a9c0SDavid du Colombier 		dp++;
215*3de6a9c0SDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%dctl", i);
216*3de6a9c0SDavid du Colombier 		dp->qid.path = NETQID(i, Nctlqid);
217*3de6a9c0SDavid du Colombier 		dp->perm = 0660;
218*3de6a9c0SDavid du Colombier 		dp++;
219*3de6a9c0SDavid du Colombier 		snprint(dp->name, sizeof dp->name, "eia%dstatus", i);
220*3de6a9c0SDavid du Colombier 		dp->qid.path = NETQID(i, Nstatqid);
221*3de6a9c0SDavid du Colombier 		dp->perm = 0444;
222*3de6a9c0SDavid du Colombier 		dp++;
223*3de6a9c0SDavid du Colombier 
224*3de6a9c0SDavid du Colombier 		uart[i] = p;
225*3de6a9c0SDavid du Colombier 		p->dev = i;
226*3de6a9c0SDavid du Colombier 		if(p->console || p->special){
227*3de6a9c0SDavid du Colombier 			if(uartenable(p) != nil){
228*3de6a9c0SDavid du Colombier 				if(p->console && up){
229*3de6a9c0SDavid du Colombier 					kbdq = p->iq;
230*3de6a9c0SDavid du Colombier 					serialoq = p->oq;
231*3de6a9c0SDavid du Colombier 					p->putc = kbdcr2nl;
232*3de6a9c0SDavid du Colombier 				}
233*3de6a9c0SDavid du Colombier 				p->opens++;
234*3de6a9c0SDavid du Colombier 			}
235*3de6a9c0SDavid du Colombier 		}
236*3de6a9c0SDavid du Colombier 		p = p->next;
237*3de6a9c0SDavid du Colombier 	}
238*3de6a9c0SDavid du Colombier 
239*3de6a9c0SDavid du Colombier 	if(uartnuart){
240*3de6a9c0SDavid du Colombier 		/*
241*3de6a9c0SDavid du Colombier 		 * at 115200 baud, the 1024 char buffer takes 56 ms to process,
242*3de6a9c0SDavid du Colombier 		 * processing it every 22 ms should be fine.
243*3de6a9c0SDavid du Colombier 		 */
244*3de6a9c0SDavid du Colombier 		uarttimer = addclock0link(uartclock, 22);
245*3de6a9c0SDavid du Colombier 	}
246*3de6a9c0SDavid du Colombier }
247*3de6a9c0SDavid du Colombier 
248*3de6a9c0SDavid du Colombier 
249*3de6a9c0SDavid du Colombier static Chan*
250*3de6a9c0SDavid du Colombier uartattach(char *spec)
251*3de6a9c0SDavid du Colombier {
252*3de6a9c0SDavid du Colombier 	return devattach('t', spec);
253*3de6a9c0SDavid du Colombier }
254*3de6a9c0SDavid du Colombier 
255*3de6a9c0SDavid du Colombier static Walkqid*
256*3de6a9c0SDavid du Colombier uartwalk(Chan *c, Chan *nc, char **name, int nname)
257*3de6a9c0SDavid du Colombier {
258*3de6a9c0SDavid du Colombier 	return devwalk(c, nc, name, nname, uartdir, uartndir, devgen);
259*3de6a9c0SDavid du Colombier }
260*3de6a9c0SDavid du Colombier 
261*3de6a9c0SDavid du Colombier static int
262*3de6a9c0SDavid du Colombier uartstat(Chan *c, uchar *dp, int n)
263*3de6a9c0SDavid du Colombier {
264*3de6a9c0SDavid du Colombier 	if(NETTYPE(c->qid.path) == Ndataqid)
265*3de6a9c0SDavid du Colombier 		setlength(NETID(c->qid.path));
266*3de6a9c0SDavid du Colombier 	return devstat(c, dp, n, uartdir, uartndir, devgen);
267*3de6a9c0SDavid du Colombier }
268*3de6a9c0SDavid du Colombier 
269*3de6a9c0SDavid du Colombier static Chan*
270*3de6a9c0SDavid du Colombier uartopen(Chan *c, int omode)
271*3de6a9c0SDavid du Colombier {
272*3de6a9c0SDavid du Colombier 	Uart *p;
273*3de6a9c0SDavid du Colombier 
274*3de6a9c0SDavid du Colombier 	c = devopen(c, omode, uartdir, uartndir, devgen);
275*3de6a9c0SDavid du Colombier 
276*3de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
277*3de6a9c0SDavid du Colombier 	case Nctlqid:
278*3de6a9c0SDavid du Colombier 	case Ndataqid:
279*3de6a9c0SDavid du Colombier 		p = uart[NETID(c->qid.path)];
280*3de6a9c0SDavid du Colombier 		qlock(p);
281*3de6a9c0SDavid du Colombier 		if(p->opens++ == 0 && uartenable(p) == nil){
282*3de6a9c0SDavid du Colombier 			qunlock(p);
283*3de6a9c0SDavid du Colombier 			c->flag &= ~COPEN;
284*3de6a9c0SDavid du Colombier 			error(Enodev);
285*3de6a9c0SDavid du Colombier 		}
286*3de6a9c0SDavid du Colombier 		qunlock(p);
287*3de6a9c0SDavid du Colombier 		break;
288*3de6a9c0SDavid du Colombier 	}
289*3de6a9c0SDavid du Colombier 
290*3de6a9c0SDavid du Colombier 	c->iounit = qiomaxatomic;
291*3de6a9c0SDavid du Colombier 	return c;
292*3de6a9c0SDavid du Colombier }
293*3de6a9c0SDavid du Colombier 
294*3de6a9c0SDavid du Colombier static int
295*3de6a9c0SDavid du Colombier uartdrained(void* arg)
296*3de6a9c0SDavid du Colombier {
297*3de6a9c0SDavid du Colombier 	Uart *p;
298*3de6a9c0SDavid du Colombier 
299*3de6a9c0SDavid du Colombier 	p = arg;
300*3de6a9c0SDavid du Colombier 	return qlen(p->oq) == 0 && p->op == p->oe;
301*3de6a9c0SDavid du Colombier }
302*3de6a9c0SDavid du Colombier 
303*3de6a9c0SDavid du Colombier static void
304*3de6a9c0SDavid du Colombier uartdrainoutput(Uart *p)
305*3de6a9c0SDavid du Colombier {
306*3de6a9c0SDavid du Colombier 	if(!p->enabled || up == nil)
307*3de6a9c0SDavid du Colombier 		return;
308*3de6a9c0SDavid du Colombier 
309*3de6a9c0SDavid du Colombier 	p->drain = 1;
310*3de6a9c0SDavid du Colombier 	if(waserror()){
311*3de6a9c0SDavid du Colombier 		p->drain = 0;
312*3de6a9c0SDavid du Colombier 		nexterror();
313*3de6a9c0SDavid du Colombier 	}
314*3de6a9c0SDavid du Colombier 	sleep(&p->r, uartdrained, p);
315*3de6a9c0SDavid du Colombier 	poperror();
316*3de6a9c0SDavid du Colombier }
317*3de6a9c0SDavid du Colombier 
318*3de6a9c0SDavid du Colombier static void
319*3de6a9c0SDavid du Colombier uartclose(Chan *c)
320*3de6a9c0SDavid du Colombier {
321*3de6a9c0SDavid du Colombier 	Uart *p;
322*3de6a9c0SDavid du Colombier 
323*3de6a9c0SDavid du Colombier 	if(c->qid.type & QTDIR)
324*3de6a9c0SDavid du Colombier 		return;
325*3de6a9c0SDavid du Colombier 	if((c->flag & COPEN) == 0)
326*3de6a9c0SDavid du Colombier 		return;
327*3de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
328*3de6a9c0SDavid du Colombier 	case Ndataqid:
329*3de6a9c0SDavid du Colombier 	case Nctlqid:
330*3de6a9c0SDavid du Colombier 		p = uart[NETID(c->qid.path)];
331*3de6a9c0SDavid du Colombier 		qlock(p);
332*3de6a9c0SDavid du Colombier 		if(--(p->opens) == 0){
333*3de6a9c0SDavid du Colombier 			qclose(p->iq);
334*3de6a9c0SDavid du Colombier 			ilock(&p->rlock);
335*3de6a9c0SDavid du Colombier 			p->ir = p->iw = p->istage;
336*3de6a9c0SDavid du Colombier 			iunlock(&p->rlock);
337*3de6a9c0SDavid du Colombier 
338*3de6a9c0SDavid du Colombier 			/*
339*3de6a9c0SDavid du Colombier 			 */
340*3de6a9c0SDavid du Colombier 			qhangup(p->oq, nil);
341*3de6a9c0SDavid du Colombier 			if(!waserror()){
342*3de6a9c0SDavid du Colombier 				uartdrainoutput(p);
343*3de6a9c0SDavid du Colombier 				poperror();
344*3de6a9c0SDavid du Colombier 			}
345*3de6a9c0SDavid du Colombier 			qclose(p->oq);
346*3de6a9c0SDavid du Colombier 			uartdisable(p);
347*3de6a9c0SDavid du Colombier 			p->dcd = p->dsr = p->dohup = 0;
348*3de6a9c0SDavid du Colombier 		}
349*3de6a9c0SDavid du Colombier 		qunlock(p);
350*3de6a9c0SDavid du Colombier 		break;
351*3de6a9c0SDavid du Colombier 	}
352*3de6a9c0SDavid du Colombier }
353*3de6a9c0SDavid du Colombier 
354*3de6a9c0SDavid du Colombier static long
355*3de6a9c0SDavid du Colombier uartread(Chan *c, void *buf, long n, vlong off)
356*3de6a9c0SDavid du Colombier {
357*3de6a9c0SDavid du Colombier 	Uart *p;
358*3de6a9c0SDavid du Colombier 	ulong offset = off;
359*3de6a9c0SDavid du Colombier 
360*3de6a9c0SDavid du Colombier 	if(c->qid.type & QTDIR){
361*3de6a9c0SDavid du Colombier 		setlength(-1);
362*3de6a9c0SDavid du Colombier 		return devdirread(c, buf, n, uartdir, uartndir, devgen);
363*3de6a9c0SDavid du Colombier 	}
364*3de6a9c0SDavid du Colombier 
365*3de6a9c0SDavid du Colombier 	p = uart[NETID(c->qid.path)];
366*3de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
367*3de6a9c0SDavid du Colombier 	case Ndataqid:
368*3de6a9c0SDavid du Colombier 		return qread(p->iq, buf, n);
369*3de6a9c0SDavid du Colombier 	case Nctlqid:
370*3de6a9c0SDavid du Colombier 		return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
371*3de6a9c0SDavid du Colombier 	case Nstatqid:
372*3de6a9c0SDavid du Colombier 		return (*p->phys->status)(p, buf, n, offset);
373*3de6a9c0SDavid du Colombier 	}
374*3de6a9c0SDavid du Colombier 
375*3de6a9c0SDavid du Colombier 	return 0;
376*3de6a9c0SDavid du Colombier }
377*3de6a9c0SDavid du Colombier 
378*3de6a9c0SDavid du Colombier int
379*3de6a9c0SDavid du Colombier uartctl(Uart *p, char *cmd)
380*3de6a9c0SDavid du Colombier {
381*3de6a9c0SDavid du Colombier 	char *f[16];
382*3de6a9c0SDavid du Colombier 	int i, n, nf;
383*3de6a9c0SDavid du Colombier 
384*3de6a9c0SDavid du Colombier 	nf = tokenize(cmd, f, nelem(f));
385*3de6a9c0SDavid du Colombier 	for(i = 0; i < nf; i++){
386*3de6a9c0SDavid du Colombier 		if(strncmp(f[i], "break", 5) == 0){
387*3de6a9c0SDavid du Colombier 			(*p->phys->dobreak)(p, 0);
388*3de6a9c0SDavid du Colombier 			continue;
389*3de6a9c0SDavid du Colombier 		}
390*3de6a9c0SDavid du Colombier 
391*3de6a9c0SDavid du Colombier 		n = atoi(f[i]+1);
392*3de6a9c0SDavid du Colombier 		switch(*f[i]){
393*3de6a9c0SDavid du Colombier 		case 'B':
394*3de6a9c0SDavid du Colombier 		case 'b':
395*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
396*3de6a9c0SDavid du Colombier 			if((*p->phys->baud)(p, n) < 0)
397*3de6a9c0SDavid du Colombier 				return -1;
398*3de6a9c0SDavid du Colombier 			break;
399*3de6a9c0SDavid du Colombier 		case 'C':
400*3de6a9c0SDavid du Colombier 		case 'c':
401*3de6a9c0SDavid du Colombier 			p->hup_dcd = n;
402*3de6a9c0SDavid du Colombier 			break;
403*3de6a9c0SDavid du Colombier 		case 'D':
404*3de6a9c0SDavid du Colombier 		case 'd':
405*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
406*3de6a9c0SDavid du Colombier 			(*p->phys->dtr)(p, n);
407*3de6a9c0SDavid du Colombier 			break;
408*3de6a9c0SDavid du Colombier 		case 'E':
409*3de6a9c0SDavid du Colombier 		case 'e':
410*3de6a9c0SDavid du Colombier 			p->hup_dsr = n;
411*3de6a9c0SDavid du Colombier 			break;
412*3de6a9c0SDavid du Colombier 		case 'f':
413*3de6a9c0SDavid du Colombier 		case 'F':
414*3de6a9c0SDavid du Colombier 			if(p->oq != nil)
415*3de6a9c0SDavid du Colombier 				qflush(p->oq);
416*3de6a9c0SDavid du Colombier 			break;
417*3de6a9c0SDavid du Colombier 		case 'H':
418*3de6a9c0SDavid du Colombier 		case 'h':
419*3de6a9c0SDavid du Colombier 			if(p->iq != nil)
420*3de6a9c0SDavid du Colombier 				qhangup(p->iq, 0);
421*3de6a9c0SDavid du Colombier 			if(p->oq != nil)
422*3de6a9c0SDavid du Colombier 				qhangup(p->oq, 0);
423*3de6a9c0SDavid du Colombier 			break;
424*3de6a9c0SDavid du Colombier 		case 'i':
425*3de6a9c0SDavid du Colombier 		case 'I':
426*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
427*3de6a9c0SDavid du Colombier 			(*p->phys->fifo)(p, n);
428*3de6a9c0SDavid du Colombier 			break;
429*3de6a9c0SDavid du Colombier 		case 'K':
430*3de6a9c0SDavid du Colombier 		case 'k':
431*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
432*3de6a9c0SDavid du Colombier 			(*p->phys->dobreak)(p, n);
433*3de6a9c0SDavid du Colombier 			break;
434*3de6a9c0SDavid du Colombier 		case 'L':
435*3de6a9c0SDavid du Colombier 		case 'l':
436*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
437*3de6a9c0SDavid du Colombier 			if((*p->phys->bits)(p, n) < 0)
438*3de6a9c0SDavid du Colombier 				return -1;
439*3de6a9c0SDavid du Colombier 			break;
440*3de6a9c0SDavid du Colombier 		case 'm':
441*3de6a9c0SDavid du Colombier 		case 'M':
442*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
443*3de6a9c0SDavid du Colombier 			(*p->phys->modemctl)(p, n);
444*3de6a9c0SDavid du Colombier 			break;
445*3de6a9c0SDavid du Colombier 		case 'n':
446*3de6a9c0SDavid du Colombier 		case 'N':
447*3de6a9c0SDavid du Colombier 			if(p->oq != nil)
448*3de6a9c0SDavid du Colombier 				qnoblock(p->oq, n);
449*3de6a9c0SDavid du Colombier 			break;
450*3de6a9c0SDavid du Colombier 		case 'P':
451*3de6a9c0SDavid du Colombier 		case 'p':
452*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
453*3de6a9c0SDavid du Colombier 			if((*p->phys->parity)(p, *(f[i]+1)) < 0)
454*3de6a9c0SDavid du Colombier 				return -1;
455*3de6a9c0SDavid du Colombier 			break;
456*3de6a9c0SDavid du Colombier 		case 'Q':
457*3de6a9c0SDavid du Colombier 		case 'q':
458*3de6a9c0SDavid du Colombier 			if(p->iq != nil)
459*3de6a9c0SDavid du Colombier 				qsetlimit(p->iq, n);
460*3de6a9c0SDavid du Colombier 			if(p->oq != nil)
461*3de6a9c0SDavid du Colombier 				qsetlimit(p->oq, n);
462*3de6a9c0SDavid du Colombier 			break;
463*3de6a9c0SDavid du Colombier 		case 'R':
464*3de6a9c0SDavid du Colombier 		case 'r':
465*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
466*3de6a9c0SDavid du Colombier 			(*p->phys->rts)(p, n);
467*3de6a9c0SDavid du Colombier 			break;
468*3de6a9c0SDavid du Colombier 		case 'S':
469*3de6a9c0SDavid du Colombier 		case 's':
470*3de6a9c0SDavid du Colombier 			uartdrainoutput(p);
471*3de6a9c0SDavid du Colombier 			if((*p->phys->stop)(p, n) < 0)
472*3de6a9c0SDavid du Colombier 				return -1;
473*3de6a9c0SDavid du Colombier 			break;
474*3de6a9c0SDavid du Colombier 		case 'W':
475*3de6a9c0SDavid du Colombier 		case 'w':
476*3de6a9c0SDavid du Colombier 			if(uarttimer == nil || n < 1)
477*3de6a9c0SDavid du Colombier 				return -1;
478*3de6a9c0SDavid du Colombier 			uarttimer->tns = (vlong)n * 100000LL;
479*3de6a9c0SDavid du Colombier 			break;
480*3de6a9c0SDavid du Colombier 		case 'X':
481*3de6a9c0SDavid du Colombier 		case 'x':
482*3de6a9c0SDavid du Colombier 			if(p->enabled){
483*3de6a9c0SDavid du Colombier 				ilock(&p->tlock);
484*3de6a9c0SDavid du Colombier 				p->xonoff = n;
485*3de6a9c0SDavid du Colombier 				iunlock(&p->tlock);
486*3de6a9c0SDavid du Colombier 			}
487*3de6a9c0SDavid du Colombier 			break;
488*3de6a9c0SDavid du Colombier 		}
489*3de6a9c0SDavid du Colombier 	}
490*3de6a9c0SDavid du Colombier 	return 0;
491*3de6a9c0SDavid du Colombier }
492*3de6a9c0SDavid du Colombier 
493*3de6a9c0SDavid du Colombier static long
494*3de6a9c0SDavid du Colombier uartwrite(Chan *c, void *buf, long n, vlong)
495*3de6a9c0SDavid du Colombier {
496*3de6a9c0SDavid du Colombier 	Uart *p;
497*3de6a9c0SDavid du Colombier 	char *cmd;
498*3de6a9c0SDavid du Colombier 
499*3de6a9c0SDavid du Colombier 	if(c->qid.type & QTDIR)
500*3de6a9c0SDavid du Colombier 		error(Eperm);
501*3de6a9c0SDavid du Colombier 
502*3de6a9c0SDavid du Colombier 	p = uart[NETID(c->qid.path)];
503*3de6a9c0SDavid du Colombier 
504*3de6a9c0SDavid du Colombier 	switch(NETTYPE(c->qid.path)){
505*3de6a9c0SDavid du Colombier 	case Ndataqid:
506*3de6a9c0SDavid du Colombier 		qlock(p);
507*3de6a9c0SDavid du Colombier 		if(waserror()){
508*3de6a9c0SDavid du Colombier 			qunlock(p);
509*3de6a9c0SDavid du Colombier 			nexterror();
510*3de6a9c0SDavid du Colombier 		}
511*3de6a9c0SDavid du Colombier 
512*3de6a9c0SDavid du Colombier 		n = qwrite(p->oq, buf, n);
513*3de6a9c0SDavid du Colombier 
514*3de6a9c0SDavid du Colombier 		qunlock(p);
515*3de6a9c0SDavid du Colombier 		poperror();
516*3de6a9c0SDavid du Colombier 		break;
517*3de6a9c0SDavid du Colombier 	case Nctlqid:
518*3de6a9c0SDavid du Colombier 		cmd = malloc(n+1);
519*3de6a9c0SDavid du Colombier 		memmove(cmd, buf, n);
520*3de6a9c0SDavid du Colombier 		cmd[n] = 0;
521*3de6a9c0SDavid du Colombier 		qlock(p);
522*3de6a9c0SDavid du Colombier 		if(waserror()){
523*3de6a9c0SDavid du Colombier 			qunlock(p);
524*3de6a9c0SDavid du Colombier 			free(cmd);
525*3de6a9c0SDavid du Colombier 			nexterror();
526*3de6a9c0SDavid du Colombier 		}
527*3de6a9c0SDavid du Colombier 
528*3de6a9c0SDavid du Colombier 		/* let output drain */
529*3de6a9c0SDavid du Colombier 		if(uartctl(p, cmd) < 0)
530*3de6a9c0SDavid du Colombier 			error(Ebadarg);
531*3de6a9c0SDavid du Colombier 
532*3de6a9c0SDavid du Colombier 		qunlock(p);
533*3de6a9c0SDavid du Colombier 		poperror();
534*3de6a9c0SDavid du Colombier 		free(cmd);
535*3de6a9c0SDavid du Colombier 		break;
536*3de6a9c0SDavid du Colombier 	}
537*3de6a9c0SDavid du Colombier 
538*3de6a9c0SDavid du Colombier 	return n;
539*3de6a9c0SDavid du Colombier }
540*3de6a9c0SDavid du Colombier 
541*3de6a9c0SDavid du Colombier static int
542*3de6a9c0SDavid du Colombier uartwstat(Chan *c, uchar *dp, int n)
543*3de6a9c0SDavid du Colombier {
544*3de6a9c0SDavid du Colombier 	Dir d;
545*3de6a9c0SDavid du Colombier 	Dirtab *dt;
546*3de6a9c0SDavid du Colombier 
547*3de6a9c0SDavid du Colombier 	if(!iseve())
548*3de6a9c0SDavid du Colombier 		error(Eperm);
549*3de6a9c0SDavid du Colombier 	if(QTDIR & c->qid.type)
550*3de6a9c0SDavid du Colombier 		error(Eperm);
551*3de6a9c0SDavid du Colombier 	if(NETTYPE(c->qid.path) == Nstatqid)
552*3de6a9c0SDavid du Colombier 		error(Eperm);
553*3de6a9c0SDavid du Colombier 
554*3de6a9c0SDavid du Colombier 	dt = &uartdir[1 + 3 * NETID(c->qid.path)];
555*3de6a9c0SDavid du Colombier 	n = convM2D(dp, n, &d, nil);
556*3de6a9c0SDavid du Colombier 	if(n == 0)
557*3de6a9c0SDavid du Colombier 		error(Eshortstat);
558*3de6a9c0SDavid du Colombier 	if(d.mode != ~0UL)
559*3de6a9c0SDavid du Colombier 		dt[0].perm = dt[1].perm = d.mode;
560*3de6a9c0SDavid du Colombier 	return n;
561*3de6a9c0SDavid du Colombier }
562*3de6a9c0SDavid du Colombier 
563*3de6a9c0SDavid du Colombier void
564*3de6a9c0SDavid du Colombier uartpower(int on)
565*3de6a9c0SDavid du Colombier {
566*3de6a9c0SDavid du Colombier 	Uart *p;
567*3de6a9c0SDavid du Colombier 
568*3de6a9c0SDavid du Colombier 	for(p = uartlist; p != nil; p = p->next) {
569*3de6a9c0SDavid du Colombier 		if(p->phys->power)
570*3de6a9c0SDavid du Colombier 			(*p->phys->power)(p, on);
571*3de6a9c0SDavid du Colombier 	}
572*3de6a9c0SDavid du Colombier }
573*3de6a9c0SDavid du Colombier 
574*3de6a9c0SDavid du Colombier Dev uartdevtab = {
575*3de6a9c0SDavid du Colombier 	't',
576*3de6a9c0SDavid du Colombier 	"uart",
577*3de6a9c0SDavid du Colombier 
578*3de6a9c0SDavid du Colombier 	uartreset,
579*3de6a9c0SDavid du Colombier 	devinit,
580*3de6a9c0SDavid du Colombier 	devshutdown,
581*3de6a9c0SDavid du Colombier 	uartattach,
582*3de6a9c0SDavid du Colombier 	uartwalk,
583*3de6a9c0SDavid du Colombier 	uartstat,
584*3de6a9c0SDavid du Colombier 	uartopen,
585*3de6a9c0SDavid du Colombier 	devcreate,
586*3de6a9c0SDavid du Colombier 	uartclose,
587*3de6a9c0SDavid du Colombier 	uartread,
588*3de6a9c0SDavid du Colombier 	devbread,
589*3de6a9c0SDavid du Colombier 	uartwrite,
590*3de6a9c0SDavid du Colombier 	devbwrite,
591*3de6a9c0SDavid du Colombier 	devremove,
592*3de6a9c0SDavid du Colombier 	uartwstat,
593*3de6a9c0SDavid du Colombier 	uartpower,
594*3de6a9c0SDavid du Colombier };
595*3de6a9c0SDavid du Colombier 
596*3de6a9c0SDavid du Colombier /*
597*3de6a9c0SDavid du Colombier  *  restart input if it's off
598*3de6a9c0SDavid du Colombier  */
599*3de6a9c0SDavid du Colombier static void
600*3de6a9c0SDavid du Colombier uartflow(void *v)
601*3de6a9c0SDavid du Colombier {
602*3de6a9c0SDavid du Colombier 	Uart *p;
603*3de6a9c0SDavid du Colombier 
604*3de6a9c0SDavid du Colombier 	p = v;
605*3de6a9c0SDavid du Colombier 	if(p->modem)
606*3de6a9c0SDavid du Colombier 		(*p->phys->rts)(p, 1);
607*3de6a9c0SDavid du Colombier }
608*3de6a9c0SDavid du Colombier 
609*3de6a9c0SDavid du Colombier /*
610*3de6a9c0SDavid du Colombier  *  put some bytes into the local queue to avoid calling
611*3de6a9c0SDavid du Colombier  *  qconsume for every character
612*3de6a9c0SDavid du Colombier  */
613*3de6a9c0SDavid du Colombier int
614*3de6a9c0SDavid du Colombier uartstageoutput(Uart *p)
615*3de6a9c0SDavid du Colombier {
616*3de6a9c0SDavid du Colombier 	int n;
617*3de6a9c0SDavid du Colombier 
618*3de6a9c0SDavid du Colombier 	n = qconsume(p->oq, p->ostage, Stagesize);
619*3de6a9c0SDavid du Colombier 	if(n <= 0)
620*3de6a9c0SDavid du Colombier //		n = 0;			/* experiment */
621*3de6a9c0SDavid du Colombier 		return 0;
622*3de6a9c0SDavid du Colombier 	p->op = p->ostage;
623*3de6a9c0SDavid du Colombier 	p->oe = p->ostage + n;
624*3de6a9c0SDavid du Colombier 	return n;
625*3de6a9c0SDavid du Colombier }
626*3de6a9c0SDavid du Colombier 
627*3de6a9c0SDavid du Colombier /*
628*3de6a9c0SDavid du Colombier  *  restart output
629*3de6a9c0SDavid du Colombier  */
630*3de6a9c0SDavid du Colombier void
631*3de6a9c0SDavid du Colombier uartkick(void *v)
632*3de6a9c0SDavid du Colombier {
633*3de6a9c0SDavid du Colombier 	Uart *p = v;
634*3de6a9c0SDavid du Colombier 
635*3de6a9c0SDavid du Colombier 	if(p->blocked)
636*3de6a9c0SDavid du Colombier 		return;
637*3de6a9c0SDavid du Colombier 
638*3de6a9c0SDavid du Colombier 	ilock(&p->tlock);
639*3de6a9c0SDavid du Colombier 	(*p->phys->kick)(p);
640*3de6a9c0SDavid du Colombier 	iunlock(&p->tlock);
641*3de6a9c0SDavid du Colombier 
642*3de6a9c0SDavid du Colombier 	if(p->drain && uartdrained(p)){
643*3de6a9c0SDavid du Colombier 		p->drain = 0;
644*3de6a9c0SDavid du Colombier 		wakeup(&p->r);
645*3de6a9c0SDavid du Colombier 	}
646*3de6a9c0SDavid du Colombier }
647*3de6a9c0SDavid du Colombier 
648*3de6a9c0SDavid du Colombier /*
649*3de6a9c0SDavid du Colombier  * Move data from the interrupt staging area to
650*3de6a9c0SDavid du Colombier  * the input Queue.
651*3de6a9c0SDavid du Colombier  */
652*3de6a9c0SDavid du Colombier static void
653*3de6a9c0SDavid du Colombier uartstageinput(Uart *p)
654*3de6a9c0SDavid du Colombier {
655*3de6a9c0SDavid du Colombier 	int n;
656*3de6a9c0SDavid du Colombier 	uchar *ir, *iw;
657*3de6a9c0SDavid du Colombier 
658*3de6a9c0SDavid du Colombier 	while(p->ir != p->iw){
659*3de6a9c0SDavid du Colombier 		ir = p->ir;
660*3de6a9c0SDavid du Colombier 		if(p->ir > p->iw){
661*3de6a9c0SDavid du Colombier 			iw = p->ie;
662*3de6a9c0SDavid du Colombier 			p->ir = p->istage;
663*3de6a9c0SDavid du Colombier 		}
664*3de6a9c0SDavid du Colombier 		else{
665*3de6a9c0SDavid du Colombier 			iw = p->iw;
666*3de6a9c0SDavid du Colombier 			p->ir = p->iw;
667*3de6a9c0SDavid du Colombier 		}
668*3de6a9c0SDavid du Colombier 		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
669*3de6a9c0SDavid du Colombier 			p->serr++;
670*3de6a9c0SDavid du Colombier 			(*p->phys->rts)(p, 0);
671*3de6a9c0SDavid du Colombier 		}
672*3de6a9c0SDavid du Colombier 		else if(n == 0)
673*3de6a9c0SDavid du Colombier 			p->berr++;
674*3de6a9c0SDavid du Colombier 	}
675*3de6a9c0SDavid du Colombier }
676*3de6a9c0SDavid du Colombier 
677*3de6a9c0SDavid du Colombier /*
678*3de6a9c0SDavid du Colombier  *  receive a character at interrupt time
679*3de6a9c0SDavid du Colombier  */
680*3de6a9c0SDavid du Colombier void
681*3de6a9c0SDavid du Colombier uartrecv(Uart *p,  char ch)
682*3de6a9c0SDavid du Colombier {
683*3de6a9c0SDavid du Colombier 	uchar *next;
684*3de6a9c0SDavid du Colombier 
685*3de6a9c0SDavid du Colombier 	/* software flow control */
686*3de6a9c0SDavid du Colombier 	if(p->xonoff){
687*3de6a9c0SDavid du Colombier 		if(ch == CTLS){
688*3de6a9c0SDavid du Colombier 			p->blocked = 1;
689*3de6a9c0SDavid du Colombier 		}else if(ch == CTLQ){
690*3de6a9c0SDavid du Colombier 			p->blocked = 0;
691*3de6a9c0SDavid du Colombier 			p->ctsbackoff = 2; /* clock gets output going again */
692*3de6a9c0SDavid du Colombier 		}
693*3de6a9c0SDavid du Colombier 	}
694*3de6a9c0SDavid du Colombier 
695*3de6a9c0SDavid du Colombier 	/* receive the character */
696*3de6a9c0SDavid du Colombier 	if(p->putc)
697*3de6a9c0SDavid du Colombier 		p->putc(p->iq, ch);
698*3de6a9c0SDavid du Colombier 	else if (p->iw) {		/* maybe the line isn't enabled yet */
699*3de6a9c0SDavid du Colombier 		ilock(&p->rlock);
700*3de6a9c0SDavid du Colombier 		next = p->iw + 1;
701*3de6a9c0SDavid du Colombier 		if(next == p->ie)
702*3de6a9c0SDavid du Colombier 			next = p->istage;
703*3de6a9c0SDavid du Colombier 		if(next == p->ir)
704*3de6a9c0SDavid du Colombier 			uartstageinput(p);
705*3de6a9c0SDavid du Colombier 		if(next != p->ir){
706*3de6a9c0SDavid du Colombier 			*p->iw = ch;
707*3de6a9c0SDavid du Colombier 			p->iw = next;
708*3de6a9c0SDavid du Colombier 		}
709*3de6a9c0SDavid du Colombier 		iunlock(&p->rlock);
710*3de6a9c0SDavid du Colombier 	}
711*3de6a9c0SDavid du Colombier }
712*3de6a9c0SDavid du Colombier 
713*3de6a9c0SDavid du Colombier /*
714*3de6a9c0SDavid du Colombier  *  we save up input characters till clock time to reduce
715*3de6a9c0SDavid du Colombier  *  per character interrupt overhead.
716*3de6a9c0SDavid du Colombier  */
717*3de6a9c0SDavid du Colombier static void
718*3de6a9c0SDavid du Colombier uartclock(void)
719*3de6a9c0SDavid du Colombier {
720*3de6a9c0SDavid du Colombier 	Uart *p;
721*3de6a9c0SDavid du Colombier 
722*3de6a9c0SDavid du Colombier 	ilock(&uartalloc);
723*3de6a9c0SDavid du Colombier 	for(p = uartalloc.elist; p; p = p->elist){
724*3de6a9c0SDavid du Colombier 
725*3de6a9c0SDavid du Colombier 		/* this hopefully amortizes cost of qproduce to many chars */
726*3de6a9c0SDavid du Colombier 		if(p->iw != p->ir){
727*3de6a9c0SDavid du Colombier 			ilock(&p->rlock);
728*3de6a9c0SDavid du Colombier 			uartstageinput(p);
729*3de6a9c0SDavid du Colombier 			iunlock(&p->rlock);
730*3de6a9c0SDavid du Colombier 		}
731*3de6a9c0SDavid du Colombier 
732*3de6a9c0SDavid du Colombier 		/* hang up if requested */
733*3de6a9c0SDavid du Colombier 		if(p->dohup){
734*3de6a9c0SDavid du Colombier 			qhangup(p->iq, 0);
735*3de6a9c0SDavid du Colombier 			qhangup(p->oq, 0);
736*3de6a9c0SDavid du Colombier 			p->dohup = 0;
737*3de6a9c0SDavid du Colombier 		}
738*3de6a9c0SDavid du Colombier 
739*3de6a9c0SDavid du Colombier 		/* this adds hysteresis to hardware/software flow control */
740*3de6a9c0SDavid du Colombier 		if(p->ctsbackoff){
741*3de6a9c0SDavid du Colombier 			ilock(&p->tlock);
742*3de6a9c0SDavid du Colombier 			if(p->ctsbackoff){
743*3de6a9c0SDavid du Colombier 				if(--(p->ctsbackoff) == 0)
744*3de6a9c0SDavid du Colombier 					(*p->phys->kick)(p);
745*3de6a9c0SDavid du Colombier 			}
746*3de6a9c0SDavid du Colombier 			iunlock(&p->tlock);
747*3de6a9c0SDavid du Colombier 		}
748*3de6a9c0SDavid du Colombier 		uartkick(p);		/* keep it moving */
749*3de6a9c0SDavid du Colombier 	}
750*3de6a9c0SDavid du Colombier 	iunlock(&uartalloc);
751*3de6a9c0SDavid du Colombier }
752*3de6a9c0SDavid du Colombier 
753*3de6a9c0SDavid du Colombier /*
754*3de6a9c0SDavid du Colombier  * polling console input, output
755*3de6a9c0SDavid du Colombier  */
756*3de6a9c0SDavid du Colombier 
757*3de6a9c0SDavid du Colombier Uart* consuart;
758*3de6a9c0SDavid du Colombier 
759*3de6a9c0SDavid du Colombier int
760*3de6a9c0SDavid du Colombier uartgetc(void)
761*3de6a9c0SDavid du Colombier {
762*3de6a9c0SDavid du Colombier 	if(consuart == nil || consuart->phys->getc == nil)
763*3de6a9c0SDavid du Colombier 		return -1;
764*3de6a9c0SDavid du Colombier 	return consuart->phys->getc(consuart);
765*3de6a9c0SDavid du Colombier }
766*3de6a9c0SDavid du Colombier 
767*3de6a9c0SDavid du Colombier void
768*3de6a9c0SDavid du Colombier uartputc(int c)
769*3de6a9c0SDavid du Colombier {
770*3de6a9c0SDavid du Colombier 	char c2;
771*3de6a9c0SDavid du Colombier 
772*3de6a9c0SDavid du Colombier 	if(consuart == nil || consuart->phys->putc == nil) {
773*3de6a9c0SDavid du Colombier 		c2 = c;
774*3de6a9c0SDavid du Colombier 		_uartputs(&c2, 1);
775*3de6a9c0SDavid du Colombier 		return;
776*3de6a9c0SDavid du Colombier 	}
777*3de6a9c0SDavid du Colombier 	consuart->phys->putc(consuart, c);
778*3de6a9c0SDavid du Colombier }
779*3de6a9c0SDavid du Colombier 
780*3de6a9c0SDavid du Colombier void
781*3de6a9c0SDavid du Colombier uartputs(char *s, int n)
782*3de6a9c0SDavid du Colombier {
783*3de6a9c0SDavid du Colombier 	char *e;
784*3de6a9c0SDavid du Colombier 
785*3de6a9c0SDavid du Colombier 	if(consuart == nil || consuart->phys->putc == nil) {
786*3de6a9c0SDavid du Colombier 		_uartputs(s, n);
787*3de6a9c0SDavid du Colombier 		return;
788*3de6a9c0SDavid du Colombier 	}
789*3de6a9c0SDavid du Colombier 
790*3de6a9c0SDavid du Colombier 	e = s+n;
791*3de6a9c0SDavid du Colombier 	for(; s<e; s++){
792*3de6a9c0SDavid du Colombier 		if(*s == '\n')
793*3de6a9c0SDavid du Colombier 			consuart->phys->putc(consuart, '\r');
794*3de6a9c0SDavid du Colombier 		consuart->phys->putc(consuart, *s);
795*3de6a9c0SDavid du Colombier 	}
796*3de6a9c0SDavid du Colombier }
797