|
|
1.1 root 1: /*
2: * DHV11 driver for Ninth Edition UNIX
3: * by Andrew Hume (loosely based on dh driver from toronto)
4: */
5:
6: #include "sys/param.h"
7: #include "sys/systm.h"
8: #include "sys/stream.h"
9: #include "sys/ttyio.h"
10: #include "sys/ubaddr.h"
11: #include "sys/conf.h"
12: #include "sys/dhv11.h"
13:
14: #define NPER 8 /* lines per board */
15:
16: /* bits in dhv[]->state */
17: #define ISOPEN 0x0002
18: #define WOPEN 0x0004
19: #define TIMEOUT 0x0008
20: #define CARRIER 0x0010
21: #define DHSTOP 0x0020
22: #define HPCL 0x0040
23: #define BRKING 0x0080
24: #define BUSY 0x0100
25: #define FLUSH 0x0200
26:
27: #define SSPEED B9600 /* reasonable default nowadays */
28: #define DHPRI 30
29:
30: /* hardware structure */
31: struct dhvreg
32: {
33: unsigned short csr;
34: short rbuf; /* coincides with txchar (not used) */
35: unsigned short lpr; /* line param */
36: unsigned short lstat; /* line status */
37: unsigned short lctl; /* line control */
38: unsigned short addr1;
39: unsigned short addr2;
40: unsigned short cnt;
41: };
42:
43: struct hilo /* for utterly wretched appalling hardware */
44: {
45: char low;
46: char high;
47: };
48: #define LOW(ptr) ((struct hilo *)&(ptr))->low
49: #define HIGH(ptr) ((struct hilo *)&(ptr))->high
50:
51: /* csr bits */
52: #define TXACT 0x8000
53: #define TXIE 0x4000
54: #define DIAGFAIL 0x2000
55: #define TXERR 0x1000
56: #define TXLINE(csr) (((csr)>>8)&0xF)
57: #define RXAVAIL 0x0080
58: #define RXIE 0x0040
59: #define MRESET 0x0020
60: #define POINT(r, l) LOW((r)->csr) = (((l)&0xF) | RXIE)
61:
62: /* rbuf */
63: #define VALID 0x8000
64: #define OERR 0x4000
65: #define FERR 0x2000
66: #define PERR 0x1000
67: #define LINE(rbuf) (((rbuf)>>8)&0xF)
68: #define ISMODEM(rbuf) (((rbuf)&0x7000)==0x7000)
69: #define DCD 0x10 /* note that it is shifted left 8 bits in lstat */
70:
71: /* lpr bits */
72: #define BITS5 0x00
73: #define BITS6 0x08
74: #define BITS7 0x10
75: #define BITS8 0x18
76: #define PENAB 0x20
77: #define EPARITY 0x40
78: #define STOP2 0x80
79:
80: /* lctl bits */
81: #define TXABORT 0x0001
82: #define RXENABLE 0x0004
83: #define BREAK 0x0008
84: #define MODEM 0x0100
85: #define DTR 0x0200
86: #define RTS 0x1000
87:
88: /* addr2 */
89: #define TXEN 0x8000
90: #define TXSTART 0x0080
91:
92: #define RESETSECS 5 /* seconds to wait for master reset */
93: #define RESETJUNK 8 /* number of bytes reset puts in the fifo */
94: #define RSDIAG 0200 /* some sort of diag message */
95: #define RSNULL 0201 /* ok self-test status */
96: #define RSSKIP 0203 /* self-test skipped */
97:
98: char dhvsp[16] =
99: {
100: 0, 0, 1, 2, 3, 4 ,0, 5, 6, 7, 8, 10, 11, 13, 14, 0
101: };
102:
103: /*
104: * interface with i/o system
105: */
106: long dhvopen();
107: int dhvclose(), dhvoput();
108: static struct qinit dhvrinit = { noput, NULL, dhvopen, dhvclose, 0, 0 };
109: static struct qinit dhvwinit = { dhvoput, NULL, dhvopen, dhvclose, 200, 100 };
110: static struct streamtab dhvinfo = { &dhvrinit, &dhvwinit };
111: struct cdevsw dhvcdev = cstrinit(&dhvinfo);
112:
113: extern struct ubaddr dhvaddr[];
114: extern struct dhv dhv[];
115: extern int dhvcnt;
116:
117: /*
118: * misc private data
119: */
120: int dhvoverrun;
121: int dhvmiss; /* chars lost due to q full */
122:
123: /*
124: use tsleep so user can interrupt without wrecking accounting
125: */
126: long
127: dhvopen(q, d)
128: register struct queue *q;
129: dev_t d;
130: {
131: register int dev;
132: register struct dhv *dhvp;
133: register int s;
134:
135: dev = minor(d);
136: if(dev >= dhvcnt)
137: return(0);
138: dhvp = &dhv[dev];
139: q->ptr = (caddr_t)dhvp;
140: WR(q)->ptr = (caddr_t)dhvp;
141: /*
142: If this is first open, initialise tty state to default.
143: */
144: if(((dhvp->state&ISOPEN)==0) || ((dhvp->state&CARRIER)==0)){
145: if (dhvinit(dev) == 0) /* reset the hardware */
146: return(0);
147: dhvp->flags = ODDP|EPARITY;
148: dhvp->ispeed = dhvp->ospeed = SSPEED;
149: dhvp->lctl = MODEM|DTR|RTS|RXENABLE;
150: dhvp->state = 0;
151: s = spl5();
152: dhvparam(dhvp);
153: while(!(dhvp->state & CARRIER))
154: if(tsleep((caddr_t)dhvp, DHPRI, 0) != TS_OK){
155: splx(s);
156: return(0);
157: }
158: dhvp->rdq = q;
159: dhvp->oblock = 0;
160: dhvp->state |= ISOPEN;
161: splx(s);
162: }
163: return 1;
164: }
165:
166: /*
167: * reset the DHV hardware
168: * -- be sure address is correct for first line of board
169: */
170: dhvinit(dev)
171: int dev;
172: {
173: register struct dhvreg *regs;
174: register struct ubaddr *ap;
175: register int bd, i, c;
176: int s, bad;
177:
178: bd = dev / NPER;
179: ap = &dhvaddr[bd];
180: bd *= NPER; /* first line of this board */
181: if (dhv[bd].regs) {
182: dhv[dev].regs = dhv[bd].regs;
183: dhv[dev].adno = ap->ubno;
184: dhv[dev].line = dev%NPER;
185: return (1); /* already set up */
186: }
187: if ((regs = (struct dhvreg *)ubaddr(ap)) == 0
188: || ubbadaddr(ap->ubno, ®s->csr, sizeof(short))) {
189: printf("dhv11 %d absent\n", bd/NPER);
190: return (0);
191: }
192: s = spl5();
193: regs->csr = MRESET;
194: for (i = 0; i < RESETSECS; i++) {
195: sleep((caddr_t)&lbolt, PZERO);
196: if ((regs->csr & MRESET) == 0)
197: break;
198: }
199: splx(s);
200: if (regs->csr & (MRESET|DIAGFAIL)) {
201: printf("dhv11 %d: bad reset: csr %o\n", bd/NPER, regs->csr);
202: return (0);
203: }
204: bad = 0;
205: for (i = 0; i < RESETJUNK; i++) {
206: c = regs->rbuf & 0377;
207: if ((c & RSDIAG) == 0) /* just a ROM version */
208: continue;
209: if (c == RSNULL || c == RSSKIP)
210: continue;
211: bad++;
212: printf("dhv11 %d: diag err %o\n", bd/NPER, c);
213: }
214: if (bad)
215: return (0);
216: dhv[dev].regs = regs;
217: dhv[dev].adno = ap->ubno;
218: dhv[dev].line = dev%NPER;
219: if (dev != bd) {
220: dhv[bd].regs = regs;
221: dhv[bd].adno = ap->ubno;
222: }
223: return (1);
224: }
225:
226: /*
227: * Close a DHV11 line.
228: */
229: dhvclose(q)
230: register struct queue *q;
231: {
232: register struct dhv *dhvp;
233: int s = spl5();
234:
235: dhvp = (struct dhv *)q->ptr;
236: if(dhvp->oblock){
237: freeb(dhvp->oblock);
238: dhvp->oblock = 0;
239: }
240: flushq(WR(q), 1);
241: dhvp->rdq = NULL;
242: POINT(dhvp->regs, dhvp->line);
243: dhvp->regs->lctl = 0;
244: dhvp->state = 0;
245: splx(s);
246: }
247:
248:
249: /*
250: * dhv11 write put routine
251: */
252: dhvoput(q, bp)
253: register struct queue *q;
254: register struct block *bp;
255: {
256: register struct dhv *dhvp = (struct dhv *)q->ptr;
257: register struct ttydevb *sp;
258: register int s;
259: int delaytime;
260:
261: switch(bp->type)
262: {
263: case M_IOCTL:
264: sp = (struct ttydevb *)stiodata(bp);
265: switch(stiocom(bp))
266: {
267: case TIOCSDEV:
268: delaytime = 0;
269: if(dhvp->ispeed != sp->ispeed)
270: delaytime = 20;
271: dhvp->ospeed = sp->ospeed;
272: dhvp->ispeed = sp->ispeed;
273: dhvp->flags = sp->flags;
274: bp->type = M_IOCACK;
275: bp->wptr = bp->rptr;
276: qreply(q, bp);
277: qpctl1(q, M_DELAY, delaytime); /* wait a bit */
278: qpctl(q, M_CTL); /* means do dhvparam */
279: dhvstart(dhvp);
280: return;
281: case TIOCGDEV:
282: sp->ispeed = dhvp->ispeed;
283: sp->ospeed = dhvp->ospeed;
284: sp->flags = dhvp->flags & (F8BIT|EVENP|ODDP);
285: bp->type = M_IOCACK;
286: qreply(q, bp);
287: return;
288: default:
289: bp->wptr = bp->rptr;
290: bp->type = M_IOCNAK;
291: qreply(q, bp);
292: return;
293: }
294: case M_STOP:
295: s = spl5();
296: dhvp->state |= DHSTOP;
297: freeb(bp);
298: dhvstop(dhvp);
299: splx(s);
300: return;
301: case M_START:
302: dhvp->state &= ~DHSTOP;
303: dhvstart(dhvp);
304: break;
305: case M_FLUSH:
306: flushq(q, 1);
307: freeb(bp);
308: return;
309: case M_BREAK:
310: qpctl1(q, M_DELAY, 10);
311: putq(q, bp);
312: qpctl1(q, M_DELAY, 10);
313: dhvstart(dhvp);
314: return;
315: case M_HANGUP:
316: dhvp->state &= ~DHSTOP;
317: case M_DELAY:
318: case M_DATA:
319: putq(q, bp);
320: dhvstart(dhvp);
321: return;
322: default: /* not handled; just toss */
323: break;
324: }
325: freeb(bp);
326: }
327:
328: /*
329: Set parameters from open or stty into the DH hardware
330: registers.
331: */
332: dhvparam(dhvp)
333: register struct dhv *dhvp;
334: {
335: register struct dhvreg *regs;
336: register int lpar;
337: register s;
338:
339: regs = dhvp->regs;
340: if(dhvp->ospeed)
341: dhvp->lctl |= (DTR|RTS);
342: else
343: dhvp->lctl &= ~(DTR|RTS);
344: lpar = (dhvsp[dhvp->ospeed]<<12) | (dhvsp[dhvp->ispeed]<<8);
345: if((dhvp->ospeed) == B134)
346: lpar |= BITS6|PENAB;
347: else if (dhvp->flags & F8BIT)
348: lpar |= BITS8;
349: else if(((s = dhvp->flags&(EVENP|ODDP)) == (EVENP|ODDP)) || (s == 0))
350: lpar |= BITS8;
351: else {
352: lpar |= BITS7|PENAB;
353: if(dhvp->flags&EVENP)
354: lpar |= EPARITY;
355: }
356: if ((dhvp->ospeed) == B110) /* 110 baud (ugh!): 2 stop bits */
357: lpar |= STOP2;
358: dhvp->state &= ~CARRIER;
359: POINT(regs, dhvp->line);
360: regs->lpr = lpar;
361: regs->lctl = dhvp->lctl;
362: if(regs->lstat&(DCD<<8))
363: dhvp->state |= CARRIER;
364: }
365:
366: /*
367: DHV11 receiver interrupt.
368: */
369: dhv0int(dev)
370: int dev;
371: {
372: register struct block *bp;
373: register struct dhvreg *regs;
374: register struct dhv *dhvp;
375: register int c;
376: int hangup;
377:
378: if(dev/NPER >= dhvcnt) {
379: printf("dhv%d: stray rcv intr\n", dev);
380: return;
381: }
382: regs = dhv[dev*NPER].regs;
383: /*
384: get chars from the silo for this line
385: */
386: while((c = regs->rbuf) < 0) { /* char present */
387: dhvp = &dhv[dev*NPER + LINE(c)];
388: hangup = 0;
389: if(ISMODEM(c)){
390: dhvp->state &= ~CARRIER;
391: if((c&DCD) == 0)
392: hangup = 1;
393: else {
394: dhvp->state |= CARRIER;
395: wakeup((caddr_t)dhvp);
396: continue;
397: }
398: c &= ~(OERR|FERR|PERR);
399: }
400: if(c&OERR){
401: ++dhvoverrun;
402: continue;
403: }
404: if(dhvp->rdq == NULL)
405: continue;
406: if(dhvp->rdq->next->flag & QFULL) {
407: dhvmiss++; /* you lose */
408: continue;
409: }
410: if((bp = allocb(16)) == NULL){
411: printf("rint: out of space\n");
412: continue; /* out of space - you lose */
413: }
414: if(hangup)
415: bp->type = M_HANGUP;
416: else if(c&FERR) /* frame error == BREAK */
417: bp->type = M_BREAK;
418: else
419: *bp->wptr++ = c;
420: (*dhvp->rdq->next->qinfo->putp)(dhvp->rdq->next, bp);
421: }
422: }
423:
424:
425: /*
426: DHV11 transmitter interrupt. Dev is board number.
427: Restart each line which used to be active but has
428: terminated transmission since the last interrupt.
429: */
430: dhv1int(dev)
431: int dev;
432: {
433: register struct dhvreg *regs;
434: register struct dhv *dhvp;
435: register struct block *bp;
436: register int unit;
437: register short csr;
438:
439: regs = dhv[dev*NPER].regs;
440: while((csr = regs->csr) < 0){
441: unit = TXLINE(csr);
442: dhvp = &dhv[unit + dev*NPER];
443: dhvp->state &= ~BUSY;
444: POINT(regs, unit);
445: if((csr&(TXACT|TXERR)) == (TXACT|TXERR)){ /* somebody goofed */
446: printf("dhv%d: txerr csr=0x%x addr2=0x%x addr1=0x%x\n",
447: dev, csr, regs->addr2, regs->addr1);
448: regs->cnt = 0; /* allow progress */
449: }
450: if(bp = dhvp->oblock){
451: bp->rptr = bp->wptr - regs->cnt;
452: if(bp->rptr == bp->wptr){
453: dhvp->oblock = 0;
454: freeb(bp);
455: }
456: }
457: dhvstart(dhvp);
458: }
459: }
460:
461: dhvtimo(dhvp)
462: register struct dhv *dhvp;
463: {
464:
465: if(dhvp->state&BRKING) {
466: int s = spl5();
467: POINT(dhvp->regs, dhvp->line);
468: dhvp->regs->lctl &= ~BREAK;
469: splx(s);
470: }
471: dhvp->state &= ~(TIMEOUT|BRKING);
472: dhvstart(dhvp);
473: }
474:
475: /*
476: Start (restart) transmission on the given DH11 line.
477: */
478: dhvstart(dhvp)
479: register struct dhv *dhvp;
480: {
481: register struct dhvreg *regs;
482: register int unit;
483: register int s = spl5();
484: register struct block *bp;
485: register uaddr_t addr;
486: ubm_t um;
487:
488: unit = dhvp->line;
489: if(dhvp->state & BUSY)
490: goto done;
491: regs = dhvp->regs;
492: again:
493: if(dhvp->state&(TIMEOUT|DHSTOP|BRKING) || (dhvp->rdq == NULL))
494: goto done;
495: if((bp = dhvp->oblock) == NULL){
496: if((bp = getq(WR(dhvp->rdq))) == NULL)
497: goto done;
498: }
499: switch(bp->type)
500: {
501: case M_DATA:
502: if (bp->wptr <= bp->rptr) {
503: freeb(bp);
504: dhvp->oblock = 0;
505: break;
506: }
507: if ((um = ubmblk(dhvp->adno, bp, 0)) == 0) { /* snh */
508: freeb(bp);
509: break;
510: }
511: addr = ubadrptr(dhvp->adno, bp, um);
512: LOW(regs->csr) = RXIE | (unit&0xF);
513: while(regs->addr2&TXSTART)
514: printf("dhv: start set\n");
515: if(regs->lctl&TXABORT)
516: regs->lctl &= ~TXABORT;
517: HIGH(regs->csr) = TXIE>>8;
518: regs->addr1 = addr;
519: regs->cnt = bp->wptr - bp->rptr;
520: HIGH(regs->addr2) = TXEN>>8;
521: LOW(regs->addr2) = (addr>>16) | TXSTART;
522: dhvp->state |= BUSY;
523: dhvp->oblock = bp;
524: break;
525: case M_BREAK:
526: dhvp->state |= BRKING|TIMEOUT;
527: timeout(dhvtimo, (caddr_t)dhvp, 15); /* about 250 ms */
528: freeb(bp);
529: break;
530: case M_DELAY:
531: dhvp->state |= TIMEOUT;
532: timeout(dhvtimo, (caddr_t)dhvp, (int)*bp->rptr + 6);
533: freeb(bp);
534: break;
535: case M_HANGUP:
536: dhvp->ispeed = dhvp->ospeed = 0;
537: /* fall through */
538: case M_CTL:
539: freeb(bp);
540: dhvparam(dhvp);
541: goto again;
542:
543: }
544: done:
545: splx(s);
546: }
547:
548:
549: /*
550: Stop output on a line, e.g. for ^S/^Q or output flush (e.g. ^O).
551: */
552: dhvstop(dhvp)
553: register struct dhv *dhvp;
554: {
555: register int s = spl5();
556:
557: if(dhvp->state & BUSY){
558: /*
559: just stop it, tint looks at the count
560: */
561: POINT(dhvp->regs, dhvp->line);
562: dhvp->regs->lctl |= TXABORT;
563: }
564: splx(s);
565: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.