|
|
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.