xref: /plan9/sys/src/9/teg2/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 //static
40 Uart*
uartenable(Uart * p)41 uartenable(Uart *p)
42 {
43 	Uart **l;
44 
45 	if (up == nil)
46 		return p;		/* too soon; try again later */
47 //		return nil;
48 
49 	if(p->iq == nil){
50 		if((p->iq = qopen(8*1024, 0, uartflow, p)) == nil)
51 			return nil;
52 	}
53 	else
54 		qreopen(p->iq);
55 	if(p->oq == nil){
56 		if((p->oq = qopen(8*1024, 0, uartkick, p)) == nil){
57 			qfree(p->iq);
58 			p->iq = nil;
59 			return nil;
60 		}
61 	}
62 	else
63 		qreopen(p->oq);
64 
65 	p->ir = p->istage;
66 	p->iw = p->istage;
67 	p->ie = &p->istage[Stagesize];
68 	p->op = p->ostage;
69 	p->oe = p->ostage;
70 
71 	p->hup_dsr = p->hup_dcd = 0;
72 	p->dsr = p->dcd = 0;
73 
74 	/* assume we can send */
75 	p->cts = 1;
76 	p->ctsbackoff = 0;
77 
78 	if (up) {
79 		if(p->bits == 0)
80 			uartctl(p, "l8");
81 		if(p->stop == 0)
82 			uartctl(p, "s1");
83 		if(p->parity == 0)
84 			uartctl(p, "pn");
85 		if(p->baud == 0)
86 			uartctl(p, "b9600");
87 		(*p->phys->enable)(p, 1);
88 	}
89 
90 	/*
91 	 * use ilock because uartclock can otherwise interrupt here
92 	 * and would hang on an attempt to lock uartalloc.
93 	 */
94 	ilock(&uartalloc);
95 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
96 		if(*l == p)
97 			break;
98 	}
99 	if(*l == 0){
100 		p->elist = uartalloc.elist;
101 		uartalloc.elist = p;
102 	}
103 	p->enabled = 1;
104 	iunlock(&uartalloc);
105 
106 	return p;
107 }
108 
109 static void
uartdisable(Uart * p)110 uartdisable(Uart *p)
111 {
112 	Uart **l;
113 
114 	(*p->phys->disable)(p);
115 
116 	ilock(&uartalloc);
117 	for(l = &uartalloc.elist; *l; l = &(*l)->elist){
118 		if(*l == p){
119 			*l = p->elist;
120 			break;
121 		}
122 	}
123 	p->enabled = 0;
124 	iunlock(&uartalloc);
125 }
126 
127 void
uartmouse(Uart * p,int (* putc)(Queue *,int),int setb1200)128 uartmouse(Uart* p, int (*putc)(Queue*, int), int setb1200)
129 {
130 	qlock(p);
131 	if(p->opens++ == 0 && uartenable(p) == nil){
132 		qunlock(p);
133 		error(Enodev);
134 	}
135 	if(setb1200)
136 		uartctl(p, "b1200");
137 	p->putc = putc;
138 	p->special = 1;
139 	qunlock(p);
140 }
141 
142 void
uartsetmouseputc(Uart * p,int (* putc)(Queue *,int))143 uartsetmouseputc(Uart* p, int (*putc)(Queue*, int))
144 {
145 	qlock(p);
146 	if(p->opens == 0 || p->special == 0){
147 		qunlock(p);
148 		error(Enodev);
149 	}
150 	p->putc = putc;
151 	qunlock(p);
152 }
153 
154 static void
setlength(int i)155 setlength(int i)
156 {
157 	Uart *p;
158 
159 	if(i > 0){
160 		p = uart[i];
161 		if(p && p->opens && p->iq)
162 			uartdir[1+3*i].length = qlen(p->iq);
163 	} else for(i = 0; i < uartnuart; i++){
164 		p = uart[i];
165 		if(p && p->opens && p->iq)
166 			uartdir[1+3*i].length = qlen(p->iq);
167 	}
168 }
169 
170 /*
171  *  set up the '#t' directory
172  */
173 static void
uartreset(void)174 uartreset(void)
175 {
176 	int i;
177 	Dirtab *dp;
178 	Uart *p, *tail;
179 
180 	tail = nil;
181 	for(i = 0; physuart[i] != nil; i++){
182 		if(physuart[i]->pnp == nil)
183 			continue;
184 		if((p = physuart[i]->pnp()) == nil)
185 			continue;
186 		if(uartlist != nil)
187 			tail->next = p;
188 		else
189 			uartlist = p;
190 		for(tail = p; tail->next != nil; tail = tail->next)
191 			uartnuart++;
192 		uartnuart++;
193 	}
194 
195 	if(uartnuart)
196 		uart = xalloc(uartnuart*sizeof(Uart*));
197 
198 	uartndir = 1 + 3*uartnuart;
199 	uartdir = xalloc(uartndir * sizeof(Dirtab));
200 	if (uart == nil || 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 && up){
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 || up == nil)
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 		memmove(cmd, buf, n);
520 		cmd[n] = 0;
521 		qlock(p);
522 		if(waserror()){
523 			qunlock(p);
524 			free(cmd);
525 			nexterror();
526 		}
527 
528 		/* let output drain */
529 		if(uartctl(p, cmd) < 0)
530 			error(Ebadarg);
531 
532 		qunlock(p);
533 		poperror();
534 		free(cmd);
535 		break;
536 	}
537 
538 	return n;
539 }
540 
541 static int
uartwstat(Chan * c,uchar * dp,int n)542 uartwstat(Chan *c, uchar *dp, int n)
543 {
544 	Dir d;
545 	Dirtab *dt;
546 
547 	if(!iseve())
548 		error(Eperm);
549 	if(QTDIR & c->qid.type)
550 		error(Eperm);
551 	if(NETTYPE(c->qid.path) == Nstatqid)
552 		error(Eperm);
553 
554 	dt = &uartdir[1 + 3 * NETID(c->qid.path)];
555 	n = convM2D(dp, n, &d, nil);
556 	if(n == 0)
557 		error(Eshortstat);
558 	if(d.mode != ~0UL)
559 		dt[0].perm = dt[1].perm = d.mode;
560 	return n;
561 }
562 
563 void
uartpower(int on)564 uartpower(int on)
565 {
566 	Uart *p;
567 
568 	for(p = uartlist; p != nil; p = p->next) {
569 		if(p->phys->power)
570 			(*p->phys->power)(p, on);
571 	}
572 }
573 
574 Dev uartdevtab = {
575 	't',
576 	"uart",
577 
578 	uartreset,
579 	devinit,
580 	devshutdown,
581 	uartattach,
582 	uartwalk,
583 	uartstat,
584 	uartopen,
585 	devcreate,
586 	uartclose,
587 	uartread,
588 	devbread,
589 	uartwrite,
590 	devbwrite,
591 	devremove,
592 	uartwstat,
593 	uartpower,
594 };
595 
596 /*
597  *  restart input if it's off
598  */
599 static void
uartflow(void * v)600 uartflow(void *v)
601 {
602 	Uart *p;
603 
604 	p = v;
605 	if(p->modem)
606 		(*p->phys->rts)(p, 1);
607 }
608 
609 /*
610  *  put some bytes into the local queue to avoid calling
611  *  qconsume for every character
612  */
613 int
uartstageoutput(Uart * p)614 uartstageoutput(Uart *p)
615 {
616 	int n;
617 
618 	n = qconsume(p->oq, p->ostage, Stagesize);
619 	if(n <= 0)
620 //		n = 0;			/* experiment */
621 		return 0;
622 	p->op = p->ostage;
623 	p->oe = p->ostage + n;
624 	return n;
625 }
626 
627 /*
628  *  restart output
629  */
630 void
uartkick(void * v)631 uartkick(void *v)
632 {
633 	Uart *p = v;
634 
635 	if(p->blocked)
636 		return;
637 
638 	ilock(&p->tlock);
639 	(*p->phys->kick)(p);
640 	iunlock(&p->tlock);
641 
642 	if(p->drain && uartdrained(p)){
643 		p->drain = 0;
644 		wakeup(&p->r);
645 	}
646 }
647 
648 /*
649  * Move data from the interrupt staging area to
650  * the input Queue.
651  */
652 static void
uartstageinput(Uart * p)653 uartstageinput(Uart *p)
654 {
655 	int n;
656 	uchar *ir, *iw;
657 
658 	while(p->ir != p->iw){
659 		ir = p->ir;
660 		if(p->ir > p->iw){
661 			iw = p->ie;
662 			p->ir = p->istage;
663 		}
664 		else{
665 			iw = p->iw;
666 			p->ir = p->iw;
667 		}
668 		if((n = qproduce(p->iq, ir, iw - ir)) < 0){
669 			p->serr++;
670 			(*p->phys->rts)(p, 0);
671 		}
672 		else if(n == 0)
673 			p->berr++;
674 	}
675 }
676 
677 /*
678  *  receive a character at interrupt time
679  */
680 void
uartrecv(Uart * p,char ch)681 uartrecv(Uart *p,  char ch)
682 {
683 	uchar *next;
684 
685 	/* software flow control */
686 	if(p->xonoff){
687 		if(ch == CTLS){
688 			p->blocked = 1;
689 		}else if(ch == CTLQ){
690 			p->blocked = 0;
691 			p->ctsbackoff = 2; /* clock gets output going again */
692 		}
693 	}
694 
695 	/* receive the character */
696 	if(p->putc)
697 		p->putc(p->iq, ch);
698 	else if (p->iw) {		/* maybe the line isn't enabled yet */
699 		ilock(&p->rlock);
700 		next = p->iw + 1;
701 		if(next == p->ie)
702 			next = p->istage;
703 		if(next == p->ir)
704 			uartstageinput(p);
705 		if(next != p->ir){
706 			*p->iw = ch;
707 			p->iw = next;
708 		}
709 		iunlock(&p->rlock);
710 	}
711 }
712 
713 /*
714  *  we save up input characters till clock time to reduce
715  *  per character interrupt overhead.
716  */
717 static void
uartclock(void)718 uartclock(void)
719 {
720 	Uart *p;
721 
722 	ilock(&uartalloc);
723 	for(p = uartalloc.elist; p; p = p->elist){
724 
725 		/* this hopefully amortizes cost of qproduce to many chars */
726 		if(p->iw != p->ir){
727 			ilock(&p->rlock);
728 			uartstageinput(p);
729 			iunlock(&p->rlock);
730 		}
731 
732 		/* hang up if requested */
733 		if(p->dohup){
734 			qhangup(p->iq, 0);
735 			qhangup(p->oq, 0);
736 			p->dohup = 0;
737 		}
738 
739 		/* this adds hysteresis to hardware/software flow control */
740 		if(p->ctsbackoff){
741 			ilock(&p->tlock);
742 			if(p->ctsbackoff){
743 				if(--(p->ctsbackoff) == 0)
744 					(*p->phys->kick)(p);
745 			}
746 			iunlock(&p->tlock);
747 		}
748 		uartkick(p);		/* keep it moving */
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 
792 	e = s+n;
793 	for(; s<e; s++){
794 		if(*s == '\n')
795 			consuart->phys->putc(consuart, '\r');
796 		consuart->phys->putc(consuart, *s);
797 	}
798 }
799