xref: /plan9-contrib/sys/src/9/port/devuart.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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 'W':
462 		case 'w':
463 			if(uarttimer == nil || n < 1)
464 				return -1;
465 			uarttimer->tns = (vlong)n * 100000LL;
466 			break;
467 		case 'X':
468 		case 'x':
469 			if(p->enabled){
470 				ilock(&p->tlock);
471 				p->xonoff = n;
472 				iunlock(&p->tlock);
473 			}
474 			break;
475 		}
476 	}
477 	return 0;
478 }
479 
480 static long
481 uartwrite(Chan *c, void *buf, long n, vlong)
482 {
483 	Uart *p;
484 	char *cmd;
485 
486 	if(c->qid.type & QTDIR)
487 		error(Eperm);
488 
489 	p = uart[NETID(c->qid.path)];
490 
491 	switch(NETTYPE(c->qid.path)){
492 	case Ndataqid:
493 		qlock(p);
494 		if(waserror()){
495 			qunlock(p);
496 			nexterror();
497 		}
498 
499 		n = qwrite(p->oq, buf, n);
500 
501 		qunlock(p);
502 		poperror();
503 		break;
504 	case Nctlqid:
505 		cmd = malloc(n+1);
506 		memmove(cmd, buf, n);
507 		cmd[n] = 0;
508 		qlock(p);
509 		if(waserror()){
510 			qunlock(p);
511 			free(cmd);
512 			nexterror();
513 		}
514 
515 		/* let output drain */
516 		if(uartctl(p, cmd) < 0)
517 			error(Ebadarg);
518 
519 		qunlock(p);
520 		poperror();
521 		free(cmd);
522 		break;
523 	}
524 
525 	return n;
526 }
527 
528 static int
529 uartwstat(Chan *c, uchar *dp, int n)
530 {
531 	Dir d;
532 	Dirtab *dt;
533 
534 	if(!iseve())
535 		error(Eperm);
536 	if(QTDIR & c->qid.type)
537 		error(Eperm);
538 	if(NETTYPE(c->qid.path) == Nstatqid)
539 		error(Eperm);
540 
541 	dt = &uartdir[1 + 3 * NETID(c->qid.path)];
542 	n = convM2D(dp, n, &d, nil);
543 	if(n == 0)
544 		error(Eshortstat);
545 	if(d.mode != ~0UL)
546 		dt[0].perm = dt[1].perm = d.mode;
547 	return n;
548 }
549 
550 void
551 uartpower(int on)
552 {
553 	Uart *p;
554 
555 	for(p = uartlist; p != nil; p = p->next) {
556 		if(p->phys->power)
557 			(*p->phys->power)(p, on);
558 	}
559 }
560 
561 Dev uartdevtab = {
562 	't',
563 	"uart",
564 
565 	uartreset,
566 	devinit,
567 	devshutdown,
568 	uartattach,
569 	uartwalk,
570 	uartstat,
571 	uartopen,
572 	devcreate,
573 	uartclose,
574 	uartread,
575 	devbread,
576 	uartwrite,
577 	devbwrite,
578 	devremove,
579 	uartwstat,
580 	uartpower,
581 };
582 
583 /*
584  *  restart input if it's off
585  */
586 static void
587 uartflow(void *v)
588 {
589 	Uart *p;
590 
591 	p = v;
592 	if(p->modem)
593 		(*p->phys->rts)(p, 1);
594 }
595 
596 /*
597  *  put some bytes into the local queue to avoid calling
598  *  qconsume for every character
599  */
600 int
601 uartstageoutput(Uart *p)
602 {
603 	int n;
604 
605 	n = qconsume(p->oq, p->ostage, Stagesize);
606 	if(n <= 0)
607 		return 0;
608 	p->op = p->ostage;
609 	p->oe = p->ostage + n;
610 	return n;
611 }
612 
613 /*
614  *  restart output
615  */
616 void
617 uartkick(void *v)
618 {
619 	Uart *p = v;
620 
621 	if(p->blocked)
622 		return;
623 
624 	ilock(&p->tlock);
625 	(*p->phys->kick)(p);
626 	iunlock(&p->tlock);
627 
628 	if(p->drain && uartdrained(p)){
629 		p->drain = 0;
630 		wakeup(&p->r);
631 	}
632 }
633 
634 /*
635  * Move data from the interrupt staging area to
636  * the input Queue.
637  */
638 static void
639 uartstageinput(Uart *p)
640 {
641 	int n;
642 	uchar *ir, *iw;
643 
644 	while(p->ir != p->iw){
645 		ir = p->ir;
646 		if(p->ir > p->iw){
647 			iw = p->ie;
648 			p->ir = p->istage;
649 		}
650 		else{
651 			iw = p->iw;
652 			p->ir = p->iw;
653 		}
654 		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
655 			p->serr++;
656 			(*p->phys->rts)(p, 0);
657 		}
658 		else if(n == 0)
659 			p->berr++;
660 	}
661 }
662 
663 /*
664  *  receive a character at interrupt time
665  */
666 void
667 uartrecv(Uart *p,  char ch)
668 {
669 	uchar *next;
670 
671 	/* software flow control */
672 	if(p->xonoff){
673 		if(ch == CTLS){
674 			p->blocked = 1;
675 		}else if(ch == CTLQ){
676 			p->blocked = 0;
677 			p->ctsbackoff = 2; /* clock gets output going again */
678 		}
679 	}
680 
681 	/* receive the character */
682 	if(p->putc)
683 		p->putc(p->iq, ch);
684 	else{
685 		ilock(&p->rlock);
686 		next = p->iw + 1;
687 		if(next == p->ie)
688 			next = p->istage;
689 		if(next == p->ir)
690 			uartstageinput(p);
691 		if(next != p->ir){
692 			*p->iw = ch;
693 			p->iw = next;
694 		}
695 		iunlock(&p->rlock);
696 	}
697 }
698 
699 /*
700  *  we save up input characters till clock time to reduce
701  *  per character interrupt overhead.
702  */
703 static void
704 uartclock(void)
705 {
706 	Uart *p;
707 
708 	lock(&uartalloc);
709 	for(p = uartalloc.elist; p; p = p->elist){
710 
711 		/* this hopefully amortizes cost of qproduce to many chars */
712 		if(p->iw != p->ir){
713 			ilock(&p->rlock);
714 			uartstageinput(p);
715 			iunlock(&p->rlock);
716 		}
717 
718 		/* hang up if requested */
719 		if(p->dohup){
720 			qhangup(p->iq, 0);
721 			qhangup(p->oq, 0);
722 			p->dohup = 0;
723 		}
724 
725 		/* this adds hysteresis to hardware/software flow control */
726 		if(p->ctsbackoff){
727 			ilock(&p->tlock);
728 			if(p->ctsbackoff){
729 				if(--(p->ctsbackoff) == 0)
730 					(*p->phys->kick)(p);
731 			}
732 			iunlock(&p->tlock);
733 		}
734 	}
735 	unlock(&uartalloc);
736 }
737 
738 /*
739  * polling console input, output
740  */
741 
742 Uart* consuart;
743 
744 int
745 uartgetc(void)
746 {
747 	if(consuart == nil || consuart->phys->getc == nil)
748 		return -1;
749 	return consuart->phys->getc(consuart);
750 }
751 
752 void
753 uartputc(int c)
754 {
755 	if(consuart == nil || consuart->phys->putc == nil)
756 		return;
757 	consuart->phys->putc(consuart, c);
758 }
759 
760 void
761 uartputs(char *s, int n)
762 {
763 	char *e;
764 
765 	if(consuart == nil || consuart->phys->putc == nil)
766 		return;
767 
768 	e = s+n;
769 	for(; s<e; s++){
770 		if(*s == '\n')
771 			consuart->phys->putc(consuart, '\r');
772 		consuart->phys->putc(consuart, *s);
773 	}
774 }
775