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