X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/b28deaf8866c3aba2ee330e5166bf1abf68c5c87..b91c756de21cd41dee810237e4534fa95b6ce41b:/usr/src/sys/vax/uba/dh.c?ds=inline diff --git a/usr/src/sys/vax/uba/dh.c b/usr/src/sys/vax/uba/dh.c index 408c5fc03d..f4ae51a799 100644 --- a/usr/src/sys/vax/uba/dh.c +++ b/usr/src/sys/vax/uba/dh.c @@ -1,54 +1,82 @@ -/* dh.c 4.8 %G% */ +/* dh.c 4.52 82/10/10 */ #include "dh.h" -#if NDH11 > 0 +#if NDH > 0 /* - * DH-11 driver - * - * Loaded with dhdm if there are DM-11's otherwise with dhfdm. - * - * NB: WE HAVEN'T TESTED dhdm CODE ON VAX. + * DH-11/DM-11 driver */ - +#include "bk.h" #include "../h/param.h" #include "../h/conf.h" #include "../h/dir.h" #include "../h/user.h" +#include "../h/proc.h" #include "../h/tty.h" #include "../h/map.h" #include "../h/pte.h" -#include "../h/uba.h" +#include "../h/buf.h" +#include "../h/vm.h" + +#include "../vaxuba/ubareg.h" +#include "../vaxuba/ubavar.h" + #include "../h/bk.h" #include "../h/clist.h" -#include "../h/mx.h" +#include "../h/file.h" +#include "../h/uio.h" /* - * When running dz's using only SAE (silo alarm) on input - * it is necessary to call dzrint() at clock interrupt time. - * This is unsafe unless spl5()s in tty code are changed to - * spl6()s to block clock interrupts. Note that the dh driver - * currently in use works the same way as the dz, even though - * we could try to more intelligently manage its silo. - * Thus don't take this out if you have no dz's unless you - * change clock.c and dhtimer(). + * Definition of the driver for the auto-configuration program. + * There is one definition for the dh and one for the dm. */ -#define spl5 spl6 - -#define UBACVT(x) (cbase + (short)((x)-(char *)cfree)) +int dhprobe(), dhattach(), dhrint(), dhxint(); +struct uba_device *dhinfo[NDH]; +u_short dhstd[] = { 0 }; +struct uba_driver dhdriver = + { dhprobe, 0, dhattach, 0, dhstd, "dh", dhinfo }; + +int dmprobe(), dmattach(), dmintr(); +struct uba_device *dminfo[NDH]; +u_short dmstd[] = { 0 }; +struct uba_driver dmdriver = + { dmprobe, 0, dmattach, 0, dmstd, "dm", dminfo }; + +struct dhdevice +{ + union { + short dhcsr; /* control-status register */ + char dhcsrl; /* low byte for line select */ + } un; + short dhrcr; /* receive character register */ + short dhlpr; /* line parameter register */ + u_short dhcar; /* current address register */ + short dhbcr; /* byte count register */ + u_short dhbar; /* buffer active register */ + short dhbreak; /* break control register */ + short dhsilo; /* silo status register */ +}; -struct tty dh11[NDH11]; -int dhact; -int dhisilo; -int ndh11 = NDH11; -int dhstart(); -int ttrstrt(); -int dh_ubinfo; -int cbase; -int getcbase; +#ifndef PORTSELECTOR +#define ISPEED B300 +#define IFLAGS (EVENP|ODDP|ECHO) +#else +#define ISPEED B4800 +#define IFLAGS (EVENP|ODDP) +#endif -/* - * Hardware control bits - */ +/* Bits in dhcsr */ +#define DH_TI 0100000 /* transmit interrupt */ +#define DH_SI 0040000 /* storage interrupt */ +#define DH_TIE 0020000 /* transmit interrupt enable */ +#define DH_SIE 0010000 /* storage interrupt enable */ +#define DH_MC 0004000 /* master clear */ +#define DH_NXM 0002000 /* non-existant memory */ +#define DH_MM 0001000 /* maintenance mode */ +#define DH_CNI 0000400 /* clear non-existant memory interrupt */ +#define DH_RI 0000200 /* receiver interrupt */ +#define DH_RIE 0000100 /* receiver interrupt enable */ + +/* Bits in dhlpr */ #define BITS6 01 #define BITS7 02 #define BITS8 03 @@ -58,210 +86,344 @@ int getcbase; #define OPAR 040 #define HDUPLX 040000 -#define IENAB 030100 -#define NXM 02000 -#define CLRNXM 0400 -#define PERROR 010000 -#define FRERROR 020000 -#define OVERRUN 040000 -#define XINT 0100000 -#define SSPEED 7 /* standard speed: 300 baud */ +#define DH_IE (DH_TIE|DH_SIE|DH_RIE) + +/* Bits in dhrcr */ +#define DH_PE 0010000 /* parity error */ +#define DH_FE 0020000 /* framing error */ +#define DH_DO 0040000 /* data overrun */ + +struct dmdevice +{ + short dmcsr; /* control status register */ + short dmlstat; /* line status register */ + short dmpad1[2]; +}; + +/* bits in dm csr */ +#define DM_RF 0100000 /* ring flag */ +#define DM_CF 0040000 /* carrier flag */ +#define DM_CTS 0020000 /* clear to send */ +#define DM_SRF 0010000 /* secondary receive flag */ +#define DM_CS 0004000 /* clear scan */ +#define DM_CM 0002000 /* clear multiplexor */ +#define DM_MM 0001000 /* maintenance mode */ +#define DM_STP 0000400 /* step */ +#define DM_DONE 0000200 /* scanner is done */ +#define DM_IE 0000100 /* interrupt enable */ +#define DM_SE 0000040 /* scan enable */ +#define DM_BUSY 0000020 /* scan busy */ + +/* bits in dm lsr */ +#define DML_RNG 0000200 /* ring */ +#define DML_CAR 0000100 /* carrier detect */ +#define DML_CTS 0000040 /* clear to send */ +#define DML_SR 0000020 /* secondary receive */ +#define DML_ST 0000010 /* secondary transmit */ +#define DML_RTS 0000004 /* request to send */ +#define DML_DTR 0000002 /* data terminal ready */ +#define DML_LE 0000001 /* line enable */ + +#define DML_ON (DML_DTR|DML_RTS|DML_LE) +#define DML_OFF (DML_LE) /* - * DM control bits + * Local variables for the driver */ -#define TURNON 03 /* CD lead + line enable */ -#define TURNOFF 01 /* line enable */ -#define DTR 02 /* data terminal ready */ -#define RQS 04 /* request to send */ +short dhsar[NDH]; /* software copy of last bar */ +short dhsoftCAR[NDH]; + +struct tty dh11[NDH*16]; +int ndh11 = NDH*16; +int dhact; /* mask of active dh's */ +int dhstart(), ttrstrt(); /* - * Software copy of last dhbar + * The clist space is mapped by the driver onto each UNIBUS. + * The UBACVT macro converts a clist space address for unibus uban + * into an i/o space address for the DMA routine. */ -short dhsar[(NDH11+15)/16]; +int dh_ubinfo[MAXNUBA]; /* info about allocated unibus map */ +int cbase[MAXNUBA]; /* base address in unibus map */ +#define UBACVT(x, uban) (cbase[uban] + ((x)-(char *)cfree)) -struct device +/* + * Routine for configuration to force a dh to interrupt. + * Set to transmit at 9600 baud, and cause a transmitter interrupt. + */ +/*ARGSUSED*/ +dhprobe(reg) + caddr_t reg; +{ + register int br, cvec; /* these are ``value-result'' */ + register struct dhdevice *dhaddr = (struct dhdevice *)reg; + +#ifdef lint + br = 0; cvec = br; br = cvec; + if (ndh11 == 0) ndh11 = 1; + dhrint(0); dhxint(0); +#endif +#ifndef notdef + dhaddr->un.dhcsr = DH_RIE|DH_MM|DH_RI; + DELAY(1000); + dhaddr->un.dhcsr &= ~DH_RI; + dhaddr->un.dhcsr = 0; +#else + dhaddr->un.dhcsr = DH_TIE; + DELAY(5); + dhaddr->dhlpr = (B9600 << 10) | (B9600 << 6) | BITS7|PENABLE; + dhaddr->dhbcr = -1; + dhaddr->dhcar = 0; + dhaddr->dhbar = 1; + DELAY(100000); /* wait 1/10'th of a sec for interrupt */ + dhaddr->un.dhcsr = 0; + if (cvec && cvec != 0x200) + cvec -= 4; /* transmit -> receive */ +#endif + return (sizeof (struct dhdevice)); +} + +/* + * Routine called to attach a dh. + */ +dhattach(ui) + struct uba_device *ui; { - union { - short dhcsr; - char dhcsrl; - } un; - short dhnxch; - short dhlpr; - unsigned short dhcar; - short dhbcr; - unsigned short dhbar; - short dhbreak; - short dhsilo; -}; + + dhsoftCAR[ui->ui_unit] = ui->ui_flags; +} /* - * Open a DH11 line. + * Configuration routine to cause a dm to interrupt. + */ +dmprobe(reg) + caddr_t reg; +{ + register int br, vec; /* value-result */ + register struct dmdevice *dmaddr = (struct dmdevice *)reg; + +#ifdef lint + br = 0; vec = br; br = vec; + dmintr(0); +#endif + dmaddr->dmcsr = DM_DONE|DM_IE; + DELAY(20); + dmaddr->dmcsr = 0; + return (1); +} + +/*ARGSUSED*/ +dmattach(ui) + struct uba_device *ui; +{ + + /* no local state to set up */ +} + +/* + * Open a DH11 line, mapping the clist onto the uba if this + * is the first dh on this uba. Turn on this dh if this is + * the first use of it. Also do a dmopen to wait for carrier. */ /*ARGSUSED*/ dhopen(dev, flag) + dev_t dev; { register struct tty *tp; - register d; - register struct device *addr; + register int unit, dh; + register struct dhdevice *addr; + register struct uba_device *ui; int s; - d = minor(dev) & 0177; - if (d >= NDH11) { + unit = minor(dev); + dh = unit >> 4; + if (unit >= NDH*16 || (ui = dhinfo[dh])== 0 || ui->ui_alive == 0) { u.u_error = ENXIO; return; } - tp = &dh11[d]; - addr = DHADDR; - addr += d>>4; + tp = &dh11[unit]; + if (tp->t_state&TS_XCLUDE && u.u_uid!=0) { + u.u_error = EBUSY; + return; + } + addr = (struct dhdevice *)ui->ui_addr; tp->t_addr = (caddr_t)addr; tp->t_oproc = dhstart; - tp->t_iproc = NULL; - tp->t_state |= WOPEN; - s = spl6(); - if (!getcbase) { - getcbase++; + tp->t_state |= TS_WOPEN; + /* + * While setting up state for this uba and this dh, + * block uba resets which can clear the state. + */ + s = spl5(); + if (dh_ubinfo[ui->ui_ubanum] == 0) { /* 512+ is a kludge to try to get around a hardware problem */ - dh_ubinfo = uballoc((caddr_t)cfree, 512+NCLIST*sizeof(struct cblock), 0); - cbase = (short)dh_ubinfo; + dh_ubinfo[ui->ui_ubanum] = + uballoc(ui->ui_ubanum, (caddr_t)cfree, + 512+nclist*sizeof(struct cblock), 0); + cbase[ui->ui_ubanum] = dh_ubinfo[ui->ui_ubanum]&0x3ffff; + } + if ((dhact&(1<un.dhcsr |= DH_IE; + dhact |= (1<dhsilo = 16; } splx(s); - addr->un.dhcsr |= IENAB; - dhact |= (1<<(d>>4)); - if ((tp->t_state&ISOPEN) == 0) { + /* + * If this is first open, initialze tty state to default. + */ + if ((tp->t_state&TS_ISOPEN) == 0) { ttychars(tp); +#ifndef PORTSELECTOR if (tp->t_ispeed == 0) { - tp->t_ispeed = SSPEED; - tp->t_ospeed = SSPEED; - tp->t_flags = ODDP|EVENP|ECHO; +#endif + tp->t_ispeed = ISPEED; + tp->t_ospeed = ISPEED; + tp->t_flags = IFLAGS; +#ifndef PORTSELECTOR } - dhparam(d); - } - if (tp->t_state&XCLUDE && u.u_uid!=0) { - u.u_error = EBUSY; - return; +#endif + dhparam(unit); } + /* + * Wait for carrier, then process line discipline specific open. + */ dmopen(dev); - (*linesw[tp->t_line].l_open)(dev,tp); + (*linesw[tp->t_line].l_open)(dev, tp); } /* - * Close a DH11 line. + * Close a DH11 line, turning off the DM11. */ /*ARGSUSED*/ dhclose(dev, flag) -dev_t dev; -int flag; + dev_t dev; + int flag; { register struct tty *tp; - register d; + register unit; - d = minor(dev) & 0177; - tp = &dh11[d]; + unit = minor(dev); + tp = &dh11[unit]; (*linesw[tp->t_line].l_close)(tp); - if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0) - dmctl(d, TURNOFF, DMSET); + ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); + if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0) + dmctl(unit, DML_OFF, DMSET); ttyclose(tp); } -/* - * Read from a DH11 line. - */ -dhread(dev) +dhread(dev, uio) + dev_t dev; + struct uio *uio; { -register struct tty *tp; + register struct tty *tp = &dh11[minor(dev)]; - tp = &dh11[minor(dev) & 0177]; - (*linesw[tp->t_line].l_read)(tp); + return ((*linesw[tp->t_line].l_read)(tp, uio)); } -/* - * write on a DH11 line - */ -dhwrite(dev) +dhwrite(dev, uio) + dev_t dev; + struct uio *uio; { -register struct tty *tp; + register struct tty *tp = &dh11[minor(dev)]; - tp = &dh11[minor(dev) & 0177]; - (*linesw[tp->t_line].l_write)(tp); + return ((*linesw[tp->t_line].l_write)(tp, uio)); } /* * DH11 receiver interrupt. */ -dhrint(dev) +dhrint(dh) + int dh; { register struct tty *tp; - register short c; - register struct device *addr; + register c; + register struct dhdevice *addr; register struct tty *tp0; - int s; + register struct uba_device *ui; + int overrun = 0; - s = spl6(); /* see comment in clock.c */ - addr = DHADDR; - addr += minor(dev) & 0177; - tp0 = &dh11[((minor(dev)&0177)<<4)]; - while ((c = addr->dhnxch) < 0) { /* char. present */ - tp = tp0 + ((c>>8)&017); - if (tp >= &dh11[NDH11]) - continue; - if((tp->t_state&ISOPEN)==0) { + ui = dhinfo[dh]; + if (ui == 0 || ui->ui_alive == 0) + return; + addr = (struct dhdevice *)ui->ui_addr; + tp0 = &dh11[dh<<4]; + /* + * Loop fetching characters from the silo for this + * dh until there are no more in the silo. + */ + while ((c = addr->dhrcr) < 0) { + tp = tp0 + ((c>>8)&0xf); +#ifndef PORTSELECTOR + if ((tp->t_state&TS_ISOPEN)==0) { +#else + if ((tp->t_state&(TS_ISOPEN|TS_WOPEN))==0) { +#endif wakeup((caddr_t)tp); continue; } - if (c&PERROR) + if (c & DH_PE) if ((tp->t_flags&(EVENP|ODDP))==EVENP || (tp->t_flags&(EVENP|ODDP))==ODDP ) continue; - if (c&OVERRUN) - printf("O"); - if (c&FRERROR) /* break */ + if ((c & DH_DO) && overrun == 0) { + printf("dh%d: silo overflow\n", dh); + overrun = 1; + } + if (c & DH_FE) + /* + * At framing error (break) generate + * a null (in raw mode, for getty), or a + * interrupt (in cooked/cbreak mode). + */ if (tp->t_flags&RAW) - c = 0; /* null (for getty) */ + c = 0; else -#ifdef IIASA - continue; -#else c = tun.t_intrc; -#endif +#if NBK > 0 if (tp->t_line == NETLDISC) { c &= 0177; BKINPUT(c, tp); } else - (*linesw[tp->t_line].l_rint)(c,tp); +#endif + (*linesw[tp->t_line].l_rint)(c, tp); } - splx(s); } /* - * stty/gtty for DH11 + * Ioctl for DH11. */ /*ARGSUSED*/ -dhioctl(dev, cmd, addr, flag) -caddr_t addr; +dhioctl(dev, cmd, data, flag) + caddr_t data; { register struct tty *tp; + register unit = minor(dev); - tp = &dh11[minor(dev) & 0177]; - cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr); - if (cmd==0) + tp = &dh11[unit]; + cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); + if (cmd == 0) return; - if (ttioctl(tp, cmd, addr, flag)) { - if (cmd==TIOCSETP||cmd==TIOCSETN) - dhparam(dev); + if (ttioctl(tp, cmd, data, flag)) { + if (cmd == TIOCSETP || cmd == TIOCSETN) + dhparam(unit); } else switch(cmd) { + case TIOCSBRK: - ((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017); + ((struct dhdevice *)(tp->t_addr))->dhbreak |= 1<<(unit&017); break; + case TIOCCBRK: - ((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017)); + ((struct dhdevice *)(tp->t_addr))->dhbreak &= ~(1<<(unit&017)); break; + case TIOCSDTR: - dmctl(minor(dev), DTR|RQS, DMBIS); + dmctl(unit, DML_DTR|DML_RTS, DMBIS); break; + case TIOCCDTR: - dmctl(minor(dev), DTR|RQS, DMBIC); + dmctl(unit, DML_DTR|DML_RTS, DMBIC); break; + default: u.u_error = ENOTTY; } @@ -271,38 +433,39 @@ caddr_t addr; * Set parameters from open or stty into the DH hardware * registers. */ -dhparam(dev) +dhparam(unit) + register int unit; { register struct tty *tp; - register struct device *addr; - register d; + register struct dhdevice *addr; + register int lpar; int s; - d = minor(dev) & 0177; - tp = &dh11[d]; - addr = (struct device *)tp->t_addr; - s = spl5(); - addr->un.dhcsrl = (d&017) | IENAB; + tp = &dh11[unit]; + addr = (struct dhdevice *)tp->t_addr; /* - * Hang up line? + * Block interrupts so parameters will be set + * before the line interrupts. */ + s = spl5(); + addr->un.dhcsrl = (unit&0xf) | DH_IE; if ((tp->t_ispeed)==0) { - tp->t_state |= HUPCLS; - dmctl(d, TURNOFF, DMSET); + tp->t_state |= TS_HUPCLS; + dmctl(unit, DML_OFF, DMSET); return; } - d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); - if ((tp->t_ispeed) == 4) /* 134.5 baud */ - d |= BITS6|PENABLE|HDUPLX; - else if (tp->t_flags&RAW) - d |= BITS8; + lpar = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6); + if ((tp->t_ispeed) == B134) + lpar |= BITS6|PENABLE|HDUPLX; + else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT)) + lpar |= BITS8; else - d |= BITS7|PENABLE; + lpar |= BITS7|PENABLE; if ((tp->t_flags&EVENP) == 0) - d |= OPAR; - if ((tp->t_ospeed) == 3) /* 110 baud */ - d |= TWOSB; - addr->dhlpr = d; + lpar |= OPAR; + if ((tp->t_ospeed) == B110) + lpar |= TWOSB; + addr->dhlpr = lpar; splx(s); } @@ -311,38 +474,43 @@ dhparam(dev) * Restart each line which used to be active but has * terminated transmission since the last interrupt. */ -dhxint(dev) +dhxint(dh) + int dh; { register struct tty *tp; - register struct device *addr; - register d; + register struct dhdevice *addr; short ttybit, bar, *sbar; - int s; - - s = spl6(); /* block the clock */ - d = minor(dev) & 0177; - addr = DHADDR + d; - addr->un.dhcsr &= (short)~XINT; - if (addr->un.dhcsr & NXM) { - addr->un.dhcsr |= CLRNXM; - printf("dh clr NXM\n"); + register struct uba_device *ui; + register int unit; + u_short cntr; + + ui = dhinfo[dh]; + addr = (struct dhdevice *)ui->ui_addr; + if (addr->un.dhcsr & DH_NXM) { + addr->un.dhcsr |= DH_CNI; + printf("dh%d: NXM\n", dh); } - sbar = &dhsar[d]; + sbar = &dhsar[dh]; bar = *sbar & ~addr->dhbar; - d <<= 4; ttybit = 1; - - for(; bar; d++, ttybit <<= 1) { - if(bar&ttybit) { + unit = dh * 16; ttybit = 1; + addr->un.dhcsr &= (short)~DH_TI; + for (; bar; unit++, ttybit <<= 1) { + if (bar & ttybit) { *sbar &= ~ttybit; bar &= ~ttybit; - tp = &dh11[d]; - tp->t_state &= ~BUSY; - if (tp->t_state&FLUSH) - tp->t_state &= ~FLUSH; + tp = &dh11[unit]; + tp->t_state &= ~TS_BUSY; + if (tp->t_state&TS_FLUSH) + tp->t_state &= ~TS_FLUSH; else { - addr->un.dhcsrl = (d&017)|IENAB; - ndflush(&tp->t_outq, - (int)(short)addr->dhcar-UBACVT(tp->t_outq.c_cf)); + addr->un.dhcsrl = (unit&017)|DH_IE; + /* + * Do arithmetic in a short to make up + * for lost 16&17 bits. + */ + cntr = addr->dhcar - + UBACVT(tp->t_outq.c_cf, ui->ui_ubanum); + ndflush(&tp->t_outq, (int)cntr); } if (tp->t_line) (*linesw[tp->t_line].l_start)(tp); @@ -350,162 +518,292 @@ dhxint(dev) dhstart(tp); } } - splx(s); } /* * Start (restart) transmission on the given DH11 line. */ dhstart(tp) -register struct tty *tp; + register struct tty *tp; { - register struct device *addr; - register short nch; - int s, d; + register struct dhdevice *addr; + register int car, dh, unit, nch; + int s; + + unit = minor(tp->t_dev); + dh = unit >> 4; + unit &= 0xf; + addr = (struct dhdevice *)tp->t_addr; /* - * If it's currently active, or delaying, - * no need to do anything. + * Must hold interrupts in following code to prevent + * state of the tp from changing. */ s = spl5(); - d = tp-dh11; - addr = (struct device *)tp->t_addr; - if (tp->t_state&(TIMEOUT|BUSY|TTSTOP)) + /* + * If it's currently active, or delaying, no need to do anything. + */ + if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) goto out; - /* - * If the writer was sleeping on output overflow, - * wake him when low tide is reached. + * If there are sleepers, and output has drained below low + * water mark, wake up the sleepers. */ - if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) { - tp->t_state &= ~ASLEEP; - if (tp->t_chan) - mcstart(tp->t_chan, (caddr_t)&tp->t_outq); - else + if (tp->t_outq.c_cc<=TTLOWAT(tp)) { + if (tp->t_state&TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; wakeup((caddr_t)&tp->t_outq); + } + if (tp->t_wsel) { + selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); + tp->t_wsel = 0; + tp->t_state &= ~TS_WCOLL; + } } - - if (tp->t_outq.c_cc == 0) - goto out; - /* - * Find number of characters to transfer. + * Now restart transmission unless the output queue is + * empty. */ - if (tp->t_flags & RAW) { + if (tp->t_outq.c_cc == 0) + goto out; + if (tp->t_flags&RAW || tp->t_local&LLITOUT) nch = ndqb(&tp->t_outq, 0); - } else { + else { nch = ndqb(&tp->t_outq, 0200); + /* + * If first thing on queue is a delay process it. + */ if (nch == 0) { nch = getc(&tp->t_outq); - timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6); - tp->t_state |= TIMEOUT; + timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6); + tp->t_state |= TS_TIMEOUT; goto out; } } /* - * If any characters were set up, start transmission; + * If characters to transmit, restart transmission. */ if (nch) { - addr->un.dhcsrl = (d&017)|IENAB; - addr->dhcar = UBACVT(tp->t_outq.c_cf); + car = UBACVT(tp->t_outq.c_cf, dhinfo[dh]->ui_ubanum); + addr->un.dhcsrl = unit|((car>>12)&0x30)|DH_IE; + /* + * The following nonsense with short word + * is to make sure the dhbar |= word below + * is done with an interlocking bisw2 instruction. + */ + { short word = 1 << unit; + dhsar[dh] |= word; + addr->dhcar = car; addr->dhbcr = -nch; - nch = 1<<(d&017); - addr->dhbar |= nch; - dhsar[d>>4] |= nch; - tp->t_state |= BUSY; + addr->dhbar |= word; + } + tp->t_state |= TS_BUSY; } - out: +out: splx(s); } /* - * Stop output on a line. - * Assume call is made at spl6. + * Stop output on a line, e.g. for ^S/^Q or output flush. */ /*ARGSUSED*/ dhstop(tp, flag) -register struct tty *tp; + register struct tty *tp; { - register struct device *addr; - register d, s; - - addr = (struct device *)tp->t_addr; - s = spl6(); - if (tp->t_state & BUSY) { - d = minor(tp->t_dev); - addr->un.dhcsrl = (d&017) | IENAB; - if ((tp->t_state&TTSTOP)==0) - tp->t_state |= FLUSH; + register struct dhdevice *addr; + register int unit, s; + + addr = (struct dhdevice *)tp->t_addr; + /* + * Block input/output interrupts while messing with state. + */ + s = spl5(); + if (tp->t_state & TS_BUSY) { + /* + * Device is transmitting; stop output + * by selecting the line and setting the byte + * count to -1. We will clean up later + * by examining the address where the dh stopped. + */ + unit = minor(tp->t_dev); + addr->un.dhcsrl = (unit&017) | DH_IE; + if ((tp->t_state&TS_TTSTOP)==0) + tp->t_state |= TS_FLUSH; addr->dhbcr = -1; } splx(s); } -int dhsilo = 16; /* - * Silo control is fixed strategy - * here, paralleling only option available - * on DZ-11. + * Reset state of driver if UBA reset was necessary. + * Reset the csrl and lpr registers on open lines, and + * restart transmitters. */ -/*ARGSUSED*/ -dhtimer() +dhreset(uban) + int uban; { - register d; - register struct device *addr; - - addr = DHADDR; d = 0; - do { - if (dhact & (1<dhsilo = dhsilo; - dhisilo |= 1<ui_alive == 0 || ui->ui_ubanum != uban) + continue; + printf(" dh%d", dh); + ((struct dhdevice *)ui->ui_addr)->un.dhcsr |= DH_IE; + ((struct dhdevice *)ui->ui_addr)->dhsilo = 16; + unit = dh * 16; + for (i = 0; i < 16; i++) { + tp = &dh11[unit]; + if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) { + dhparam(unit); + dmctl(unit, DML_ON, DMSET); + tp->t_state &= ~TS_BUSY; + dhstart(tp); } - dhrint(d); + unit++; } - d++; - addr++; - } while (d < (NDH11+15)/16); + } + dhtimer(); } /* - * Reset state of driver if UBA reset was necessary. - * Reset the csrl and lpr registers on open lines, and - * restart transmitters. + * At software clock interrupt time or after a UNIBUS reset + * empty all the dh silos. + */ +dhtimer() +{ + register int dh; + register int s = spl5(); + + for (dh = 0; dh < NDH; dh++) + dhrint(dh); + splx(s); +} + +/* + * Turn on the line associated with dh dev. + */ +dmopen(dev) + dev_t dev; +{ + register struct tty *tp; + register struct dmdevice *addr; + register struct uba_device *ui; + register int unit; + register int dm; + int s; + + unit = minor(dev); + dm = unit >> 4; + tp = &dh11[unit]; + unit &= 0xf; + if (dm >= NDH || (ui = dminfo[dm]) == 0 || ui->ui_alive == 0 || + (dhsoftCAR[dm]&(1<t_state |= TS_CARR_ON; + return; + } + addr = (struct dmdevice *)ui->ui_addr; + s = spl5(); + addr->dmcsr &= ~DM_SE; + while (addr->dmcsr & DM_BUSY) + ; + addr->dmcsr = unit; + addr->dmlstat = DML_ON; + if (addr->dmlstat&DML_CAR) + tp->t_state |= TS_CARR_ON; + addr->dmcsr = DM_IE|DM_SE; + while ((tp->t_state&TS_CARR_ON)==0) + sleep((caddr_t)&tp->t_rawq, TTIPRI); + splx(s); +} + +/* + * Dump control bits into the DM registers. + */ +dmctl(dev, bits, how) + dev_t dev; + int bits, how; +{ + register struct uba_device *ui; + register struct dmdevice *addr; + register int unit, s; + int dm; + + unit = minor(dev); + dm = unit >> 4; + if ((ui = dminfo[dm]) == 0 || ui->ui_alive == 0) + return; + addr = (struct dmdevice *)ui->ui_addr; + s = spl5(); + addr->dmcsr &= ~DM_SE; + while (addr->dmcsr & DM_BUSY) + ; + addr->dmcsr = unit & 0xf; + switch(how) { + case DMSET: + addr->dmlstat = bits; + break; + case DMBIS: + addr->dmlstat |= bits; + break; + case DMBIC: + addr->dmlstat &= ~bits; + break; + } + addr->dmcsr = DM_IE|DM_SE; + splx(s); +} + +/* + * DM11 interrupt; deal with carrier transitions. */ -dhreset() +dmintr(dm) + register int dm; { - int d; + register struct uba_device *ui; register struct tty *tp; - register struct device *addr; + register struct dmdevice *addr; - if (getcbase == 0) + ui = dminfo[dm]; + if (ui == 0) return; - printf(" dh"); - dhisilo = 0; - ubarelse(&dh_ubinfo); - dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0); - cbase = (short)dh_ubinfo; - d = 0; - do { - addr = DHADDR + d; - if (dhact & (1<un.dhcsr |= IENAB; - d++; - } while (d < (NDH11+15)/16); - for (d = 0; d < NDH11; d++) { - tp = &dh11[d]; - if (tp->t_state & (ISOPEN|WOPEN)) { - dhparam(d); - dmctl(d, TURNON, DMSET); - tp->t_state &= ~BUSY; - dhstart(tp); + addr = (struct dmdevice *)ui->ui_addr; + if (addr->dmcsr&DM_DONE) { + if (addr->dmcsr&DM_CF) { + tp = &dh11[(dm<<4)+(addr->dmcsr&0xf)]; + wakeup((caddr_t)&tp->t_rawq); + if ((tp->t_state&TS_WOPEN)==0 && + (tp->t_local&LMDMBUF)) { + if (addr->dmlstat & DML_CAR) { + tp->t_state &= ~TS_TTSTOP; + ttstart(tp); + } else if ((tp->t_state&TS_TTSTOP) == 0) { + tp->t_state |= TS_TTSTOP; + dhstop(tp, 0); + } + } else if ((addr->dmlstat&DML_CAR)==0) { + if ((tp->t_state&TS_WOPEN)==0 && + (tp->t_local&LNOHANG)==0) { + gsignal(tp->t_pgrp, SIGHUP); + gsignal(tp->t_pgrp, SIGCONT); + addr->dmlstat = 0; + flushtty(tp, FREAD|FWRITE); + } + tp->t_state &= ~TS_CARR_ON; + } else + tp->t_state |= TS_CARR_ON; } + addr->dmcsr = DM_IE|DM_SE; } - dhtimer(); } -#if DHDM > 0 -#include "../dev/dhdm.c" -#else -#include "../dev/dhfdm.c" -#endif #endif