/* * DZ-11 Driver */ /* Modified 4/84 by J. Wolitzky to allow dialout operation with smart modems */ #include "dz.h" #define TRC(c) #include "../h/param.h" #include "../h/stream.h" #include "../h/ttyio.h" #include "../h/ttyld.h" #include "../h/pte.h" #include "../h/map.h" #include "../h/buf.h" #include "../h/systm.h" #include "../h/ubavar.h" #include "../h/conf.h" #define NDZLINE (8*NDZ) #define BITS7 020 #define BITS8 030 #define TWOSB 040 #define PENABLE 0100 #define OPAR 0200 #define CLR 020 /* Clear */ #define MSE 040 /* Master Scan Enable */ #define RIE 0100 /* Receiver Interrupt Enable */ #define SAE 010000 /* Silo Alarm Enable */ #define TIE 040000 /* Transmit Interrupt Enable */ #define TRDY 0100000 /* Transmitter ready */ #define DZ_IEN (MSE+RIE+TIE) #define PERROR 010000 #define FRERROR 020000 #define OVERRUN 040000 #define SSPEED 9 /* std speed = 1200 baud */ #define EXISTS 01 #define ISOPEN 02 #define WOPEN 04 #define TIMEOUT 010 #define CARR_ON 020 #define DZSTOP 040 #define HPCL 0100 #define BRKING 0200 #define DIALOUT 0400 /* set when used as dialout with smart modems */ #define DZPRI 30 struct device { short dzcsr; short dzrbuf; #define dzlpr dzrbuf char dztcr; char dzdtr; char dztbuf; #define dzrind dztbuf char dzbrk; #define dzmsr dzbrk }; int dzprobe(), dzattach(), dzrint(); struct uba_device *dzboard[NDZ]; u_short dzstd[] = { 0 }; struct uba_driver dzdriver = { dzprobe, 0, dzattach, 0, dzstd, "dz", dzboard }; /* * One structure per line */ struct dz { short state; short flags; struct block *oblock; struct queue *rdq; char board; char line; char speed; char brking; } dz[NDZLINE]; int dzoverrun; char dz_speeds[] = { 0, 020 , 021 , 022 , 023 , 024 , 0, 025, 026 , 027 , 030 , 032 , 034 , 036 , 037 , 0 }; int dzopen(), dzclose(), dzoput(), nodev(); static struct qinit dzrinit = { nodev, NULL, dzopen, dzclose, 0, 0 }; struct qinit dzwinit = { dzoput, NULL, dzopen, dzclose, 200, 100 }; struct streamtab dzinfo = { &dzrinit, &dzwinit }; int dzmiss; dzprobe(reg) caddr_t reg; { register int br, cvec; register struct device *dzaddr = (struct device *)reg; dzaddr->dzcsr = TIE|MSE; dzaddr->dztcr = 1; /* enable any line */ DELAY(100000); dzaddr->dzcsr = CLR; /* reset everything */ if (cvec && cvec != 0x200) cvec -= 4; return (1); } dzattach(ui) register struct uba_device *ui; { extern dzscan(); static dz_timer; register i; for (i=0; i<8; i++) { dz[ui->ui_unit*8+i].state = EXISTS; dz[ui->ui_unit*8+i].board = ui->ui_unit; dz[ui->ui_unit*8+i].line = i; } if (dz_timer == 0) { dz_timer++; timeout(dzscan, (caddr_t)0, hz); } return (1); } /*ARGSUSED*/ dzopen(q, d, flag) register struct queue *q; { register dev; register struct dz *dzp; int dzflag; dev = minor(d); dzp = &dz[dev]; if (dev >= NDZLINE || (dzp->state&EXISTS)==0) return(0); q->ptr = (caddr_t)dzp; WR(q)->ptr = (caddr_t)dzp; dzscan((caddr_t)1); /* update CARR_ON */ if ((dzp->state&ISOPEN)==0 || (dzp->state&CARR_ON)==0) { register s = spl5(); for (;;) { dzp->flags = F8BIT|ODDP|EVENP; dzp->speed = SSPEED; dzparam(dzp); if (dzp->state & CARR_ON) break; dzflag = dzboard[dev / 8]->ui_flags; /* ignore carrier? */ if (dzflag & (1 << (dev % 8))) { dzp->state |= (DIALOUT | CARR_ON); break; } if (tsleep((caddr_t)dzp, DZPRI, 0) != TS_OK) { wakeup((caddr_t)dzp); dzp->speed = 0; dzparam(dzp); splx(s); return(0); } } dzp->rdq = q; dzp->state |= ISOPEN; splx(s); } TRC('o'); return(1); } dzclose(q, d) register struct queue *q; { register struct dz *dzp; register s; dzp = (struct dz *)q->ptr; s = spl5(); if (dzp->oblock) { register struct block *bp = dzp->oblock; dzp->oblock = NULL; freeb(bp); } flushq(WR(q), 1); dzp->rdq = NULL; if (dzp->state&HPCL || (dzp->state&CARR_ON)==0) { dzp->speed = 0; dzparam(dzp); } dzp->state &= EXISTS; splx(s); TRC('c'); } /* * DZ write put routine */ dzoput(q, bp) register struct queue *q; register struct block *bp; { register struct dz *dzp = (struct dz *)q->ptr; register union stmsg *sp; register s; int delaytime; TRC('p'); switch(bp->type) { case M_IOCTL: TRC('i'); sp = (union stmsg *)bp->rptr; switch (sp->ioc0.com) { case TIOCSDEV: delaytime = 0; if (dzp->speed != sp->ioc3.sb.ispeed) delaytime = 20; dzp->speed = sp->ioc3.sb.ispeed; dzp->flags = sp->ioc3.sb.flags; bp->type = M_IOCACK; bp->wptr = bp->rptr; qreply(q, bp); qpctl1(q, M_DELAY, delaytime); /* wait a bit */ qpctl(q, M_CTL); /* means do dzparam */ dzstart(dzp); return; case TIOCGDEV: sp->ioc3.sb.ispeed = sp->ioc3.sb.ospeed = dzp->speed; sp->ioc3.sb.flags = dzp->flags; bp->type = M_IOCACK; qreply(q, bp); return; case TIOCHPCL: dzp->state |= HPCL; bp->type = M_IOCACK; bp->wptr = bp->rptr; qreply(q, bp); return; default: bp->wptr = bp->rptr; bp->type = M_IOCNAK; qreply(q, bp); return; } case M_STOP: s = spl5(); dzp->state |= DZSTOP; freeb(bp); if (bp = dzp->oblock) { dzp->oblock = NULL; putbq(q, bp); } splx(s); return; case M_START: dzp->state &= ~DZSTOP; dzstart(dzp); break; case M_FLUSH: flushq(q, 1); freeb(bp); s = spl5(); if (bp = dzp->oblock) { dzp->oblock = NULL; freeb(bp); } splx(s); return; case M_BREAK: qpctl1(q, M_DELAY, 10); putq(q, bp); qpctl1(q, M_DELAY, 10); dzstart(dzp); return; case M_HANGUP: dzp->state &= ~DZSTOP; case M_DELAY: case M_DATA: putq(q, bp); TRC('d'); dzstart(dzp); return; default: /* not handled; just toss */ break; } freeb(bp); } /* * Receive interrupt. Argument is DZ board number */ dzrint(dev) { register struct dz *dzp; register struct block *bp; register struct device *dzaddr; register int c; if (dev >= NDZ) { printf("bad dz rd intr\n"); return; } dzaddr = (struct device *)dzboard[dev]->ui_addr; while ((c = dzaddr->dzrbuf) < 0) { /* char present */ dzp = &dz[dev*8 + ((c>>8)&07)]; if (c&(OVERRUN/*|PERROR*/)) { if (c&OVERRUN) dzoverrun++; continue; } if (dzp->rdq == NULL) continue; if (dzp->rdq->next->flag&QFULL) { dzmiss++; continue; } if ((bp = allocb(16)) == NULL) continue; /* no space */ if (c&FRERROR) /* frame err (break) */ bp->type = M_BREAK; else *bp->wptr++ = c; (*dzp->rdq->next->qinfo->putp)(dzp->rdq->next, bp); } } /* * set device parameters */ dzparam(dzp) register struct dz *dzp; { register short lpr; struct device *dzaddr = (struct device *)dzboard[dzp->board]->ui_addr; dzaddr->dzcsr = DZ_IEN; if (dzp->speed == 0) { dzaddr->dzdtr &= ~(1 << dzp->line); /* hang up */ return; } dzaddr->dzdtr |= 1 << dzp->line; lpr = (dz_speeds[dzp->speed]<<8) | dzp->line; if (dzp->flags & F8BIT) lpr |= BITS8; else lpr |= (BITS7|PENABLE); if ((dzp->flags & EVENP) == 0) lpr |= OPAR; if (dzp->speed == 3) lpr |= TWOSB; /* 110 baud: 2 stop bits */ dzaddr->dzlpr = lpr; } /* * Transmitter interrupt. dev is board number. */ dztint(dev) { register struct device *dzaddr = (struct device *)dzboard[dev]->ui_addr; register struct dz *dzp; register struct block *bp; register sts; while ((sts = dzaddr->dzcsr) & TRDY) { dzp = &dz[dev*8 + ((sts>>8)&07)]; if (bp = dzp->oblock) { if (bp->rptr < bp->wptr) { dzaddr->dztbuf = *bp->rptr++; continue; } freeb(bp); dzp->oblock = NULL; } dzaddr->dztcr &= ~(1 << (dzp->line)); dzstart(dzp); } } dztimo(dzp) register struct dz *dzp; { if (dzp->state&BRKING) { dzp->brking &= ~(1 << dzp->line); ((struct device *)dzboard[dzp->board]->ui_addr)->dzbrk = dzp->brking; } dzp->state &= ~(TIMEOUT|BRKING); dzstart(dzp); } dzstart(dzp) register struct dz *dzp; { register s = spl5(); register struct block *bp; register struct device *dzaddr; TRC('s'); again: if (dzp->state & (TIMEOUT|DZSTOP|BRKING) || dzp->oblock) { TRC('t'); goto out; } if (dzp->rdq == NULL) goto out; if ((bp = getq(WR(dzp->rdq))) == NULL) { TRC('n'); goto out; } switch (bp->type) { case M_DATA: dzp->oblock = bp; dzaddr = (struct device *)dzboard[dzp->board]->ui_addr; dzaddr->dztcr |= 1 << (dzp->line); break; case M_BREAK: dzaddr = (struct device *)dzboard[dzp->board]->ui_addr; dzp->brking |= 1 << dzp->line; dzaddr->dzbrk = dzp->brking; dzp->state |= BRKING|TIMEOUT; timeout(dztimo, (caddr_t)dzp, 15); /* about 250 ms */ freeb(bp); break; case M_DELAY: dzp->state |= TIMEOUT; timeout(dztimo, (caddr_t)dzp, (int)*bp->rptr + 6); freeb(bp); break; case M_HANGUP: dzp->speed = 0; case M_CTL: freeb(bp); dzparam(dzp); goto again; } out: splx(s); } dzscan(timo) caddr_t timo; { register struct device *dzaddr; register struct dz *dzp; register i, j; for (i=0; i<NDZ; i++) { if (dzboard[i] == NULL) continue; dzaddr = (struct device *)dzboard[i]->ui_addr; for (j=0,dzp = &dz[i*8]; j<8; j++, dzp++) { if (dzaddr->dzmsr & (1<<j)) { /* carrier present */ if ((dzp->state & CARR_ON)==0) wakeup((caddr_t)dzp); dzp->state |= CARR_ON; } else if ((dzp->state & CARR_ON) && !(dzp->state & DIALOUT)) { /* carrier lost */ if (dzp->state&ISOPEN) { dzaddr->dzdtr &= ~(1<<j); if (dzp->rdq) putctl(dzp->rdq->next,M_HANGUP); } dzp->state &= ~CARR_ON; } } } if (timo == 0) timeout(dzscan, (caddr_t)0, 2*hz); }