[net.sources] DMF32 driver for 4.2BSD, includes line printer driver

chris@umcp-cs.UUCP (Chris Torek) (06/02/85)

The remainder of this file (up to the .signature part) is a shell
script which will extract a 4.2BSD DMF32 driver.  This code is known to
work properly with Emulex CS21Fs (on which you can disable the line
printer driver, since it's not in the hardware) and with DEC DMF32s,
though I have not tested the line printer code.  It also includes the
U of MD ``outgoing mode'' code (which uses an extra cdevsw table entry).
If you wish to take advantage of the ``dial'' portion of the driver,
add a line to your config file of the form

	pseudo-device dmfo

and add a cdevsw entry in /sys/vax/conf.c that is like the dmf entry,
but uses dmfoopen and dmfoclose as the first two routines (note that
you will also need to declare them as int functions).  This is done in
the same way as for the outgoing mode DZ mods I posted earlier.

And now for our show:

: Run this shell script with "sh" not "csh"
: files: dmf.c dmfo.c dmfreg.h
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting dmf.c'
sed 's/^X//' <<'//go.sysin dd *' >dmf.c
X/*
 * DMF32 driver
 *
 * From Chris Maloney: MDDC Version 1.00 June 23, 1984
 * Modified by Chris Torek, U of M, for 4.1BSD and dial out (``dmfo'' device)
 * and for #define EMULEX garbage
 *
 * Converted back to 4.2BSD 29 Mar 1985, Chris Torek
 * Formatting completely revised 15 Apr 1985, Chris Torek
 *
 * TODO:
 *	test reset code
 *
 * DMF32 line printer driver
 * The line printer on dmfx is indicated by a minor device code of 128+x.
 *
 *
 * The flags field of the config file is interpreted as:
 *   bits	meaning
 *   ----	-------
 *   0-7	soft carrier bits for ttys part of dmf32
 *   8-15	number of cols/line on the line printer
 *		if 0, 132 will be used.
 *   16-23	number of lines/page on the line printer
 *		if 0, 66 will be used.
 */

#include "dmf.h"
#if NDMF > 0
#include "dmfo.h"

X/* Define this if you have Emulex CS21Fs *and no DEC DMFs*, then change your
   config file to list only "dmfrint dmfxint" as the interrupt vectors.  This
   also disables the line printer driver. */
X/* #define EMULEX */

#include "../machine/pte.h"

#include "bk.h"
#include "../h/param.h"
#include "../h/conf.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/ioctl.h"
#include "../h/tty.h"
#include "../h/uio.h"
#include "../h/map.h"
#include "../h/buf.h"
#include "../h/vm.h"
#include "../h/bk.h"
#include "../h/clist.h"
#include "../h/file.h"

#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
#include "../vaxuba/dmfreg.h"

X/*
 * SILO TIME OUT constant:  if you get data overruns, or have problems with
 * XON/XOFF not responing quick enough, set this lower, but keep it at least
 * 1.  If you make this 0, you are in trouble.
 */
#define SILO_TIME_OUT	3

X/*
 * DO DMA COUNT constant:  number of characters at which driver uses DMA mode.
 * DEC uses 32, but this is too high for Unix.  (I think VMS has to remap UBA
 * memory to do the DMA.)  Setting this to 0 disables silo mode.
 *
 * N.B.:  You probably want to increase CBSIZE and CROUND in param.h.
 * We have found clist size = 128 to be about right (CBSIZE=124, CROUND=127).
 */
#define DO_DMA_COUNT	16

X/*
 * Definition of the driver for the auto-configuration program.
 */
int     dmfprobe(), dmfattach(), dmfrint(), dmfxint();
#ifndef EMULEX
int	dmflint();
#endif
struct  uba_device *dmfinfo[NDMF];
u_short dmfstd[] = { 0160340, 0 };
struct uba_driver dmfdriver =
	{ dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };

X/*
 * Local variables for the driver
 */
int     dmfact;			/* mask of active dmf's */

#ifndef EMULEX
X/* states for line printer (1 per DMF) */
#define ASLP		1	/* waiting for interrupt from dmf */
#define OPEN		2	/* line printer is open */
#define ERROR		4	/* error while printing; driver refuses to
				   do anything till closed */
#define MORETODO	8	/* more output on the way */

struct dmfl_softc {
	short	sc_state;	/* soft state bits */
	u_char	sc_lines;	/* lines per page (66 def.) */
	u_char	sc_cols;	/* cols per line (132 def.) */
	u_int	sc_info;	/* uba info */
	char	sc_buf[DMFL_SIZ];
} dmfl_softc[NDMF];
#endif

char   dmf_speeds[] = { 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 10, 12, 14, 15, 15};
int    dmfstart();

#ifndef lint
int    ndmf = NDMF * 8;		/* used by iostat, among others */
#endif

int    ttrstrt();
struct tty dmf_tty[NDMF * 8];

char   dmfsoftCAR[NDMF];	/* soft carrier flags */
#if NDMFO > 0
char   dmf_inout[NDMF];		/* outgoing mode flags */
char   dmf_flags[NDMF];		/* permanent copy of flags */
#endif

X/* states for async lines (8 per DMF) */
#define ST_TXOFF	0x01	/* tx turned off */
#define ST_DMA		0x02	/* dma operation inprogress */
#define ST_INBUSY	0x04	/* stop tx in busy */
struct dmfa_softc {
	short	sc_state;	/* dmf state */
	short	sc_count;	/* dmf dma count */
} dmfa_softc[NDMF * 8];


X/*
 * 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.  <<Ripped off from dh.c>>
 */
int     dmf_ubinfo[MAXNUBA];	/* info about allocated unibus map */
static int cbase[MAXNUBA];	/* base address in unibus map */
#define	UBACVT(x,uban) (cbase[uban] + ((x) - (char *)cfree))

extern int hz;			/* clock frequency */

X/*
 * Routine for configuration to set dmf interrupt.
 */
X/* ARGSUSED */
dmfprobe(reg, ctlr)
	caddr_t reg;
	int ctlr;
{
	register int br, cvec;	/* these are ``value-result'' */
	register struct dmfdevice *dmf_addr = (struct dmfdevice *) reg;
	register int i;

#ifdef lint
	br = 0; cvec = br; br = cvec;
	dmfxint (0); dmfrint (0); dmfsrint (); dmfsxint ();
	dmfdaint (); dmfdbint (); dmflint ();
#endif

	/*
	 * Interupt level is 15.  We get to chose our own vector, and then
	 * tell the controller what it is.
	 */
	br = 0x15;
#ifndef EMULEX
	cvec = (uba_hd[numuba].uh_lastiv -= 8 * 4);
	dmf_addr->dmfc_config = cvec >> 2;
#else
	cvec = (uba_hd[numuba].uh_lastiv -= 2 * 4);
	dmf_addr->dmfc_config = (cvec - 020) >> 2;
#endif
	if ((dmf_addr->dmfc_config & 0x8000) == 0) {
		printf("no DMF async flag!?\n");
		return (0);
	}
	dmf_addr->dmfl_ctrl = DMFL_RST;
	return (sizeof (struct dmfdevice));
}

X/*
 * Routine to "attach" a DMF.  Get columns, lines and other device dependent
 * information for the specific device.
 */
dmfattach(ui)
	register struct uba_device *ui;
{
#ifndef EMULEX
	register int cols, lines;

	cols = (ui->ui_flags >> 8) & 0xff;
	lines = (ui->ui_flags >> 16) & 0xff;
	dmfl_softc[ui->ui_unit].sc_cols = (cols == 0 ? DMFL_DCL : cols);
	dmfl_softc[ui->ui_unit].sc_lines = (lines == 0 ? DMFL_DLN : lines);
#endif
#if NDMFO == 0
	dmfsoftCAR[ui->ui_unit] = ui->ui_flags & 0xff;
#else
	dmfsoftCAR[ui->ui_unit] = dmf_flags[ui->ui_unit] =
		ui->ui_flags & 0xff;
#endif
}

X/*
 * Open a DMF32 line, mapping the clist onto the UBA if this is the first
 * DMF on this UBA.  Turn on this DMF if this is the first use of it.
 */
X/* ARGSUSED */
dmfopen(dev, flag)
	dev_t dev;
	int flag;
{
	register struct tty *tp;
	register int unit, ctlr;
	register struct dmfdevice *dmf;
	register struct uba_device *ui;
	int s, bit;

	unit = minor(dev);
#ifndef EMULEX
	if (unit & 0200)	/* printer open request */
		return (dmflopen(dev, flag));
#endif
	ctlr = unit >> 3;
	if (unit >= NDMF * 8 || (ui = dmfinfo[ctlr]) == NULL || !ui->ui_alive)
		return (ENXIO);
	tp = &dmf_tty[unit];
	dmf = (struct dmfdevice *)ui->ui_addr;
	tp->t_addr = (caddr_t)dmf;
	tp->t_oproc = dmfstart;

	/*
	 * While setting up state for this UBA+DMF, block UBA resets which can
	 * clear the state.
	 */
	s = spl5();
	if (dmf_ubinfo[ui->ui_ubanum] == 0) {
		dmf_ubinfo[ui->ui_ubanum] = uballoc(ui->ui_ubanum,
			(caddr_t)cfree, nclist * sizeof (struct cblock), 0);
		cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum] & 0x3ffff;
	}
	bit = 1 << ctlr;
	if ((dmfact & bit) == 0) {
		dmfact |= bit;
		dmf->dmfa_csr |= DMFA_IE;
		dmf->dmfa_sato = SILO_TIME_OUT;
	}
	splx(s);

	/*
	 * If this is first open, initialze tty state to default.
	 */
	if ((tp->t_state&TS_ISOPEN) == 0) {
		ttychars(tp);
		if (tp->t_ispeed == 0) {
			tp->t_ispeed = tp->t_ospeed = B2400;
			tp->t_flags = ODDP | EVENP | ECHO;
		}
		dmfparam(unit);
		dmfa_softc[unit].sc_state = 0;
	}
	else {
#if NDMFO == 0
		if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
			return (EBUSY);
#else
		if ((tp->t_state&TS_XCLUDE || flag < 0) && u.u_uid != 0)
			return (EBUSY);
#endif
	}
	/*
	 * Turn on the line and wait for a carrier.  Carrier tests must be
	 * done with dmfrint held, since carrier transitions look like input.
	 */
#if NDMFO == 0
	if (dmfmctl(dev, DMFA_ON, DMSET) & (DMFA_CAR << 8))
		tp->t_state |= TS_CARR_ON;
	s = spl5();
	while ((tp->t_state&TS_CARR_ON) == 0) {
		tp->t_state |= TS_WOPEN;
		sleep((caddr_t)&tp->t_rawq, TTIPRI);
	}
#else
	bit = 1 << (unit & 7);
	if (flag < 0) {
		dmf_inout[ctlr] |= bit;	/* outgoing mode on */
		dmfsoftCAR[ctlr] |= bit;/* fake carrier on */
	}
	s = spl5();
	for (;;) {		/* keep turning it on */
		if (dmfmctl(dev, DMFA_ON, DMSET) & (DMFA_CAR << 8))
			tp->t_state |= TS_CARR_ON;
		if (tp->t_state&TS_CARR_ON &&
		    ((dmf_inout[ctlr]&bit) == 0 || flag < 0))
			break;
		tp->t_state |= TS_WOPEN;
		sleep((caddr_t)&tp->t_rawq, TTIPRI);
	}
#endif
	splx(s);
	return ((*linesw[tp->t_line].l_open)(dev, tp));
}

X/*
 * Set parameters from open or stty into the DMF hardware registers.
 * Block interrupts so parameters will be set before the line interrupts.
 * If terminal speed is set to 0, hang up on last close, turm modem off
 * and return to caller.
 */
dmfparam(unit)
	register int unit;
{
	register struct tty *tp;
	register struct dmfdevice *dmf;
	register int lparm, lctl;
	int s;

	tp = &dmf_tty[unit];
	dmf = (struct dmfdevice *) tp->t_addr;

	s = spl5();
	if (tp->t_ispeed == 0) {
		tp->t_state |= TS_HUPCLS;
		(void) dmfmctl(unit, DMFA_OFF, DMSET);
		splx(s);
		return;
	}

	/*
	 * Set up line parameters and control info.  Emulex CS21s don't
	 * support split baud rates properly so we just use the output speed.
	 */
#ifndef EMULEX
	lparm = (dmf_speeds[tp->t_ospeed]<<12)|(dmf_speeds[tp->t_ispeed]<<8);
#else
	lparm = dmf_speeds[tp->t_ospeed] << 8;
	lparm |= lparm << 4;
#endif
	lctl = DMFA_LCE;
	if (tp->t_ispeed == B134)
		lparm |= DMFA_6BT | DMFA_PEN;
	else if (tp->t_flags & (RAW|LITOUT))
		lparm |= DMFA_8BT;
	else
		lparm |= DMFA_7BT | DMFA_PEN;
	if (tp->t_flags & EVENP)
		lparm |= DMFA_EPR;
	if (tp->t_ospeed == B110)
		lparm |= DMFA_SCD;

	unit &= 7;
	dmf->dmfa_lparm = lparm | unit;
	dmf->dmfa_csr = DMFA_IE | IR_LCTMR | unit;
	dmf->dmfa_lctmr |= lctl & 0xff;
	splx(s);
}

#if NDMFO > 0
X/*
 * Finish closing a DMF line (after holding DTR low)
 */
dmfpause(tp)
	struct tty *tp;
{

	wakeup((caddr_t)&tp->t_state);
}
#endif

X/*
 * Close a DMF32 line.
 */
dmfclose(dev, flag)
	dev_t dev;
	int flag;
{
	register struct tty *tp;
	register int unit;

	unit = minor(dev);
	tp = &dmf_tty[unit];

#ifndef EMULEX
	if (unit & 0200) {
		dmflclose(dev, flag);
		return;
	}
#endif
	(*linesw[tp->t_line].l_close)(tp);

	/*
	 * un-break, hang-up and close the modem.
	 */
	(void) dmfmctl(unit, DMFA_BRK, DMBIC);
#if NDMFO == 0
	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN) == 0)
		(void) dmfmctl(unit, DMFA_OFF, DMSET);
	ttyclose(tp);
#else
	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN) == 0 ||
	    flag < 0) {
		(void) dmfmctl(unit, DMFA_OFF, DMSET);
		/*
		 * Force DTR to remain low for ~1/2 second
		 */
		timeout(dmfpause, (caddr_t)tp, hz >> 1);
		sleep((caddr_t)&tp->t_state, TTOPRI);
	}
	ttyclose(tp);
	if (flag < 0) {		/* line was open in outgoing mode */
		register int dmf = unit >> 3;
		register int bit = 1 << (unit & 7);

		dmf_inout[dmf] &= ~bit;
		if (dmf_flags[dmf] & bit)	/* restore softCAR */
			dmfsoftCAR[dmf] |= bit;
		else
			dmfsoftCAR[dmf] &= ~bit;
		wakeup((caddr_t)&tp->t_rawq);
	}
#endif NDMFO == 0
}

X/*
 * Reset state of driver if UBA reset was necessary.
 * Reset the csr, lpr, and lctmr registers on open lines,
 * and restart transmitters.
 */
dmfreset(uban)
	int uban;
{
	register int ctlr, unit;
	register struct tty *tp;
	register struct dmfdevice *dmf;
	register struct uba_device *ui;
	register struct dmfa_softc *sc;
	int i;

	/* 
	 * Set up Unibus map registers.
	 */
	if (dmf_ubinfo[uban] == 0)
		return;
	dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
		nclist * sizeof (struct cblock), 0);
	cbase[uban] = dmf_ubinfo[uban] & 0x3ffff;
	for (ctlr = 0; ctlr < NDMF; ctlr++) {
		ui = dmfinfo[ctlr];
		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
			continue;
		printf (" dmf%d", ctlr);
		dmf = (struct dmfdevice *)ui->ui_addr;
		dmf->dmfa_csr |= DMFA_IE;
		dmf->dmfa_sato = SILO_TIME_OUT;
		/* 
		 * For each unit on a dmf controller, if the unit is open
		 * or waiting for open to complete, reset it.
		 */
		unit = ctlr << 3;
		sc = &dmfa_softc[unit];
		tp = &dmf_tty[unit];
		for (i = 0; i < 8; i++) {
			sc->sc_state = 0;
			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
				dmfparam(unit);
				(void) dmfmctl(unit, DMFA_ON, DMSET);
				tp->t_state &= ~TS_BUSY;
				dmfstart(tp);
			}
			sc++, unit++, tp++;
		}
	}
}

X/*
 * Routine to read a dmf32 line.
 */
dmfread(dev, uio)
	dev_t dev;
	struct uio *uio;
{
	register struct tty *tp;

#ifndef EMULEX
	if (minor(dev) & 0200)
		return (ENXIO);
#endif
	tp = &dmf_tty[minor(dev)];
	return ((*linesw[tp->t_line].l_read)(tp, uio));
}

X/*
 * Routine to write to a dmf32 line.
 */
dmfwrite(dev, uio)
	dev_t dev;
	struct uio *uio;
{
	register struct tty *tp;

#ifndef EMULEX
	if (minor(dev) & 0200)
		return (dmflwrite(dev, uio));
#endif
	tp = &dmf_tty[minor(dev)];
	return ((*linesw[tp->t_line].l_write)(tp, uio));
}

X/*
 * Routine to process a DMF32 receiver interrupt.
 */
dmfrint(ctlr)
	int ctlr;
{
	register int c;
	register struct tty *tp, *tp0;
	register struct dmfdevice *dmf;
	register struct uba_device *ui;
	int overrun, unit, s;

	overrun = 0;
	if ((ui = dmfinfo[ctlr]) == NULL || ui->ui_alive == 0)
		return;
	dmf = (struct dmfdevice *)ui->ui_addr;
	tp0 = &dmf_tty[ctlr << 3];

	/*
	 * Loop fetching characters from the silo for this
	 * dmf until there are no more in the silo.
	 */
	while ((c = dmf->dmfa_rbuf) & DMFA_DV) {
		unit = (c >> 8) & 7;
		tp = &tp0[unit];
		if (c & DMFA_DSC) {
			dmfdsc(ctlr, unit, dmf, tp);
			continue;
		}
		if ((tp->t_state&TS_ISOPEN) == 0) {
			wakeup((caddr_t)tp);
			continue;
		}
		if (c & DMFA_PE) {
			if ((tp->t_flags & (EVENP|ODDP)) == EVENP ||
				(tp->t_flags & (EVENP|ODDP)) == ODDP)
			continue;
		}
		if ((c & DMFA_DO) && overrun == 0) {
			printf ("dmf%d: silo overflow\n", ctlr);
			overrun++;
		}
		if (c & DMFA_FE) {
			if (tp->t_flags & RAW)
				c = 0;
			else
				c = tp->t_intrc;
		}
#if NBK > 0
		if (tp->t_line == NETLDISC) {
			c &= 0177;
			BKINPUT(c, tp);
		}
		else
#endif
		(*linesw[tp->t_line].l_rint)(c, tp);
	}
}

X/*
 * Process a carrier state change.  Find out what the real carrier
 * state is; if on, and in use outgoing, clear soft carrier.
 * N.B.: no MDMBUF-style flow control, sorry...
 */
dmfdsc(ctlr, unit, dmf, tp)
	register int ctlr, unit;
	register struct dmfdevice *dmf;
	register struct tty *tp;
{
	int realc, bit;

	bit = 1 << unit;
	dmf->dmfa_csr = DMFA_IE | IR_RMS | unit;
	realc = dmf->dmfa_rms & DMFA_CAR;
	if (realc) {
#if NDMFO > 0
		if (dmf_inout[ctlr] & bit)
			dmfsoftCAR[ctlr] &= ~bit;
#endif
		if ((tp->t_state&TS_CARR_ON) == 0)
			tp->t_state |= TS_CARR_ON;
		wakeup((caddr_t)&tp->t_rawq);
	}
	else {
		if ((dmfsoftCAR[ctlr] & bit) == 0 && tp->t_state&TS_CARR_ON) {
			gsignal(tp->t_pgrp, SIGHUP);
			gsignal(tp->t_pgrp, SIGCONT);
			dmf->dmfa_csr = DMFA_IE | IR_LCTMR | unit;
			dmf->dmfa_lctmr &= (DMFA_OFF << 8) | 0xff;
			ttyflush(tp, FREAD|FWRITE);
			tp->t_state &= ~TS_CARR_ON;
		}
	}
}

X/*
 * Start (restart) transmission on the given DMF32 line.
 */
dmfstart(tp)
	register struct tty *tp;
{
	register struct dmfdevice *dmf;
	register struct dmfa_softc *sc;
	register int unit, nch;
	int ctlr, use_dma, s;

	unit = minor(tp->t_dev);
	ctlr = unit >> 3;
	dmf = (struct dmfdevice *)tp->t_addr;
	sc = &dmfa_softc[unit];
	unit &= 7;
	s = spl5();
	/*
	 * 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 transmitter has been disabled reenable it.
	 * If the transmitter was disabled before the interrupt
	 * (BUSY was still on), then reset the BUSY state and
	 * we will wait for the interrupt.  If !BUSY we already
	 * saw the interrupt so we can start another transmission.
	 */
	if (sc->sc_state & ST_TXOFF) {
		dmf->dmfa_csr = DMFA_IE | IR_LCTMR | unit;
		dmf->dmfa_lctmr |= DMFA_TE;
		sc->sc_state &= ~ST_TXOFF;
		if (sc->sc_state & ST_INBUSY) {
			sc->sc_state &= ~ST_INBUSY;
			tp->t_state |= TS_BUSY;
			goto out;
		}
	}

	/*
	 * If there are sleepers, and output has drained below low
	 * water mark, wake 'em up.
	 */
	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;
		}
	}

	/*
	 * Now restart transmission unless the output queue is empty.
	 */
	if (tp->t_outq.c_cc == 0)
		goto out;
	if (tp->t_flags & (RAW|LITOUT))
		nch = ndqb(&tp->t_outq, 0);
	else {
		/*
		 * If first thing on queue is a delay process it.
		 */
		nch = ndqb(&tp->t_outq, 0200);
		if (nch == 0) {
			nch = getc(&tp->t_outq);
			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f) + 6);
			tp->t_state |= TS_TIMEOUT;
			goto out;
		}
	}

	/*
	 * If characters to transmit, (re)start transmission:
	 * enable transmitter and interrupts and set the mode to busy;
	 * pick DMA or SILO mode based on the number of characters to
	 * transmit and the amount of space left in the silo.
	 * For DMA:
	 *	Calculate the DMA address; load it and the character count
	 *	into the DMF.  Have to wait for the transmit interrupt before
	 *	flushing.
	 * For non DMA:
	 *	Move characters into the silo (in pairs when possible) and
	 *	flush them from the queue.
	 */
	if (nch) {
		dmf->dmfa_csr = DMFA_IE | IR_LCTMR | unit;
		dmf->dmfa_lctmr |= DMFA_TE;
		tp->t_state |= TS_BUSY;
		use_dma = 0;
		if (nch >= DO_DMA_COUNT)
			use_dma++;
		else {
			register int room;

			dmf->dmfa_csr = DMFA_IE | IR_TSC | unit;
			room = DMFA_SIZ - dmf->dmfa_tsc;
			if (room < nch)
				use_dma++;
		}
		if (use_dma) {
			register int car;
	    
			car = UBACVT(tp->t_outq.c_cf, dmfinfo[ctlr]->ui_ubanum);
			sc->sc_count = nch;
			sc->sc_state |= ST_DMA;
			dmf->dmfa_csr = DMFA_IE | IR_TBA | unit;
			dmf->dmfa_tba = car;
			dmf->dmfa_tcc = ((car >> 2) & 0xc000) | nch;
		}
		else {
			sc->sc_state &= ~ST_DMA;
			dmf->dmfa_csr = DMFA_IE | IR_TBUF | unit;
			unit = nch;
#ifdef notdef
			/*
			 * I'm feeling particularly register- and
			 * instruction-thrifty today . . . guess
			 * what this code does!
			 */
			{ register char *cp = tp->t_outq.c_cf;
			  if ((int)cp & 1)
				dmf->dmfa_tbf = *cp++, unit--;
			}
			{ register short *cp;
			  while ((unit -= 2) >= 0)
				dmf->dmfa_tbf2 = *cp++;
			  if (unit & 1)
				dmf->dmfa_tbf = *(char *)cp;
			}
#else
			/*
			 * However, I'm also prepared to be reasonable.
			 */
			{ register short *cp = (short *)tp->t_outq.c_cf;
			  while ((unit -= 2) >= 0)
				dmf->dmfa_tbf2 = *cp++;
			  if (unit & 1)
				dmf->dmfa_tbf = *(char *)cp;
			}
#endif
			ndflush(&tp->t_outq, nch);
		}
	}
out: 
	splx(s);
}

X/*
 * Stop output on a line, e.g. for ^S/^Q or output flush.  Block I/O
 * interrupts (must use spl6(), not spl5(), as the stop routine is
 * called from flushtty() at spl6).  Disable the transmitter.  We must
 * disable the transmitter even if tp->t_state says the terminal is not
 * busy, because in DMA mode, there are characters left in the silo after
 * the controller interrupts with transmit complete.  If flush request
 * (i.e. a non stopped-by-^S request), then flush the silo by setting
 * the appropriate bit.  This will cause a transmit interrupt when the
 * flush is complete so mark it busy as well.  Otherwise, if busy, mark
 * as stopped while busy.
 */
dmfstop(tp)
	register struct tty *tp;
{
	register struct dmfdevice *dmf;
	register struct dmfa_softc *sc;
	register int unit;
	int s;
    
	dmf = (struct dmfdevice *)tp->t_addr;
	unit = minor(tp->t_dev);
	sc = &dmfa_softc[unit];
	s = spl6();
	dmf->dmfa_csr = IR_LCTMR | (unit & 7) | DMFA_IE;
	dmf->dmfa_lctmr &= ~DMFA_TE;
	sc->sc_state |= ST_TXOFF;
	if ((tp->t_state&TS_TTSTOP) == 0) {
		tp->t_state |= TS_FLUSH | TS_BUSY;
		dmf->dmfa_lctmr |= DMFA_FLS;
	}
	else {
		if (tp->t_state&TS_BUSY) {
			sc->sc_state |= ST_INBUSY;
			tp->t_state &= ~TS_BUSY;
		}
	}
	splx(s);
}

X/*
 * Routine to handle a DMF32 transmitter interrupt.
 * Restart the idle line(s).  Clear the TS_BUSY from tp->t_state.
 * Test for DMA error and print error message.
 * SHOULD RESTART OR SOMETHING...
 * Test (& clear) DMA flush bit.  Reenable the transmitter.
 */
dmfxint(ctlr)
	int ctlr;
{
	register struct tty *tp;
	register struct dmfdevice *dmf;
	register int unit, t;
	register struct dmfa_softc *sc;
	int s;

	dmf = (struct dmfdevice *)dmfinfo[ctlr]->ui_addr;
	s = spl5();
	while ((t = dmf->dmfa_csr) & DMFA_TRDY) {
		unit = (t >> 8) & 7;
		unit |= ctlr << 3;
		tp = &dmf_tty[unit];
		sc = &dmfa_softc[unit];
		unit &= 7;
		tp->t_state &= ~TS_BUSY;
		if (t & DMFA_NXM)
			printf("dmf%d: NXM line %d\n", ctlr, unit);
		if (tp->t_state & TS_FLUSH) {
			tp->t_state &= ~TS_FLUSH;
			dmf->dmfa_csr = DMFA_IE | IR_LCTMR | unit;
			dmf->dmfa_lctmr |= DMFA_TE;
		}
		else if (sc->sc_state & ST_DMA)
			ndflush(&tp->t_outq, sc->sc_count);
		sc->sc_state = 0;

		/*
		 * Start (restart) transmission.
		 */
		if (tp->t_line)
			(*linesw[tp->t_line].l_start)(tp);
		else
			dmfstart(tp);
	}
	splx(s);
}

X/*
 * Routine for ioctl for DMF32.
 * Perform line specific ioctl for Berkeley line discipline,
 * and tty ioctl then process any errors.
 */
X/* ARGSUSED */
dmfioctl(dev, cmd, data, flag)
	dev_t dev;
	caddr_t data;
{
	register struct tty *tp;
	register int unit = minor(dev);
	int error;

#ifndef EMULEX
	if (unit & 0200)
		return (ENOTTY);
#endif
	tp = &dmf_tty[unit];
	error = ttioctl(tp, cmd, data, flag);
	if (error >= 0) {
		if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET ||
		    cmd == TIOCLBIS || cmd == TIOCLBIC)
			dmfparam(unit);
		return (error);
	}
	/*
	 * Process line-specific ioctl command.
	 */
	switch (cmd) {

	case TIOCSBRK: 
		(void) dmfmctl(dev, DMFA_BRK, DMBIS);
		break;

	case TIOCCBRK: 
		(void) dmfmctl(dev, DMFA_BRK, DMBIC);
		break;

	case TIOCSDTR: 
		(void) dmfmctl(dev, DMFA_DTR | DMFA_RTS, DMBIS);
		break;

	case TIOCCDTR: 
		(void) dmfmctl(dev, DMFA_DTR | DMFA_RTS, DMBIC);
		break;

	case TIOCMSET: 
		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET);
		break;

	case TIOCMBIS:
		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS);
		break;

	case TIOCMBIC: 
		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC);
		break;

	case TIOCMGET: 
		*(int *)data = dmftodm(dmfmctl(dev, 0, DMGET));
		break;

	default: 
		return (ENOTTY);
	}
	return (0);
}

X/*
 * Routine for DMF32 modem control
 */
dmfmctl(dev, bits, how)
	dev_t dev;
	int bits, how;
{
	register struct dmfdevice *dmf;
	register int unit, modem_status, line_control;
	register int temp;
	int s;

	unit = minor(dev);
	dmf = (struct dmfdevice *)dmf_tty[unit].t_addr;

	/*
	 * Block I/O interrupts.
	 * Get receive modem status, transmit modem status & line control info.
	 */
	s = spl5();
	dmf->dmfa_csr = DMFA_IE | IR_RMS | (unit & 7);
	modem_status = dmf->dmfa_rms << 8;
    
	dmf->dmfa_csr = DMFA_IE | IR_LCTMR | (unit & 7);
	temp = dmf->dmfa_lctmr;
	modem_status |= ((temp >> 8) & (0x1f));
	/*
	 * Fake up a carrier if software carrier is set.
	 */
	if (dmfsoftCAR[unit >> 3] & (1 << (unit & 7)))
		modem_status |= DMFA_CAR << 8;
	line_control = temp & 0x3f;
	if (line_control & DMFA_RBK)
		modem_status |= DMFA_BRK;

	/*
	 * Process modem control commands.
	 */
	switch (how) {

	case DMSET: 
		modem_status = (modem_status & 0xff00) | bits;
		break;

	case DMBIS: 
		modem_status |= bits;
		break;

	case DMBIC: 
		modem_status &= ~bits;
		break;

	case DMGET: 
		(void) splx(s);
		return (modem_status);
	}

	/*
	 * Process the break bit and set up the modem status and line control
	 * information to be replaced in the transmit modem register for the
	 * selected line.
	 */
	if (modem_status & DMFA_BRK)
		line_control |= DMFA_RBK;
	else
		line_control &= ~DMFA_RBK;
	dmf->dmfa_csr = DMFA_IE | IR_LCTMR | (unit & 7);
	dmf->dmfa_lctmr = ((modem_status&0x1f) << 8) | (line_control&0x3f);

	(void) splx(s);
	return (modem_status);
}

X/*
 * Routine to convert modem status from dm to dmf format.
 * Pull bits 1 & 3 through unchanged. If dm secondary transmit bit is set,
 * and/or dm request to send bit is set, and/or dm user modem signal bit
 * is set, set the corresponding dmf bits.
 */
dmtodmf(bits)
	register int bits;
{
	register int b;

	b = bits & 012;
	if (bits & DM_ST)
		b |= DMFA_RAT;
	if (bits & DM_RTS)
		b |= DMFA_RTS;
	if (bits & DM_USR)
		b |= DMFA_USW;
	return (b);
}

X/*
 * Routine to convert modem status from dmf to dm format.
 * Pull bits 1 & 3 through unchanged. Pull bits 11 - 15 through as bits
 * 4 - 8 and set bit 0 to dm line enable.  If dmf user modem signal bit
 * set, and/or dmf request to send bit set, then set the corresponding
 * dm bit also.
 */
dmftodm(bits)
	register int bits;
{
	register int b;

	b = (bits & 012) | ((bits >> 7) & 0760) | DM_LE;
	if (bits & DMFA_USR)
		b |= DM_USR;
	if (bits & DMFA_RTS)
		b |= DM_RTS;
	return (b);
}

#ifndef EMULEX
X/*
 * Routine to open the line printer port on a dmf32
 */
dmflopen(dev, flag)
	dev_t dev;
	int flag;
{
	register int ctlr = minor(dev) & 7;
	register struct dmfl_softc *sc;
	register struct uba_device *ui;
	register struct dmfdevice *dmf;

	if (ctlr >= NDMF || (ui = dmfinfo[ctlr]) == 0 || ui->ui_alive == 0)
		return (ENXIO);
	sc = &dmfl_softc[ctlr];
	if (sc->sc_state & OPEN)
		return (EBUSY);	/* none of this ENXIO trash, please! */
	dmf = (struct dmfdevice *)ui->ui_addr;
	if (dmf->dmfl_ctrl & DMFL_OFL) {
		/* printf("dmf: line printer offline/jammed\n"); */
		return (EIO);
	}
	if (dmf->dmfl_ctrl & DMFL_CNV) {
		printf("dmf: line printer disconnected\n");
		return (EIO);
	}
	dmf->dmfl_ctrl = 0;
	sc->sc_state |= OPEN;
	return (0);
}

X/*
 * Routine to close the line printer part of a dmf32.
 */
dmflclose(dev, flag)
	dev_t dev;
	int flag;
{
	register int ctlr = minor(dev) & 7;
	register struct dmfl_softc *sc;
	register struct uba_device *ui;

	dmflout(dev, "\f", 1);
	ui = dmfinfo[ctlr];
	sc = &dmfl_softc[ctlr];
	sc->sc_state = 0;
	if (sc->sc_info)
		ubarelse(ui->ui_ubanum, &sc->sc_info);
	((struct dmfdevice *)ui->ui_addr)->dmfl_ctrl = 0;
	return (0);
}

X/*
 * Routine to write to the line printer part of a dmf32.
 */
dmflwrite(dev, uio)
	dev_t dev;
	register struct uio *uio;
{
	register int n, error = 0;
	register struct dmfl_softc *sc = &dmfl_softc[minor(dev) & 7];

	if (sc->sc_state & ERROR)
		return (EIO);
	while ((n = uio->uio_resid) > 0) {
		if (n > DMFL_SIZ) {
			n = DMFL_SIZ;
			sc->sc_state |= MORETODO;
		}
		else
			sc->sc_state &= ~MORETODO;
		error = uiomove(sc->sc_buf, n, UIO_WRITE, uio);
		if (error)
			break;
		error = dmflout(dev, sc->sc_buf, n);
		if (error)
			break;
	}
	return (error);
}

X/*
 * Routine to start I/O operation to DMF line printer.
 * ``cp'' is ptr to ``n'' chars (in kernel space) to be sent.
 * DMF will be put in formatted output mode; this can be made
 * selectable from an ioctl if the need ever arises.
 */
#define DMFL_OPTIONS ((1 << 8) | (1 << 9) | (1 << 15))
		/* auto cr, use real ff, no ul conversion */

dmflout(dev, cp, n)
	dev_t dev;
	char *cp;
	int n;
{
	register struct dmfl_softc *sc;
	register int ctlr = minor(dev) & 7;
	register struct uba_device *ui;
	register struct dmfdevice *d;
	register unsigned info;
	int s;

	sc = &dmfl_softc[ctlr];
	if (sc->sc_state & ERROR)
		return (EIO);
	ui = dmfinfo[ctlr];

	/*
	 * Allocate UNIBUS resources, if needed
	 */
	if (sc->sc_info == 0)
		sc->sc_info = uballoc(ui->ui_ubanum, cp, n, 0);
	info = sc->sc_info;
	d = (struct dmfdevice *)ui->ui_addr;
	d->dmfl_ctrl = (2 << 8) | DMFL_FMT;	/* indir reg 2 */

	/*
	 * indir reg auto increments on r/w . . .
	 * SO DON'T CHANGE THE ORDER OF THIS CODE!
	 */
	d->dmfl_indrct = 0;		/* prefix chars & num */
	d->dmfl_indrct = 0;		/* suffix chars & num */
	d->dmfl_indrct = info;		/* dma lo 16 bits address */
	d->dmfl_indrct = -n;		/* number of chars, 2's complement */
	d->dmfl_indrct = ((info>>16) & 3) | DMFL_OPTIONS;/* dma hi, opts */
	d->dmfl_indrct = sc->sc_lines | (sc->sc_cols << 8);
					/* page length, width */
	sc->sc_state |= ASLP;
	s = spl5();
	d->dmfl_ctrl |= DMFL_PEN | DMFL_IE;
	while (sc->sc_state & ASLP) {
		sleep((caddr_t)sc->sc_buf, PZERO + 8);
		while (sc->sc_state & ERROR) {
			timeout(dmflint, ctlr, 10 * hz);
			sleep((caddr_t)&sc->sc_state, PZERO + 8);
		}
		/* if (sc->sc_state & ERROR) return (EIO); */
	}
	splx(s);
	return (0);
}

X/*
 * Routine to handle an interrupt from the line printer part of the dmf32
 */
dmflint(ctlr)
	int ctlr;
{
	register struct uba_device *ui = dmfinfo[ctlr];
	register struct dmfl_softc *sc = &dmfl_softc[ctlr];
	register struct dmfdevice *d;

	d = (struct dmfdevice *)ui->ui_addr;
	d->dmfl_ctrl &= ~DMFL_IE;
	if (sc->sc_state & ERROR) {
		printf("dmfl: intr while in error state\n");
		if ((d->dmfl_ctrl & DMFL_OFL) == 0)
			sc->sc_state &= ~ERROR;
		wakeup((caddr_t)&sc->sc_state);
		return;
	}
	if (d->dmfl_ctrl & DMFL_DER)
		printf("dmf: NXM\n");
	if (d->dmfl_ctrl & DMFL_OFL) {
		printf("dmf: printer error\n");
		sc->sc_state |= ERROR;
	}
#ifdef notdef
	if (d->dmfl_ctrl & DMFL_PDN) {
		printf("bytes= %d\n", d->dmfl_indrct);
		printf("lines= %d\n", d->dmfl_indrct);
	}
#endif
	sc->sc_state &= ~ASLP;
	wakeup((caddr_t)sc->sc_buf);
	if (sc->sc_info && (sc->sc_state & MORETODO) == 0)
		ubarelse(ui->ui_ubanum, &sc->sc_info);
}

X/*
 * NON-SUPPORTED INTERFACES...Parallel and synchronous
 */

X/*
 * Interrupt routine for parallel interface, not yet supported
 */
dmfdaint()
{

	printf("dmfdaint\n"); 
}

X/*
 * Interrupt routine for parallel interface, not yet supported
 */
dmfdbint()
{

	printf("dmfdbint\n"); 
}

X/*
 * Interrupt routine for synchronous interface, not yet supported
 */
dmfsrint()
{

	printf("dmfsrint\n"); 
}

X/*
 * interrupt routine for synchronous interface, not yet supported
 */
dmfsxint()
{

	printf("dmfsxint\n"); 
}
#endif not EMULEX
#endif NDMF > 0
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 dmf.c
	/bin/echo -n '	'; /bin/ls -ld dmf.c
fi
/bin/echo 'Extracting dmfo.c'
sed 's/^X//' <<'//go.sysin dd *' >dmfo.c
X/* $Header: /usr/sys/vaxuba/RCS/dmfo.c,v 1.1 84/09/12 01:31:20 james Exp $ */

#include "dmf.h"
#if NDMF > 0
#include "dmfo.h"
#if NDMFO > 0
X/*
 * DMF-11 ``outgoing mode'' driver
 *
 * Requires hooks in dmf.c
 */
#include "../h/types.h"

X/*
 * Open a DMF32 line in outgoing mode
 */
X/*ARGSUSED*/
dmfoopen(dev, flag)
	dev_t dev;
{
	return (dmfopen(dev, -1));
}

X/*
 * Close a DMF32 outgoing mode line
 */
X/*ARGSUSED*/
dmfoclose(dev, flag)
	dev_t dev;
{
	dmfclose(dev, -1);
}
#endif NDMFO > 0
#endif NDMF > 0
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 664 dmfo.c
	/bin/echo -n '	'; /bin/ls -ld dmfo.c
fi
/bin/echo 'Extracting dmfreg.h'
sed 's/^X//' <<'//go.sysin dd *' >dmfreg.h
X/*
 * dmfreg.h
 *
 * DMF32 register definitions.
 *
 *  "dmfc" refers to the dmf32 as a whole,
 *  "dmfa" refers to the async portion of the dmf32,
 *  "dmfs" refers to the sync portion of the dmf32,
 *  "dmfd" refers to the dr11 portion of the dmf32, and
 *  "dmfl" to the lp portion of the dmf32.
 *
 * (ro) - read only
 * (wo) - write only
 */

X/*
 * dmf32 control register definitions
 */
struct dmfdevice {
	short	dmfc_config;	/* configuration control status reg. */
	short	dmfc_maint;	/* diagnostic control status register */
	short	dmfs_receive;	/* synchronous receive register */
	short	dmfs_xmit;	/* synchronous transmit register */
	short	dmfs_misc;	/* synchronous miscellaneous register */
	short	dmfs_indrct;	/* synchronous indirect register */
	short	dmfa_csr;	/* asynch. control status register */
	short	dmfa_lparm;	/* asynch. line parameter register */
	short	dmfa_rbuf;	/* asynch. receive buffer register */
	union {
		u_short	word;		/* word */
		u_char	bytes[2];	/* bytes */
	} dmfa_ir;		/* indirect register */
	short	dmfl_ctrl;	/* line printer control register */
	short	dmfl_indrct;	/* line printer indirect register */
	short	dmfd_ctrl;	/* dr11 control register */
	short	dmfd_outbuf;	/* dr11 output buffer register */
	short	dmfd_inbuf;	/* dr11 input buffer register */
	short	dmfd_indrct;	/* dr11 indirect register */
};

#define dmfa_sato dmfa_rbuf	/* receive silo alarm timeout (wo) */

X/*
 * aliases for asynchronous indirect control registers
 */
#define IR_TBUF		000	/* transmit buffer register (wo)*/
#define	IR_RMS		000	/* recieve modem status register (ro)*/
#define	IR_TSC		000	/* transmit silo count register (ro)*/
#define IR_LCTMR	010	/* line control and transmit modem */
#define IR_TBA		020	/* trans. buf. addr register */
#define IR_TCC		030	/* transmit char. count */

#define dmfa_tbf	dmfa_ir.bytes[0]	/* transmit buffer (wo) */
#define dmfa_tbf2	dmfa_ir.word		/* tb for 2 chars. (wo) */

#define dmfa_rms	dmfa_ir.bytes[1]	/* receive modem status (ro) */
#define dmfa_tsc	dmfa_ir.bytes[0]	/* transmit silo count (ro) */

#define dmfa_lctmr	dmfa_ir.word	/* line control and transmit modem */

#define dmfa_tba	dmfa_ir.word	/* transmit buffer address */

#define dmfa_tcc	dmfa_ir.word	/* transmit character count */

X/*
 * bits in dmfc_config register
 */
#define dmfc_flg	0100000	/* Asynch.flag */

X/*
 * bits in dmfa_csr register
 */
#define DMFA_TRDY 	0100000	/* transmit ready */
#define DMFA_TIE  	0040000	/* transmit interrupt enable */
#define DMFA_NXM  	0030000	/* non-existant memory */
#define DMFA_LIN  	0003400	/* transmit line number */
#define DMFA_RRDY 	0000200	/* receiver data available */
#define DMFA_RIE  	0000100	/* receiver interrupt enable */
#define DMFA_RESET	0000040	/* master reset */
#define DMFA_IAD  	0000037	/* indirect address register */

#define DMFA_SIZ	32	/* size of output silo (per line) */
#define DMFA_IE		(DMFA_TIE|DMFA_RIE)

X/*
 * bits in dmfa_lparm register
 */
#define DMFA_6BT	0010	 /* 6 bits per character */
#define DMFA_7BT	0020	 /* 7 bits per character */
#define DMFA_8BT	0030	 /* 8 bits per character */
#define DMFA_PEN	0040	 /* parity enable */
#define DMFA_EPR	0100	 /* even parity */
#define DMFA_SCD	0200	 /* stop code */
#define DMFA_XTE	0170000	 /* transmit rate */
#define DMFA_RRT	0007400	 /* receive rate */
#define DMFA_LSL	0000007	 /* line select */

X/*
 * baud rates
 */
#define BR_50		000
#define BR_75		001
#define BR_110		002
#define BR_134_5	003
#define BR_150		004
#define BR_300		005
#define BR_600		006
#define BR_1200		007
#define BR_1800		010
#define BR_2000		011
#define BR_2400		012
#define BR_3600		013
#define BR_4800		014
#define BR_7200		015
#define BR_9600		016
#define BR_19200	017

X/*
 * bits in dmfa_rbuf register
 */
#define DMFA_DSC	0004000	/* data set change */
#define DMFA_PE		0010000	/* parity error */
#define DMFA_FE		0020000	/* framing error */
#define DMFA_DO		0040000	/* data overrun */
#define DMFA_DV		0100000	/* data valid */
#define DMFA_RL		0003400	/* line */
#define DMFA_RD		0000377	/* data */
#define DMFA_AT		0000377	/* alarm timeout */

X/*
 * bits in dmfa_rms register (i.e., dmfa_rmstsc >> 8)
 */
#define DMFA_USR	0004	/* user modem signal (pin 25) */
#define DMFA_SR		0010	/* secondary receive */
#define DMFA_CTS	0020	/* clear to send */
#define DMFA_CAR	0040	/* carrier detect */
#define DMFA_RNG	0100	/* ring */
#define DMFA_DSR	0200	/* data set ready */

X/*
 * bits in dmfa_tms register
 */
#define DMFA_USW	0001	/* user modem signal (pin 18) */
#define DMFA_DTR	0002	/* data terminal ready */
#define DMFA_RAT	0004	/* data signal rate select */
#define DMFA_ST		0010	/* secondary transmit */
#define DMFA_RTS	0020	/* request to send */
#define DMFA_BRK	0040	/* pseudo break bit */
#define DMFA_PMT	0200	/* preempt output */

#define DMFA_ON		(DMFA_DTR|DMFA_RTS)
#define DMFA_OFF	0

X/*
 * bits in dmfa_lcr register
 */
#define DMFA_MIE	0040	/* modem interrupt enable */
#define DMFA_FLS	0020	/* flush transmit silo */
#define DMFA_RBK	0010	/* real break bit */
#define DMFA_RE		0004	/* receive enable */
#define DMFA_AUT	0002	/* auto XON/XOFF */
#define DMFA_TE		0001	/* transmit enable */
#define DMFA_CF		0300	/* control function */

#define DMFA_LCE	(DMFA_MIE|DMFA_RE|DMFA_TE)

X/*
 * bits in dmfa_tcc register
 */
#define DMFA_HA		0140000	/* high address bits */

X/*
 * bits in dm lsr, copied from dh.c
 */
#define DM_USR		0001000	/* usr modem sig, not a real DM bit */
#define DM_DSR		0000400	/* data set ready, not a real DM bit */
#define DM_RNG		0000200	/* ring */
#define DM_CAR		0000100	/* carrier detect */
#define DM_CTS		0000040	/* clear to send */
#define DM_SR		0000020	/* secondary receive */
#define DM_ST		0000010	/* secondary transmit */
#define DM_RTS		0000004	/* request to send */
#define DM_DTR		0000002	/* data terminal ready */
#define DM_LE		0000001	/* line enable */

X/*
 * bits in the line printer control registers
 */
#define DMFL_PEN	0000001	/* print enable */
#define DMFL_RST	0000002	/* master reset */
#define DMFL_FMT	0000004	/* format control */
#define DMFL_xx1	0000030	/* unused */
#define DMFL_MNT	0000040	/* mainenance mode on */
#define DMFL_IE		0000100	/* intr enable */
#define DMFL_PDN	0000200	/* print done bit */
#define DMFL_IDR	0003400	/* indirect reg */
#define DMFL_xx2	0004000	/* unused */
#define DMFL_CNV	0010000	/* connect verify */
#define DMFL_DVR	0020000	/* davfu ready */
#define DMFL_OFL	0040000	/* printer offline */
#define DMFL_DER	0100000	/* dma error bit */
#define DMFL_SIZ	512	/* max chars per dma */
#define DMFL_DCL	132	/* default # of cols/line */
#define DMFL_DLN	66	/* default # of lines/page */
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 dmfreg.h
	/bin/echo -n '	'; /bin/ls -ld dmfreg.h
fi
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland