Annotation of researchv10no/sys/io/dhv11.c, revision 1.1.1.1

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, &regs->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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.