|
|
1.1 root 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 "ureg.h"
8: #include "../port/error.h"
9:
10: #include "devtab.h"
11:
12: int duartacr;
13: int duartimr;
14: void (*kprofp)(ulong);
15:
16: /*
17: * Register set for half the duart. There are really two sets.
18: */
19: struct Duart{
20: uchar mr1_2; /* Mode Register Channels 1 & 2 */
21: uchar sr_csr; /* Status Register/Clock Select Register */
22: uchar cmnd; /* Command Register */
23: uchar data; /* RX Holding / TX Holding Register */
24: uchar ipc_acr; /* Input Port Change/Aux. Control Register */
25: #define ivr ivr /* Interrupt Vector Register */
26: uchar is_imr; /* Interrupt Status/Interrupt Mask Register */
27: #define ip_opcr is_imr /* Input Port/Output Port Configuration Register */
28: uchar ctur; /* Counter/Timer Upper Register */
29: #define scc_sopbc ctur /* Start Counter Command/Set Output Port Bits Command */
30: uchar ctlr; /* Counter/Timer Lower Register */
31: #define scc_ropbc ctlr /* Stop Counter Command/Reset Output Port Bits Command */
32: };
33:
34: enum{
35: CHAR_ERR =0x00, /* MR1x - Mode Register 1 */
36: PAR_ENB =0x00,
37: EVEN_PAR =0x00,
38: ODD_PAR =0x04,
39: NO_PAR =0x10,
40: CBITS8 =0x03,
41: CBITS7 =0x02,
42: CBITS6 =0x01,
43: CBITS5 =0x00,
44: NORM_OP =0x00, /* MR2x - Mode Register 2 */
45: TWOSTOPB =0x0F,
46: ONESTOPB =0x07,
47: ENB_RX =0x01, /* CRx - Command Register */
48: DIS_RX =0x02,
49: ENB_TX =0x04,
50: DIS_TX =0x08,
51: RESET_MR =0x10,
52: RESET_RCV =0x20,
53: RESET_TRANS =0x30,
54: RESET_ERR =0x40,
55: RESET_BCH =0x50,
56: STRT_BRK =0x60,
57: STOP_BRK =0x70,
58: RCV_RDY =0x01, /* SRx - Channel Status Register */
59: FIFOFULL =0x02,
60: XMT_RDY =0x04,
61: XMT_EMT =0x08,
62: OVR_ERR =0x10,
63: PAR_ERR =0x20,
64: FRM_ERR =0x40,
65: RCVD_BRK =0x80,
66: BD38400 =0xCC|0x0000,
67: BD19200 =0xCC|0x0100,
68: BD9600 =0xBB|0x0000,
69: BD4800 =0x99|0x0000,
70: BD2400 =0x88|0x0000,
71: BD1200 =0x66|0x0000,
72: BD300 =0x44|0x0000,
73: IM_IPC =0x80, /* IMRx/ISRx - Interrupt Mask/Interrupt Status */
74: IM_DBB =0x40,
75: IM_RRDYB =0x20,
76: IM_XRDYB =0x10,
77: IM_CRDY =0x08,
78: IM_DBA =0x04,
79: IM_RRDYA =0x02,
80: IM_XRDYA =0x01,
81: };
82:
83: /*
84: * software info for a serial duart interface
85: */
86: typedef struct Duartport Duartport;
87: struct Duartport
88: {
89: QLock;
90: int printing; /* true if printing */
91:
92: /* console interface */
93: int nostream; /* can't use the stream interface */
94: IOQ *iq; /* input character queue */
95: IOQ *oq; /* output character queue */
96:
97: /* stream interface */
98: Queue *wq; /* write queue */
99: Rendez r; /* kproc waiting for input */
100: int kstarted; /* kproc started */
101: };
102: Duartport duartport[1];
103:
104: uchar keymap[]={
105: /*80*/ 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
106: 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x8e, 0x58,
107: /*90*/ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
108: 0x98, 0x99, 0x9a, 0x9b, 0x58, 0x58, 0x58, 0x58,
109: /*A0*/ 0x58, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
110: 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xae, 0xaf,
111: /*B0*/ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
112: 0xb8, 0xb9, 0x00, 0xbb, 0x1e, 0xbd, 0x60, 0x1f,
113: /*C0*/ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0x58, 0xc6, 0x0a,
114: 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
115: /*D0*/ 0x09, 0x08, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
116: 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x7f, 0x58,
117: /*E0*/ 0x58, 0x58, 0xe2, 0x1b, 0x0d, 0xe5, 0x58, 0x0a,
118: 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
119: /*F0*/ 0x09, 0x08, 0xb2, 0x1b, 0x0d, 0xf5, 0x81, 0x58,
120: 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x7f, 0x80,
121: };
122:
123: void
124: duartinit(void)
125: {
126: Duart *duart;
127: static int already;
128:
129: if(already)
130: return;
131: already = 1;
132:
133: duart = DUARTREG;
134:
135: /*
136: * Keyboard
137: */
138: duart[0].cmnd = RESET_RCV|DIS_TX|DIS_RX;
139: duart[0].cmnd = RESET_TRANS;
140: duart[0].cmnd = RESET_ERR;
141: duart[0].cmnd = RESET_MR;
142: duart[0].mr1_2 = CHAR_ERR|PAR_ENB|EVEN_PAR|CBITS8;
143: duart[0].mr1_2 = NORM_OP|ONESTOPB;
144: duart[0].sr_csr = BD4800;
145:
146: /*
147: * RS232
148: */
149: duart[1].cmnd = RESET_RCV|DIS_TX|DIS_RX;
150: duart[1].cmnd = RESET_TRANS;
151: duart[1].cmnd = RESET_ERR;
152: duart[1].cmnd = RESET_MR;
153: duart[1].mr1_2 = CHAR_ERR|NO_PAR|CBITS8;
154: duart[1].mr1_2 = NORM_OP|ONESTOPB;
155: duart[1].sr_csr = BD9600;
156:
157: /*
158: * Output port
159: */
160: duart[0].ipc_acr = duartacr = 0xB7; /* allow change of state interrupt */
161: duart[1].ip_opcr = 0x00;
162: duart[1].scc_ropbc = 0xFF; /* make sure the port is reset first */
163: duart[1].scc_sopbc = 0x04; /* dtr = 1, pp = 01 */
164: duart[0].is_imr = duartimr = IM_IPC|IM_RRDYB|IM_XRDYB|IM_RRDYA|IM_XRDYA;
165: duart[0].cmnd = ENB_TX|ENB_RX; /* enable TX and RX last */
166: duart[1].cmnd = ENB_TX|ENB_RX;
167:
168: /*
169: * Initialize keyboard
170: */
171: while (!(duart[0].sr_csr & (XMT_EMT|XMT_RDY)))
172: ;
173: duart[0].data = 0x02;
174: }
175:
176:
177: void
178: duartbaud(int b)
179: {
180: int x = 0;
181: Duart *duart = DUARTREG;
182:
183: switch(b){
184: case 38400:
185: x = BD38400;
186: break;
187: case 19200:
188: x = BD19200;
189: break;
190: case 9600:
191: x = BD9600;
192: break;
193: case 4800:
194: x = BD4800;
195: break;
196: case 2400:
197: x = BD2400;
198: break;
199: case 1200:
200: x = BD1200;
201: break;
202: case 300:
203: x = BD300;
204: break;
205: default:
206: error(Ebadarg);
207: }
208: if(x & 0x0100)
209: duart[0].ipc_acr = duartacr |= 0x80;
210: else
211: duart[0].ipc_acr = duartacr &= ~0x80;
212: duart[1].sr_csr = x;
213: }
214:
215: void
216: duartdtr(int val)
217: {
218: Duart *duart = DUARTREG;
219: if (val)
220: duart[1].scc_ropbc=0x01;
221: else
222: duart[1].scc_sopbc=0x01;
223: }
224:
225: void
226: duartbreak(int ms)
227: {
228: static QLock brk;
229: Duart *duart = DUARTREG;
230: if (ms<=0 || ms >20000)
231: error(Ebadarg);
232: qlock(&brk);
233: duart[0].is_imr = duartimr &= ~IM_XRDYB;
234: duart[1].cmnd = STRT_BRK|ENB_TX;
235: tsleep(&u->p->sleep, return0, 0, ms);
236: duart[1].cmnd = STOP_BRK|ENB_TX;
237: duart[0].is_imr = duartimr |= IM_XRDYB;
238: qunlock(&brk);
239: }
240:
241: enum{
242: Kptime=200
243: };
244: void
245: duartstarttimer(void)
246: {
247: Duart *duart;
248: char x;
249:
250: duart = DUARTREG;
251: duart[0].ctur = (Kptime)>>8;
252: duart[0].ctlr = (Kptime)&255;
253: duart[0].is_imr = duartimr |= IM_CRDY;
254: x = duart[1].scc_sopbc;
255: USED(x);
256: }
257:
258: void
259: duartstoptimer(void)
260: {
261: Duart *duart;
262: char x;
263:
264: duart = DUARTREG;
265: x = duart[1].scc_ropbc;
266: USED(x);
267: duart[0].is_imr = duartimr &= ~IM_CRDY;
268: }
269:
270:
271: /*
272: * a serial line input interrupt
273: */
274: void
275: duartrintr(char ch)
276: {
277: IOQ *cq;
278: Duartport *dp = duartport;
279:
280: cq = dp->iq;
281: if(cq->putc)
282: (*cq->putc)(cq, ch);
283: else {
284: putc(cq, ch);
285: }
286: }
287: void
288: duartclock(void)
289: {
290: Duartport *dp = duartport;
291: IOQ *cq;
292:
293: cq = dp->iq;
294: if(cangetc(cq))
295: wakeup(&cq->r);
296: }
297:
298: /*
299: * a serial line output interrupt
300: */
301: void
302: duartxintr(void)
303: {
304: int ch;
305: IOQ *cq;
306: Duartport *dp = duartport;
307: Duart *duart;
308:
309: cq = dp->oq;
310: lock(cq);
311: ch = getc(cq);
312: duart = DUARTREG;
313: if(ch < 0){
314: dp->printing = 0;
315: wakeup(&cq->r);
316: duart[1].cmnd = DIS_TX;
317: } else
318: duart[1].data = ch;
319: unlock(cq);
320: }
321:
322:
323: void
324: duartintr(Ureg *ur)
325: {
326: int cause, status, ch, c, i;
327: Duart *duart;
328: static int collecting, nk;
329: static uchar kc[5];
330:
331: duart = DUARTREG;
332: cause = duart->is_imr;
333: /*
334: * I can guess your interrupt.
335: */
336: /*
337: * Is it 0?
338: */
339: if(cause & IM_CRDY){
340: if(kprofp)
341: (*kprofp)(ur->pc);
342: ch = duart[1].scc_ropbc;
343: USED(ch);
344: duart[0].ctur = (Kptime)>>8;
345: duart[0].ctlr = (Kptime)&255;
346: ch = duart[1].scc_sopbc;
347: USED(ch);
348: return;
349: }
350: /*
351: * Is it 1?
352: */
353: if(cause & IM_RRDYA){ /* keyboard input */
354: status = duart->sr_csr;
355: ch = duart->data;
356: if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
357: duart->cmnd = RESET_ERR;
358: if(status & PAR_ERR) /* control word: caps lock (0x4) or repeat (0x10) */
359: kbdrepeat((ch&0x10) == 0);
360: else{
361: if(ch == 0x7F) /* VIEW key (bizarre) */
362: ch = 0xFF;
363: if(ch == 0xB6) /* NUM PAD */
364: collecting = 1;
365: else{
366: if(ch & 0x80)
367: ch = keymap[ch&0x7F];
368: if(!collecting)
369: kbdputc(&kbdq, ch);
370: else{
371: kc[nk++] = ch;
372: c = latin1(kc, nk);
373: if(c >= -1){ /* otherwise need more keystrokes */
374: if(c != -1) /* valid sequence */
375: kbdputc(&kbdq, c);
376: else /* dump characters */
377: for(i=0; i<nk; i++)
378: kbdputc(&kbdq, kc[i]);
379: nk = 0;
380: collecting = 0;
381: }
382: }
383: }
384: }
385: }
386: /*
387: * Is it 2?
388: */
389: while(cause & IM_RRDYB){ /* duart input */
390: status = duart[1].sr_csr;
391: ch = duart[1].data;
392: if(status & (FRM_ERR|OVR_ERR|PAR_ERR))
393: duart[1].cmnd = RESET_ERR;
394: else
395: duartrintr(ch);
396: cause = duart->is_imr;
397: }
398: /*
399: * Is it 3?
400: */
401: if(cause & IM_XRDYB) /* duart output */
402: duartxintr();
403: /*
404: * Is it 4?
405: */
406: if(cause & IM_XRDYA)
407: duart[0].cmnd = DIS_TX;
408: /*
409: * Is it 5?
410: */
411: if(cause & IM_IPC)
412: mousetrack((~duart[0].ipc_acr) & 7, 0, 0);
413: }
414:
415:
416: /*
417: * Queue n characters for output; if queue is full, we lose characters.
418: * Get the output going if it isn't already.
419: */
420: void
421: duartputs(IOQ *cq, char *s, int n)
422: {
423: int ch, x;
424: Duartport *dp = duartport;
425: Duart *duart;
426:
427: x = splduart();
428: lock(cq);
429: puts(cq, s, n);
430: if(dp->printing == 0){
431: ch = getc(cq);
432: if(ch >= 0){
433: dp->printing = 1;
434: duart = DUARTREG;
435: duart[1].cmnd = ENB_TX;
436: while(!(duart[1].sr_csr & (XMT_RDY|XMT_EMT)))
437: ;
438: duart[1].data = ch;
439: }
440: }
441: unlock(cq);
442: splx(x);
443: }
444:
445: void
446: duartenable(Duartport *dp)
447: {
448: /*
449: * set up i/o routines
450: */
451: if(dp->oq){
452: dp->oq->puts = duartputs;
453: dp->oq->ptr = dp;
454: }
455: if(dp->iq)
456: dp->iq->ptr = dp;
457: }
458:
459: /*
460: * set up an duart port as something other than a stream
461: */
462: void
463: duartspecial(int port, IOQ *oq, IOQ *iq, int baud)
464: {
465: Duartport *dp = &duartport[port];
466:
467: dp->nostream = 1;
468: dp->oq = oq;
469: dp->iq = iq;
470: duartenable(dp);
471: duartbaud(baud);
472: }
473:
474: static int duartputc(IOQ *, int);
475: static void duartstopen(Queue*, Stream*);
476: static void duartstclose(Queue*);
477: static void duartoput(Queue*, Block*);
478: static void duartkproc(void *);
479: Qinfo duartinfo =
480: {
481: nullput,
482: duartoput,
483: duartstopen,
484: duartstclose,
485: "duart"
486: };
487:
488: static void
489: duartstopen(Queue *q, Stream *s)
490: {
491: Duartport *dp;
492: char name[NAMELEN];
493:
494: if(s->id > 0)
495: panic("duartstopen");
496: dp = &duartport[s->id];
497:
498: qlock(dp);
499: dp->wq = WR(q);
500: WR(q)->ptr = dp;
501: RD(q)->ptr = dp;
502: qunlock(dp);
503:
504: if(dp->kstarted == 0){
505: dp->kstarted = 1;
506: sprint(name, "duart%d", s->id);
507: kproc(name, duartkproc, dp);
508: }
509: }
510:
511: static void
512: duartstclose(Queue *q)
513: {
514: Duartport *dp = q->ptr;
515:
516: qlock(dp);
517: dp->wq = 0;
518: dp->iq->putc = 0;
519: WR(q)->ptr = 0;
520: RD(q)->ptr = 0;
521: qunlock(dp);
522: }
523:
524: static void
525: duartoput(Queue *q, Block *bp)
526: {
527: Duartport *dp = q->ptr;
528: IOQ *cq;
529: int n, m;
530:
531: if(dp == 0){
532: freeb(bp);
533: return;
534: }
535: cq = dp->oq;
536: if(waserror()){
537: freeb(bp);
538: nexterror();
539: }
540: if(bp->type == M_CTL){
541: while (cangetc(cq)) /* let output drain */
542: sleep(&cq->r, cangetc, cq);
543: n = strtoul((char *)(bp->rptr+1), 0, 0);
544: switch(*bp->rptr){
545: case 'B':
546: case 'b':
547: duartbaud(n);
548: break;
549: case 'D':
550: case 'd':
551: duartdtr(n);
552: break;
553: case 'K':
554: case 'k':
555: duartbreak(n);
556: break;
557: case 'R':
558: case 'r':
559: /* can't control? */
560: break;
561: case 'W':
562: case 'w':
563: /* obsolete */
564: break;
565: }
566: }else while((m = BLEN(bp)) > 0){
567: while ((n = canputc(cq)) == 0){
568: kprint(" duartoput: sleeping\n");
569: sleep(&cq->r, canputc, cq);
570: }
571: if(n > m)
572: n = m;
573: (*cq->puts)(cq, bp->rptr, n);
574: bp->rptr += n;
575: }
576: poperror();
577: freeb(bp);
578: }
579:
580: /*
581: * process to send bytes upstream for a port
582: */
583: static void
584: duartkproc(void *a)
585: {
586: Duartport *dp = a;
587: IOQ *cq = dp->iq;
588: Block *bp;
589: int n;
590:
591: loop:
592: while ((n = cangetc(cq)) == 0)
593: sleep(&cq->r, cangetc, cq);
594: qlock(dp);
595: if(dp->wq == 0){
596: cq->out = cq->in;
597: }else{
598: bp = allocb(n);
599: bp->flags |= S_DELIM;
600: bp->wptr += gets(cq, bp->wptr, n);
601: PUTNEXT(RD(dp->wq), bp);
602: }
603: qunlock(dp);
604: goto loop;
605: }
606:
607: enum{
608: Qdir= 0,
609: Qeia0= STREAMQID(0, Sdataqid),
610: Qeia0ctl= STREAMQID(0, Sctlqid),
611: };
612:
613: Dirtab duartdir[]={
614: "eia0", {Qeia0}, 0, 0666,
615: "eia0ctl", {Qeia0ctl}, 0, 0666,
616: };
617:
618: #define NDuartport (sizeof duartdir/sizeof(Dirtab))
619:
620: /*
621: * allocate the queues if no one else has
622: */
623: void
624: duartreset(void)
625: {
626: Duartport *dp = duartport;
627:
628: if(dp->nostream)
629: return;
630: dp->iq = xalloc(sizeof(IOQ));
631: initq(dp->iq);
632: dp->oq = xalloc(sizeof(IOQ));
633: initq(dp->oq);
634: duartenable(dp);
635: }
636:
637: Chan*
638: duartattach(char *spec)
639: {
640: return devattach('t', spec);
641: }
642:
643: Chan*
644: duartclone(Chan *c, Chan *nc)
645: {
646: return devclone(c, nc);
647: }
648:
649: int
650: duartwalk(Chan *c, char *name)
651: {
652: return devwalk(c, name, duartdir, NDuartport, devgen);
653: }
654:
655: void
656: duartstat(Chan *c, char *dp)
657: {
658: switch(c->qid.path){
659: case Qeia0:
660: streamstat(c, dp, duartdir[0].name, duartdir[0].perm);
661: break;
662: default:
663: devstat(c, dp, duartdir, NDuartport, devgen);
664: break;
665: }
666: }
667:
668: Chan*
669: duartopen(Chan *c, int omode)
670: {
671: Duartport *dp;
672:
673: switch(c->qid.path){
674: case Qeia0:
675: case Qeia0ctl:
676: dp = &duartport[0];
677: break;
678: default:
679: dp = 0;
680: break;
681: }
682:
683: if(dp && dp->nostream)
684: error(Einuse);
685:
686: if((c->qid.path & CHDIR) == 0)
687: streamopen(c, &duartinfo);
688: return devopen(c, omode, duartdir, NDuartport, devgen);
689: }
690:
691: void
692: duartcreate(Chan *c, char *name, int omode, ulong perm)
693: {
694: USED(c, name, omode, perm);
695: error(Eperm);
696: }
697:
698: void
699: duartclose(Chan *c)
700: {
701: if(c->stream)
702: streamclose(c);
703: }
704:
705: long
706: duartread(Chan *c, void *buf, long n, ulong offset)
707: {
708: int s;
709: Duart *duart = DUARTREG;
710:
711: switch(c->qid.path&~CHDIR){
712: case Qdir:
713: return devdirread(c, buf, n, duartdir, NDuartport, devgen);
714: case Qeia0ctl:
715: if(offset)
716: return 0;
717: s = splhi();
718: *(uchar *)buf = duart[1].ip_opcr;
719: splx(s);
720: return 1;
721: }
722: return streamread(c, buf, n);
723: }
724:
725: long
726: duartwrite(Chan *c, void *va, long n, ulong offset)
727: {
728: USED(offset);
729: return streamwrite(c, va, n, 0);
730: }
731:
732: void
733: duartremove(Chan *c)
734: {
735: USED(c);
736: error(Eperm);
737: }
738:
739: void
740: duartwstat(Chan *c, char *dp)
741: {
742: USED(c, dp);
743: error(Eperm);
744: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.