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