-/* 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
#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<<dh)) == 0) {
+ addr->un.dhcsr |= DH_IE;
+ dhact |= (1<<dh);
+ addr->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;
}
* 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);
}
* 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);
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<<d)) {
- if ((dhisilo & (1<<d)) == 0) {
- addr->dhsilo = dhsilo;
- dhisilo |= 1<<d;
+ register int dh, unit;
+ register struct tty *tp;
+ register struct uba_device *ui;
+ int i;
+
+ if (dh_ubinfo[uban] == 0)
+ return;
+ ubarelse(uban, &dh_ubinfo[uban]);
+ dh_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
+ 512+nclist*sizeof (struct cblock), 0);
+ cbase[uban] = dh_ubinfo[uban]&0x3ffff;
+ dh = 0;
+ for (dh = 0; dh < NDH; dh++) {
+ ui = dhinfo[dh];
+ if (ui == 0 || ui->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<<unit))) {
+ tp->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<<d))
- addr->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