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