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