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 #include "../port/netif.h"
9
10 /*
11 * currently no DMA or flow control (hardware or software)
12 */
13
14 /*
15 * problems fixed from previous vsn:
16 *
17 * - no kick on queue's, so redirections weren't getting
18 * started until the clock tick
19 *
20 * - lots of unnecessary overhead
21 *
22 * - initialization sequencing
23 *
24 * - uart[n] no longer indexed before calling uartinstall()
25 */
26 #define DEBUG if(0)iprint
27
28 static void uartintr(Ureg*, void*);
29
30 enum
31 {
32 Stagesize= 1024,
33 Dmabufsize=Stagesize/2,
34 Nuart=7, /* max per machine */
35 };
36
37 typedef struct Uart Uart;
38 struct Uart
39 {
40 QLock;
41
42 int opens;
43
44 int enabled;
45
46 int port; /* 0 or 1 */
47 int kickme; /* for kick */
48 int frame; /* framing errors */
49 int overrun; /* rcvr overruns */
50 int perror; /* parity error */
51 int bps; /* baud rate */
52 uchar bits;
53 char parity;
54 uchar stop;
55
56 int inters; /* total interrupt count */
57 int rinters; /* interrupts due to read */
58 int winters; /* interrupts due to write */
59
60 int rcount; /* total read count */
61 int wcount; /* total output count */
62
63 /* buffers */
64 int (*putc)(Queue*, int);
65 Queue *iq;
66 Queue *oq;
67
68 UartReg *reg;
69
70 /* staging areas to avoid some of the per character costs */
71 uchar *ip;
72 uchar *ie;
73 uchar *op;
74 uchar *oe;
75
76 /* put large buffers last to aid register-offset optimizations: */
77 char name[KNAMELEN];
78 uchar istage[Stagesize];
79 uchar ostage[Stagesize];
80 };
81
82 #define UCON_ENABLEMASK (UCON_RXMDMASK | UCON_TXMDMASK | UCON_SINTMASK)
83 #define UCON_ENABLESET (UCON_RXMDINT | UCON_TXMDINT | UCON_SINTON)
84 #define UCON_DISABLESET (UCON_RXMDOFF | UCON_TXMDOFF | UCON_SINTOFF)
85
86 static Uart *uart[Nuart];
87 static int nuart;
88
89 static uchar
readstatus(Uart * p)90 readstatus(Uart *p)
91 {
92 UartReg *reg = p->reg;
93 uchar stat = reg->stat;
94 if (stat & USTAT_OV)
95 p->overrun++;
96 if (stat & USTAT_PE)
97 p->perror++;
98 if (stat & USTAT_FE)
99 p->frame++;
100 return stat;
101 }
102
103 static void
uartset(Uart * p)104 uartset(Uart *p)
105 {
106 UartReg *reg = p->reg;
107 ulong denom;
108 ulong brdiv;
109 int n;
110 uchar lcon;
111
112 lcon= ULCON_CLOCKMCLK | ULCON_IROFF;
113 lcon |= ULCON_WL5 + (p->bits - 5);
114 lcon |= p->stop == 1 ? ULCON_STOP1 : ULCON_STOP2;
115 switch (p->parity) {
116 default:
117 case 'n':
118 lcon |= ULCON_PMDNONE;
119 break;
120 case 'o':
121 lcon |= ULCON_PMDODD;
122 break;
123 case 'e':
124 lcon |= ULCON_PMDEVEN;
125 break;
126 }
127 reg->lcon = lcon;
128
129 /* clear the break and loopback bits; leave everything else alone */
130 reg->con = (reg->con & ~(UCON_BRKMASK | UCON_LOOPMASK)) | UCON_BRKOFF | UCON_LOOPOFF;
131
132 denom = 2 * 16 * p->bps;
133 brdiv = (TIMER_HZ + denom / 2) / denom - 1;
134 reg->brdiv = brdiv << 4;
135
136 /* set buffer length according to speed, to allow
137 * at most a 200ms delay before dumping the staging buffer
138 * into the input queue
139 */
140 n = p->bps/(10*1000/200);
141 p->ie = &p->istage[n < Stagesize ? n : Stagesize];
142 }
143
144 /*
145 * send break
146 */
147 static void
uartbreak(Uart * p,int ms)148 uartbreak(Uart *p, int ms)
149 {
150 UartReg *reg = p->reg;
151 if(ms == 0)
152 ms = 200;
153 reg->con |= UCON_BRKON;
154 tsleep(&up->sleep, return0, 0, ms);
155 reg->con &= ~UCON_BRKON;
156 }
157
158 /*
159 * turn on a port
160 */
161 static void
uartenable(Uart * p)162 uartenable(Uart *p)
163 {
164 UartReg *reg = p->reg;
165
166 if(p->enabled)
167 return;
168
169 uartset(p);
170 // enable receive, transmit, and receive interrupt:
171 reg->con = (reg->con & UCON_ENABLEMASK) | UCON_ENABLESET;
172 p->enabled = 1;
173 }
174
175 /*
176 * turn off a port
177 */
178 static void
uartdisable(Uart * p)179 uartdisable(Uart *p)
180 {
181 p->reg->con = (p->reg->con & UCON_ENABLEMASK) | UCON_DISABLESET;
182 p->enabled = 0;
183 }
184
185 /*
186 * put some bytes into the local queue to avoid calling
187 * qconsume for every character
188 */
189 static int
stageoutput(Uart * p)190 stageoutput(Uart *p)
191 {
192 int n;
193 Queue *q = p->oq;
194
195 if(!q)
196 return 0;
197 n = qconsume(q, p->ostage, Stagesize);
198 if(n <= 0)
199 return 0;
200 p->op = p->ostage;
201 p->oe = p->ostage + n;
202 return n;
203 }
204
205 static void
uartxmit(Uart * p)206 uartxmit(Uart *p)
207 {
208 UartReg *reg = p->reg;
209 ulong gag = 1;
210 while(p->op < p->oe || stageoutput(p)) {
211 if(readstatus(p) & USTAT_TBE) {
212 DEBUG("T");
213 reg->txbuf = *(p->op++);
214 p->wcount++;
215 } else {
216 DEBUG("F");
217 gag = 0;
218 break;
219 }
220 }
221 if (gag) {
222 DEBUG("G");
223 p->kickme = 1;
224 intrmask(UARTTXbit(p->port), 0);
225 }
226 }
227
228 static void
uartrecvq(Uart * p)229 uartrecvq(Uart *p)
230 {
231 uchar *cp = p->istage;
232 int n = p->ip - cp;
233
234 if(n == 0)
235 return;
236 if(p->putc)
237 while(n-- > 0)
238 p->putc(p->iq, *cp++);
239 else if(p->iq)
240 if(qproduce(p->iq, p->istage, n) < n)
241 print("qproduce flow control");
242 p->ip = p->istage;
243 }
244
245 static void
uartrecv(Uart * p)246 uartrecv(Uart *p)
247 {
248 UartReg *reg = p->reg;
249 uchar stat = readstatus(p);
250
251 DEBUG("R");
252 if (stat & USTAT_RDR) {
253 int c;
254 c = reg->rxbuf;
255 if (c == '?') {
256 DEBUG("mod 0x%.8lx\n", INTREG->mod);
257 DEBUG("msk 0x%.8lx\n", INTREG->msk);
258 DEBUG("pnd 0x%.8lx\n", INTREG->pnd);
259 }
260 *p->ip++ = c;
261 /* if(p->ip >= p->ie) */
262 uartrecvq(p);
263 p->rcount++;
264 }
265 }
266
267 static void
uartkick(void * a)268 uartkick(void *a)
269 {
270 Uart *p = a;
271 int x = splhi();
272 DEBUG("k");
273 if (p->kickme) {
274 p->kickme = 0;
275 DEBUG("K");
276 intrunmask(UARTTXbit(p->port), 0);
277 }
278 splx(x);
279 }
280
281 /*
282 * UART Interrupt Handler
283 */
284 static void
uarttxintr(Ureg *,void * arg)285 uarttxintr(Ureg*, void* arg)
286 {
287 Uart *p = arg;
288 intrclear(UARTTXbit(p->port), 0);
289 p->inters++;
290 p->winters++;
291 uartxmit(p);
292 }
293
294 static void
uartrxintr(Ureg *,void * arg)295 uartrxintr(Ureg*, void* arg)
296 {
297 Uart *p = arg;
298 intrclear(UARTRXbit(p->port), 0);
299 p->inters++;
300 p->rinters++;
301 uartrecv(p);
302 }
303
304
305 static void
uartsetup(ulong port,char * name)306 uartsetup(ulong port, char *name)
307 {
308 Uart *p;
309
310 if(nuart >= Nuart)
311 return;
312
313 p = xalloc(sizeof(Uart));
314 uart[nuart++] = p;
315 strcpy(p->name, name);
316
317 p->reg = &UARTREG[port];
318 p->bps = 9600;
319 p->bits = 8;
320 p->parity = 'n';
321 p->stop = 1;
322 p->kickme = 0;
323 p->port = port;
324
325 p->iq = qopen(4*1024, 0, 0 , p);
326 p->oq = qopen(4*1024, 0, uartkick, p);
327
328 p->ip = p->istage;
329 p->ie = &p->istage[Stagesize];
330 p->op = p->ostage;
331 p->oe = p->ostage;
332
333 intrenable(UARTTXbit(port), uarttxintr, p, 0);
334 intrenable(UARTRXbit(port), uartrxintr, p, 0);
335 }
336
337 static void
uartinstall(void)338 uartinstall(void)
339 {
340 static int already;
341
342 if(already)
343 return;
344 already = 1;
345
346 uartsetup(0, "eia0");
347 // uartsetup(1, "eia1");
348 }
349
350 /*
351 * called by main() to configure a duart port as a console or a mouse
352 */
353 void
uartspecial(int port,int bps,char parity,Queue ** in,Queue ** out,int (* putc)(Queue *,int))354 uartspecial(int port, int bps, char parity, Queue **in, Queue **out, int (*putc)(Queue*, int))
355 {
356 Uart *p;
357
358 uartinstall();
359 if(port >= nuart)
360 return;
361 p = uart[port];
362 if(bps)
363 p->bps = bps;
364 if(parity)
365 p->parity = parity;
366 uartenable(p);
367 p->putc = putc;
368 if(in)
369 *in = p->iq;
370 if(out)
371 *out = p->oq;
372 p->opens++;
373 }
374
375 Dirtab *uartdir;
376 int ndir;
377
378 static void
setlength(int i)379 setlength(int i)
380 {
381 Uart *p;
382
383 if(i > 0){
384 p = uart[i];
385 if(p && p->opens && p->iq)
386 uartdir[1+3*i].length = qlen(p->iq);
387 } else for(i = 0; i < nuart; i++){
388 p = uart[i];
389 if(p && p->opens && p->iq)
390 uartdir[1+3*i].length = qlen(p->iq);
391 }
392 }
393
394 /*
395 * all uarts must be uartsetup() by this point or inside of uartinstall()
396 */
397 static void
uartreset(void)398 uartreset(void)
399 {
400 int i;
401 Dirtab *dp;
402
403 uartinstall();
404
405 ndir = 1+3*nuart;
406 uartdir = xalloc(ndir * sizeof(Dirtab));
407 dp = uartdir;
408 strcpy(dp->name, ".");
409 mkqid(&dp->qid, 0, 0, QTDIR);
410 dp->length = 0;
411 dp->perm = DMDIR|0555;
412 dp++;
413 for(i = 0; i < nuart; i++){
414 /* 3 directory entries per port */
415 strcpy(dp->name, uart[i]->name);
416 dp->qid.path = NETQID(i, Ndataqid);
417 dp->perm = 0660;
418 dp++;
419 sprint(dp->name, "%sctl", uart[i]->name);
420 dp->qid.path = NETQID(i, Nctlqid);
421 dp->perm = 0660;
422 dp++;
423 sprint(dp->name, "%sstatus", uart[i]->name);
424 dp->qid.path = NETQID(i, Nstatqid);
425 dp->perm = 0444;
426 dp++;
427 }
428 }
429
430 static Chan*
uartattach(char * spec)431 uartattach(char *spec)
432 {
433 return devattach('t', spec);
434 }
435
436 static Walkqid*
uartwalk(Chan * c,Chan * nc,char ** name,int nname)437 uartwalk(Chan *c, Chan *nc, char **name, int nname)
438 {
439 return devwalk(c, nc, name, nname, uartdir, ndir, devgen);
440 }
441
442 static int
uartstat(Chan * c,uchar * dp,int n)443 uartstat(Chan *c, uchar *dp, int n)
444 {
445 if(NETTYPE(c->qid.path) == Ndataqid)
446 setlength(NETID(c->qid.path));
447 return devstat(c, dp, n, uartdir, ndir, devgen);
448 }
449
450 static Chan*
uartopen(Chan * c,int omode)451 uartopen(Chan *c, int omode)
452 {
453 Uart *p;
454
455 c = devopen(c, omode, uartdir, ndir, devgen);
456
457 switch(NETTYPE(c->qid.path)){
458 case Nctlqid:
459 case Ndataqid:
460 p = uart[NETID(c->qid.path)];
461 qlock(p);
462 if(p->opens++ == 0){
463 uartenable(p);
464 qreopen(p->iq);
465 qreopen(p->oq);
466 }
467 qunlock(p);
468 break;
469 }
470
471 return c;
472 }
473
474 static void
uartclose(Chan * c)475 uartclose(Chan *c)
476 {
477 Uart *p;
478
479 if(c->qid.type & QTDIR)
480 return;
481 if((c->flag & COPEN) == 0)
482 return;
483 switch(NETTYPE(c->qid.path)){
484 case Ndataqid:
485 case Nctlqid:
486 p = uart[NETID(c->qid.path)];
487 qlock(p);
488 if(--(p->opens) == 0){
489 uartdisable(p);
490 qclose(p->iq);
491 qclose(p->oq);
492 p->ip = p->istage;
493 }
494 qunlock(p);
495 break;
496 }
497 }
498
499 static long
uartstatus(Chan * c,Uart * p,void * buf,long n,long offset)500 uartstatus(Chan *c, Uart *p, void *buf, long n, long offset)
501 {
502 char str[256];
503 USED(c);
504
505 str[0] = 0;
506 sprint(str, "opens %d ferr %d oerr %d perr %d baud %d parity %c"
507 " intr %d rintr %d wintr %d"
508 " rcount %d wcount %d",
509 p->opens, p->frame, p->overrun, p->perror, p->bps, p->parity,
510 p->inters, p->rinters, p->winters,
511 p->rcount, p->wcount);
512
513 strcat(str, "\n");
514 return readstr(offset, buf, n, str);
515 }
516
517 static long
uartread(Chan * c,void * buf,long n,vlong offset)518 uartread(Chan *c, void *buf, long n, vlong offset)
519 {
520 Uart *p;
521
522 if(c->qid.type & QTDIR){
523 setlength(-1);
524 return devdirread(c, buf, n, uartdir, ndir, devgen);
525 }
526
527 p = uart[NETID(c->qid.path)];
528 switch(NETTYPE(c->qid.path)){
529 case Ndataqid:
530 return qread(p->iq, buf, n);
531 case Nctlqid:
532 return readnum(offset, buf, n, NETID(c->qid.path), NUMSIZE);
533 case Nstatqid:
534 return uartstatus(c, p, buf, n, offset);
535 }
536
537 return 0;
538 }
539
540 static void
uartctl(Uart * p,char * cmd)541 uartctl(Uart *p, char *cmd)
542 {
543 int i, n;
544
545 /* let output drain for a while (up to 4 secs) */
546 for(i = 0; i < 200 && (qlen(p->oq) || (readstatus(p) & USTAT_TC) == 0); i++)
547 tsleep(&up->sleep, return0, 0, 20);
548
549 if(strncmp(cmd, "break", 5) == 0){
550 uartbreak(p, 0);
551 return;
552 }
553
554 n = atoi(cmd+1);
555 switch(*cmd){
556 case 'B':
557 case 'b':
558 if(n <= 0)
559 error(Ebadarg);
560 p->bps = n;
561 uartset(p);
562 break;
563 case 'f':
564 case 'F':
565 qflush(p->oq);
566 break;
567 case 'H':
568 case 'h':
569 qhangup(p->iq, 0);
570 qhangup(p->oq, 0);
571 break;
572 case 'L':
573 case 'l':
574 if(n < 7 || n > 8)
575 error(Ebadarg);
576 p->bits = n;
577 uartset(p);
578 break;
579 case 'n':
580 case 'N':
581 qnoblock(p->oq, n);
582 break;
583 case 'P':
584 case 'p':
585 p->parity = *(cmd+1);
586 uartset(p);
587 break;
588 case 'K':
589 case 'k':
590 uartbreak(p, n);
591 break;
592 case 'Q':
593 case 'q':
594 qsetlimit(p->iq, n);
595 qsetlimit(p->oq, n);
596 break;
597 case 's':
598 case 'S':
599 if(n < 1 || n > 2)
600 error(Ebadarg);
601 p->stop = n;
602 uartset(p);
603 break;
604 }
605 }
606
607 static long
uartwrite(Chan * c,void * buf,long n,vlong offset)608 uartwrite(Chan *c, void *buf, long n, vlong offset)
609 {
610 Uart *p;
611 char cmd[32];
612
613 USED(offset);
614
615 if(c->qid.type & QTDIR)
616 error(Eperm);
617
618 p = uart[NETID(c->qid.path)];
619
620 switch(NETTYPE(c->qid.path)){
621 case Ndataqid:
622 return qwrite(p->oq, buf, n);
623 case Nctlqid:
624
625 if(n >= sizeof(cmd))
626 n = sizeof(cmd)-1;
627 memmove(cmd, buf, n);
628 cmd[n] = 0;
629 uartctl(p, cmd);
630 return n;
631 }
632 }
633
634 static int
uartwstat(Chan * c,uchar * dp,int n)635 uartwstat(Chan *c, uchar *dp, int n)
636 {
637 error(Eperm);
638 return 0;
639 #ifdef xxx
640 Dir d;
641 Dirtab *dt;
642
643 if(!iseve())
644 error(Eperm);
645 if(c->qid.type & QTDIR)
646 error(Eperm);
647 if(NETTYPE(c->qid.path) == Nstatqid)
648 error(Eperm);
649
650 dt = &uartdir[3 * NETID(c->qid.path)];
651 convM2D(dp, &d);
652 d.mode &= 0666;
653 dt[0].perm = dt[1].perm = d.mode;
654 #endif
655 }
656
657 Dev uartdevtab = {
658 't',
659 "uart",
660
661 uartreset,
662 devinit,
663 devshutdown,
664 uartattach,
665 uartwalk,
666 uartstat,
667 uartopen,
668 devcreate,
669 uartclose,
670 uartread,
671 devbread,
672 uartwrite,
673 devbwrite,
674 devremove,
675 uartwstat,
676 };
677
678 void
uartputc(int c)679 uartputc(int c)
680 {
681 UartReg *u;
682
683 if (!c)
684 return;
685 u = &UARTREG[1];
686 while ((u->stat & USTAT_TBE) == 0)
687 ;
688 u->txbuf = c;
689 if (c == '\n')
690 while((u->stat & USTAT_TC) == 0) /* flush xmit fifo */
691 ;
692 }
693
694 void
uartputs(char * data,int len)695 uartputs(char *data, int len)
696 {
697 int x;
698
699 clockpoll();
700 x = splfhi();
701 while (len--){
702 if(*data == '\n')
703 uartputc('\r');
704 uartputc(*data++);
705 }
706 splx(x);
707 }
708
709 int
uartgetc(void)710 uartgetc(void)
711 {
712 UartReg *u;
713
714 clockcheck();
715 u = &UARTREG[1];
716 while((u->stat & USTAT_RDR) == 0)
717 clockcheck();
718 return u->rxbuf;
719 }
720