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