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