|
|
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 "../port/error.h"
8:
9: #include "devtab.h"
10:
11: /*
12: * Driver for the Z8530.
13: */
14: enum
15: {
16: /* wr 0 */
17: ResExtPend= 2<<3,
18: ResTxPend= 5<<3,
19: ResErr= 6<<3,
20:
21: /* wr 1 */
22: ExtIntEna= 1<<0,
23: TxIntEna= 1<<1,
24: RxIntDis= 0<<3,
25: RxIntFirstEna= 1<<3,
26: RxIntAllEna= 2<<3,
27:
28: /* wr 3 */
29: RxEna= 1,
30: Rx5bits= 0<<6,
31: Rx7bits= 1<<6,
32: Rx6bits= 2<<6,
33: Rx8bits= 3<<6,
34: Rxbitmask= 3<<6,
35:
36: /* wr 4 */
37: ParEven= 3<<0,
38: ParOdd= 1<<0,
39: ParOff= 0<<0,
40: ParMask= 3<<0,
41: SyncMode= 0<<2,
42: Rx1stop= 1<<2,
43: Rx1hstop= 2<<2,
44: Rx2stop= 3<<2,
45: X16= 1<<6,
46:
47: /* wr 5 */
48: TxRTS= 1<<1,
49: TxEna= 1<<3,
50: TxBreak= 1<<4,
51: TxDTR= 1<<7,
52: Tx5bits= 0<<5,
53: Tx7bits= 1<<5,
54: Tx6bits= 2<<5,
55: Tx8bits= 3<<5,
56: Txbitmask= 3<<5,
57:
58: /* wr 9 */
59: IntEna= 1<<3,
60: ResetB= 1<<6,
61: ResetA= 2<<6,
62: HardReset= 3<<6,
63:
64: /* wr 11 */
65: TRxCOutBR= 2,
66: TxClockTRxC= 1<<3,
67: TxClockBR= 2<<3,
68: RxClockTRxC= 1<<5,
69: RxClockBR= 2<<5,
70: TRxCOI= 1<<2,
71:
72: /* wr 14 */
73: BREna= 1,
74: BRSource= 2,
75:
76: /* rr 0 */
77: RxReady= 1,
78: TxReady= 1<<2,
79: RxDCD= 1<<3,
80: RxCTS= 1<<5,
81: RxBreak= 1<<7,
82:
83: /* rr 3 */
84: ExtPendB= 1,
85: TxPendB= 1<<1,
86: RxPendB= 1<<2,
87: ExtPendA= 1<<3,
88: TxPendA= 1<<4,
89: RxPendA= 1<<5,
90: };
91:
92: typedef struct SCC SCC;
93: struct SCC
94: {
95: QLock;
96: ushort sticky[16]; /* sticky write register values */
97: uchar* ptr; /* command/pointer register in Z8530 */
98: uchar* data; /* data register in Z8530 */
99: int printing; /* true if printing */
100: ulong freq; /* clock frequency */
101: uchar mask; /* bits/char */
102:
103: /* console interface */
104: int special; /* can't use the stream interface */
105: IOQ* iq; /* input character queue */
106: IOQ* oq; /* output character queue */
107:
108: /* stream interface */
109: Queue* wq; /* write queue */
110: Rendez r; /* kproc waiting for input */
111: int kstarted; /* kproc started */
112:
113: /* idiot flow control */
114: int xonoff; /* true if we obey this tradition */
115: int blocked; /* abstinence */
116: };
117:
118: int invrtsdtr; /* set to 1 on indigo's */
119: int nscc;
120: SCC *scc[8]; /* up to 4 8530's */
121: #define CTLS 023
122: #define CTLQ 021
123:
124: #ifdef Zduart
125: #define SCCTYPE 'z'
126: #define onepointseven()
127: #else
128: #define SCCTYPE 't'
129: void
130: onepointseven(void)
131: {
132: int i;
133: for(i = 0; i < 20; i++)
134: ;
135: }
136: #endif
137:
138: /*
139: * Access registers using the pointer in register 0.
140: * This is a bit stupid when accessing register 0.
141: */
142: void
143: sccwrreg(SCC *sp, int addr, int value)
144: {
145: onepointseven();
146: *sp->ptr = addr;
147: wbflush();
148: onepointseven();
149: *sp->ptr = sp->sticky[addr] | value;
150: wbflush();
151: }
152: ushort
153: sccrdreg(SCC *sp, int addr)
154: {
155: onepointseven();
156: *sp->ptr = addr;
157: wbflush();
158: onepointseven();
159: return *sp->ptr;
160: }
161:
162: /*
163: * set the baud rate by calculating and setting the baudrate
164: * generator constant. This will work with fairly non-standard
165: * baud rates.
166: */
167: void
168: sccsetbaud(SCC *sp, int rate)
169: {
170: int brconst;
171:
172: if(rate == 0)
173: error(Ebadctl);
174:
175: brconst = (sp->freq+16*rate-1)/(2*16*rate) - 2;
176:
177: sccwrreg(sp, 12, brconst & 0xff);
178: sccwrreg(sp, 13, (brconst>>8) & 0xff);
179: }
180:
181: void
182: sccparity(SCC *sp, char type)
183: {
184: int val;
185:
186: switch(type){
187: case 'e':
188: val = ParEven;
189: break;
190: case 'o':
191: val = ParOdd;
192: break;
193: default:
194: val = ParOff;
195: break;
196: }
197: sp->sticky[4] = (sp->sticky[4] & ~ParMask) | val;
198: sccwrreg(sp, 4, 0);
199: }
200:
201: /*
202: * set bits/character, default 8
203: */
204: void
205: sccbits(SCC *sp, int n)
206: {
207: int rbits, tbits;
208:
209: switch(n){
210: case 5:
211: sp->mask = 0x1f;
212: rbits = Rx5bits;
213: tbits = Tx5bits;
214: break;
215: case 6:
216: sp->mask = 0x3f;
217: rbits = Rx6bits;
218: tbits = Tx6bits;
219: break;
220: case 7:
221: sp->mask = 0x7f;
222: rbits = Rx7bits;
223: tbits = Tx7bits;
224: break;
225: case 8:
226: default:
227: sp->mask = 0xff;
228: rbits = Rx8bits;
229: tbits = Tx8bits;
230: break;
231: }
232: sp->sticky[3] = (sp->sticky[3]&~Rxbitmask) | rbits;
233: sccwrreg(sp, 3, 0);
234: sp->sticky[5] = (sp->sticky[5]&~Txbitmask) | tbits;
235: sccwrreg(sp, 5, 0);
236: }
237:
238: /*
239: * set/clear external clock mode; the indigo uses the CTS pin,
240: * so we disable external interrupts.
241: */
242: void
243: sccextclk(SCC *sp, int n)
244: {
245: if(n){
246: sp->sticky[1] &= ~ExtIntEna;
247: sp->sticky[11] = TxClockTRxC | RxClockTRxC;
248: }else{
249: sp->sticky[1] |= ExtIntEna;
250: sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR;
251: }
252: sccwrreg(sp, 1, 0);
253: sccwrreg(sp, 11, 0);
254: }
255:
256: /*
257: * toggle DTR
258: */
259: void
260: sccdtr(SCC *sp, int n)
261: {
262: if((n!=0)^invrtsdtr)
263: sp->sticky[5] |= TxDTR;
264: else
265: sp->sticky[5] &=~TxDTR;
266: sccwrreg(sp, 5, 0);
267: }
268:
269: /*
270: * toggle RTS
271: */
272: void
273: sccrts(SCC *sp, int n)
274: {
275: if((n!=0)^invrtsdtr)
276: sp->sticky[5] |= TxRTS;
277: else
278: sp->sticky[5] &=~TxRTS;
279: sccwrreg(sp, 5, 0);
280: }
281:
282: /*
283: * send break
284: */
285: void
286: sccbreak(SCC *sp, int ms)
287: {
288: if(ms == 0)
289: ms = 100;
290: sp->sticky[1] &=~TxIntEna;
291: sccwrreg(sp, 1, 0);
292: sccwrreg(sp, 5, TxBreak|TxEna);
293: tsleep(&u->p->sleep, return0, 0, ms);
294: sccwrreg(sp, 5, 0);
295: if(sp->oq){
296: sp->sticky[1] |= TxIntEna;
297: sccwrreg(sp, 1, 0);
298: }
299: }
300:
301: /*
302: * set number of stop bits
303: */
304: void
305: sccnstop(SCC *sp, char code)
306: {
307: sp->sticky[4] &=~Rx2stop;
308: switch(code){
309: default:
310: sp->sticky[4] |= Rx1stop;
311: break;
312: case 'h':
313: sp->sticky[4] |= Rx1hstop;
314: break;
315: case '2':
316: sp->sticky[4] |= Rx2stop;
317: break;
318: }
319: sccwrreg(sp, 4, 0);
320: }
321:
322: /*
323: * default is 9600 baud, 1 stop bit, 8 bit chars, no interrupts,
324: * transmit and receive enabled, interrupts disabled.
325: */
326: static void
327: sccsetup0(SCC *sp, int brsource)
328: {
329: memset(sp->sticky, 0, sizeof(sp->sticky));
330:
331: /*
332: * turn on baud rate generator and set rate to 9600 baud.
333: * use 1 stop bit.
334: */
335: sp->sticky[14] = brsource ? BRSource : 0;
336: sccwrreg(sp, 14, 0);
337: sccsetbaud(sp, 9600);
338: sp->sticky[4] = Rx1stop | X16;
339: sccwrreg(sp, 4, 0);
340: sp->sticky[11] = TxClockBR | RxClockBR | TRxCOutBR /*| TRxCOI*/;
341: sccwrreg(sp, 11, 0);
342: sp->sticky[14] = BREna;
343: if(brsource)
344: sp->sticky[14] |= BRSource;
345: sccwrreg(sp, 14, 0);
346:
347: /*
348: * enable I/O, 8 bits/character
349: */
350: sp->sticky[3] = RxEna | Rx8bits;
351: sccwrreg(sp, 3, 0);
352: sp->sticky[5] = TxEna | Tx8bits;
353: sccwrreg(sp, 5, 0);
354: sp->mask = 0xff;
355: }
356:
357: void
358: sccsetup(void *addr, ulong freq, int brsource)
359: {
360: SCCdev *dev;
361: SCC *sp;
362:
363: dev = addr;
364:
365: /*
366: * allocate a structure, set port addresses, and setup the line
367: */
368: sp = xalloc(sizeof(SCC));
369: scc[nscc] = sp;
370: sp->ptr = &dev->ptra;
371: sp->data = &dev->dataa;
372: sp->freq = freq;
373: sccsetup0(sp, brsource);
374: sp = xalloc(sizeof(SCC));
375: scc[nscc+1] = sp;
376: sp->ptr = &dev->ptrb;
377: sp->data = &dev->datab;
378: sp->freq = freq;
379: sccsetup0(sp, brsource);
380: nscc += 2;
381: }
382:
383: void
384: sccputc(int port, char ch)
385: {
386: SCC *sp;
387:
388: sp = scc[port];
389: for(;;) {
390: onepointseven();
391: if(*sp->ptr & TxReady)
392: break;
393: }
394: onepointseven();
395: *sp->data = ch;
396: }
397:
398: int
399: iprint(char *fmt, ...)
400: {
401: int n, i;
402: char buf[512];
403:
404: n = doprint(buf, buf+sizeof(buf), fmt, (&fmt+1)) - buf;
405: for(i = 0; i < n; i++)
406: sccputc(1, buf[i]);
407: return n;
408: }
409:
410: /*
411: * Queue n characters for output; if queue is full, we lose characters.
412: * Get the output going if it isn't already.
413: */
414: void
415: sccputs(IOQ *cq, char *s, int n)
416: {
417: SCC *sp = cq->ptr;
418: int ch, x;
419:
420: x = splhi();
421: lock(cq);
422: puts(cq, s, n);
423: if(sp->printing == 0 && sp->blocked==0){
424: ch = getc(cq);
425: /*kprint("<start %2.2ux>", ch);*/
426: if(ch >= 0){
427: sp->printing = 1;
428: while((*sp->ptr&TxReady)==0)
429: ;
430: *sp->data = ch;
431: }
432: }
433: unlock(cq);
434: splx(x);
435: }
436:
437: /*
438: * an scc interrupt (a damn lot of work for one character)
439: */
440: void
441: sccintr0(SCC *sp, uchar x)
442: {
443: int ch;
444: IOQ *cq;
445:
446: if(x & ExtPendB){
447: sccwrreg(sp, 0, ResExtPend);
448: }
449: if(x & RxPendB){
450: cq = sp->iq;
451: while(*sp->ptr&RxReady){
452: onepointseven();
453: ch = *sp->data & sp->mask;
454: if (ch == CTLS && sp->xonoff)
455: sp->blocked = 1;
456: else if (ch == CTLQ && sp->xonoff) {
457: sp->blocked = 0;
458: sccputs(sp->oq, "", 0);
459: }
460: if(cq->putc)
461: (*cq->putc)(cq, ch);
462: else
463: putc(cq, ch);
464: }
465: }
466: if(x & TxPendB){
467: if (sp->blocked) {
468: sccwrreg(sp, 0, ResTxPend);
469: sp->printing = 0;
470: return;
471: }
472: cq = sp->oq;
473: lock(cq);
474: ch = getc(cq);
475: onepointseven();
476: if(ch < 0){
477: sccwrreg(sp, 0, ResTxPend);
478: sp->printing = 0;
479: wakeup(&cq->r);
480: }else
481: *sp->data = ch;
482: unlock(cq);
483: }
484: }
485:
486: int
487: sccintr(void)
488: {
489: uchar x;
490: int i, j;
491:
492: for(i = j = 0; i < nscc; i += 2){
493: x = sccrdreg(scc[i], 3);
494: if(x & (ExtPendB|RxPendB|TxPendB))
495: ++j, sccintr0(scc[i+1], x);
496: x = x >> 3;
497: if(x & (ExtPendB|RxPendB|TxPendB))
498: ++j, sccintr0(scc[i], x);
499: }
500: return j;
501: }
502:
503: void
504: sccclock(void)
505: {
506: SCC *sp;
507: IOQ *cq;
508: int i;
509:
510: for(i = 0; i < nscc; i++){
511: sp = scc[i];
512: cq = sp->iq;
513: if(sp->wq && cangetc(cq))
514: wakeup(&cq->r);
515: }
516: }
517:
518: /*
519: * turn on a port's interrupts. set DTR and RTS
520: */
521: void
522: sccenable(SCC *sp)
523: {
524: /*
525: * set up i/o routines
526: */
527: if(sp->oq){
528: sp->oq->puts = sccputs;
529: sp->oq->ptr = sp;
530: sp->sticky[1] |= TxIntEna | ExtIntEna;
531: }
532: if(sp->iq){
533: sp->iq->ptr = sp;
534: sp->sticky[1] |= RxIntAllEna | ExtIntEna;
535: }
536:
537: /*
538: * turn on interrupts
539: */
540: sccwrreg(sp, 1, 0);
541: sp->sticky[9] |= IntEna;
542: sccwrreg(sp, 9, 0);
543:
544: /*
545: * turn on DTR and RTS
546: */
547: sccdtr(sp, 1);
548: sccrts(sp, 1);
549: }
550:
551: /*
552: * set up an scc port as something other than a stream
553: */
554: void
555: sccspecial(int port, IOQ *oq, IOQ *iq, int baud)
556: {
557: SCC *sp = scc[port];
558:
559: /* let output drain */
560: if(sp->oq){
561: while(cangetc(sp->oq))
562: sleep(&sp->oq->r, cangetc, sp->oq);
563: tsleep(&sp->oq->r, cangetc, sp->oq, 50);
564: }
565:
566: sp->special = 1;
567: sp->oq = oq;
568: sp->iq = iq;
569: sccenable(sp);
570: if(baud)
571: sccsetbaud(sp, baud);
572:
573: if(iq){
574: /*
575: * Stupid HACK to undo a stupid hack
576: */
577: if(iq == &kbdq)
578: kbdq.putc = kbdcr2nl;
579: }
580: }
581:
582: void
583: sccrawput(int port, int c)
584: {
585: SCC *sp = scc[port];
586:
587: if(c == '\n') {
588: sccrawput(port, '\r');
589: delay(100);
590: }
591:
592: while((*sp->ptr&TxReady)==0)
593: ;
594: *sp->data = c;
595: }
596:
597: static void sccstopen(Queue*, Stream*);
598: static void sccstclose(Queue*);
599: static void sccoput(Queue*, Block*);
600: static void scckproc(void *);
601: Qinfo sccinfo =
602: {
603: nullput,
604: sccoput,
605: sccstopen,
606: sccstclose,
607: "scc"
608: };
609:
610: static void
611: sccstopen(Queue *q, Stream *s)
612: {
613: SCC *sp;
614: char name[NAMELEN];
615:
616: kprint("sccstopen: q=0x%ux, inuse=%d, type=%d, dev=%d, id=%d\n",
617: q, s->inuse, s->type, s->dev, s->id);
618: sp = scc[s->id];
619: qlock(sp);
620: sp->wq = WR(q);
621: WR(q)->ptr = sp;
622: RD(q)->ptr = sp;
623: qunlock(sp);
624:
625: if(sp->kstarted == 0){
626: sp->kstarted = 1;
627: sprint(name, "scc%d", s->id);
628: kproc(name, scckproc, sp);
629: }
630: }
631:
632: static void
633: sccstclose(Queue *q)
634: {
635: SCC *sp = q->ptr;
636:
637: if(sp->special)
638: return;
639:
640: qlock(sp);
641: sp->wq = 0;
642: sp->iq->putc = 0;
643: WR(q)->ptr = 0;
644: RD(q)->ptr = 0;
645: qunlock(sp);
646: }
647:
648: static void
649: sccoput(Queue *q, Block *bp)
650: {
651: SCC *sp = q->ptr;
652: IOQ *cq;
653: int n, m;
654:
655: if(sp == 0){
656: freeb(bp);
657: return;
658: }
659: cq = sp->oq;
660: if(waserror()){
661: freeb(bp);
662: nexterror();
663: }
664: if(bp->type == M_CTL){
665: if(*bp->rptr == '!') /* do it now! */
666: ++bp->rptr;
667: else while(cangetc(cq)) /* else let output drain */
668: sleep(&cq->r, cangetc, cq);
669: n = strtoul((char *)(bp->rptr+1), 0, 0);
670: switch(*bp->rptr){
671: case 'B':
672: case 'b':
673: if(BLEN(bp)>4 && strncmp((char*)(bp->rptr+1), "reak", 4) == 0)
674: sccbreak(sp, 0);
675: else
676: sccsetbaud(sp, n);
677: break;
678: case 'C':
679: case 'c':
680: sccextclk(sp, n);
681: break;
682: case 'D':
683: case 'd':
684: sccdtr(sp, n);
685: break;
686: case 'L':
687: case 'l':
688: sccbits(sp, n);
689: break;
690:
691: case 'P':
692: case 'p':
693: sccparity(sp, *(bp->rptr+1));
694: break;
695: case 'K':
696: case 'k':
697: sccbreak(sp, n);
698: break;
699: case 'R':
700: case 'r':
701: sccrts(sp, n);
702: break;
703: case 'S':
704: case 's':
705: sccnstop(sp, *(bp->rptr+1));
706: break;
707: case 'W':
708: case 'w':
709: /* obsolete */
710: break;
711: case 'X':
712: case 'x':
713: sp->xonoff = n;
714: break;
715: }
716: }else while((m = BLEN(bp)) > 0){
717: while ((n = canputc(cq)) == 0){
718: kprint(" sccoput: sleeping\n");
719: sleep(&cq->r, canputc, cq);
720: }
721: if(n > m)
722: n = m;
723: (*cq->puts)(cq, bp->rptr, n);
724: bp->rptr += n;
725: }
726: freeb(bp);
727: poperror();
728: }
729:
730: /*
731: * process to send bytes upstream for a port
732: */
733: static void
734: scckproc(void *a)
735: {
736: SCC *sp = a;
737: IOQ *cq = sp->iq;
738: Block *bp;
739: int n;
740:
741: loop:
742: while ((n = cangetc(cq)) == 0)
743: sleep(&cq->r, cangetc, cq);
744: /*kprint(" scckproc: %d\n", n);*/
745: qlock(sp);
746: if(sp->wq == 0){
747: cq->out = cq->in;
748: }else{
749: bp = allocb(n);
750: bp->flags |= S_DELIM;
751: bp->wptr += gets(cq, bp->wptr, n);
752: PUTNEXT(RD(sp->wq), bp);
753: }
754: qunlock(sp);
755: goto loop;
756: }
757:
758: Dirtab *sccdir;
759:
760: /*
761: * create 2 directory entries for each 'sccsetup' ports.
762: * allocate the queues if no one else has.
763: */
764: void
765: sccreset(void)
766: {
767: SCC *sp;
768: int i;
769: Dirtab *dp;
770:
771: sccdir = xalloc(2 * nscc * sizeof(Dirtab));
772: dp = sccdir;
773: for(i = 0; i < nscc; i++){
774: /* 2 directory entries per port */
775: sprint(dp->name, "eia%d", i);
776: dp->qid.path = STREAMQID(i, Sdataqid);
777: dp->perm = 0666;
778: dp++;
779: sprint(dp->name, "eia%dctl", i);
780: dp->qid.path = STREAMQID(i, Sctlqid);
781: dp->perm = 0666;
782: dp++;
783:
784: /* set up queues if a stream port */
785: sp = scc[i];
786: if(sp->special)
787: continue;
788: sp->iq = xalloc(sizeof(IOQ));
789: initq(sp->iq);
790: sp->oq = xalloc(sizeof(IOQ));
791: initq(sp->oq);
792: sccenable(sp);
793: }
794: }
795:
796: void
797: sccinit(void)
798: {
799: }
800:
801: Chan*
802: sccattach(char *spec)
803: {
804: return devattach(SCCTYPE, spec);
805: }
806:
807: Chan*
808: sccclone(Chan *c, Chan *nc)
809: {
810: return devclone(c, nc);
811: }
812:
813: int
814: sccwalk(Chan *c, char *name)
815: {
816: return devwalk(c, name, sccdir, 2*nscc, devgen);
817: }
818:
819: void
820: sccstat(Chan *c, char *dp)
821: {
822: int i;
823:
824: i = STREAMID(c->qid.path);
825: switch(STREAMTYPE(c->qid.path)){
826: case Sdataqid:
827: streamstat(c, dp, sccdir[2*i].name, sccdir[2*i].perm);
828: break;
829: default:
830: devstat(c, dp, sccdir, 2*nscc, devgen);
831: break;
832: }
833: }
834:
835: Chan*
836: sccopen(Chan *c, int omode)
837: {
838: SCC *sp;
839:
840: if(c->qid.path != CHDIR){
841: sp = scc[STREAMID(c->qid.path)];
842: if(sp->special)
843: error(Einuse);
844: streamopen(c, &sccinfo);
845: }
846: return devopen(c, omode, sccdir, 2*nscc, devgen);
847: }
848:
849: void
850: scccreate(Chan *c, char *name, int omode, ulong perm)
851: {
852: USED(c, name, omode, perm);
853: error(Eperm);
854: }
855:
856: void
857: sccclose(Chan *c)
858: {
859: if(c->stream)
860: streamclose(c);
861: }
862:
863: long
864: sccread(Chan *c, void *buf, long n, ulong offset)
865: {
866: char b[8];
867:
868: if(c->qid.path == CHDIR)
869: return devdirread(c, buf, n, sccdir, 2*nscc, devgen);
870:
871: switch(STREAMTYPE(c->qid.path)){
872: case Sdataqid:
873: return streamread(c, buf, n);
874: case Sctlqid:
875: sprint(b, "%d", STREAMID(c->qid.path));
876: return readstr(offset, buf, n, b);
877: }
878: error(Egreg);
879: return 0; /* not reached */
880: }
881:
882: long
883: sccwrite(Chan *c, void *va, long n, ulong offset)
884: {
885: USED(offset);
886: return streamwrite(c, va, n, 0);
887: }
888:
889: void
890: sccremove(Chan *c)
891: {
892: USED(c);
893: error(Eperm);
894: }
895:
896: void
897: sccwstat(Chan *c, char *dp)
898: {
899: USED(c, dp);
900: error(Eperm);
901: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.