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