xref: /csrg-svn/sys/vax/uba/dmf.c (revision 9772)
1*9772Ssam /*	dmf.c	4.16	82/12/17	*/
26940Ssam 
36940Ssam #include "dmf.h"
46940Ssam #if NDMF > 0
56940Ssam /*
66940Ssam  * DMF32 driver
76940Ssam  *
86940Ssam  * TODO:
96940Ssam  *	test with modem
106940Ssam  *	load as much as possible into silo
116940Ssam  *	get correct numbers for receive silo parameter timeout
126940Ssam  *	use auto XON/XOFF
136940Ssam  *	test reset code
146940Ssam  *	test with more than one unit
156940Ssam  *	optimize for efficient DMA and dynamically
166940Ssam  *	  decide between silo and DMA mode
176940Ssam  */
18*9772Ssam #include "../machine/pte.h"
19*9772Ssam 
206940Ssam #include "bk.h"
216940Ssam #include "../h/param.h"
226940Ssam #include "../h/conf.h"
236940Ssam #include "../h/dir.h"
246940Ssam #include "../h/user.h"
259550Ssam #include "../h/ioctl.h"
266940Ssam #include "../h/tty.h"
276940Ssam #include "../h/map.h"
286940Ssam #include "../h/buf.h"
296940Ssam #include "../h/vm.h"
306940Ssam #include "../h/bk.h"
316940Ssam #include "../h/clist.h"
326940Ssam #include "../h/file.h"
337726Sroot #include "../h/uio.h"
346940Ssam 
358473Sroot #include "../vaxuba/ubareg.h"
368473Sroot #include "../vaxuba/ubavar.h"
378473Sroot 
386940Ssam /*
396940Ssam  * Definition of the driver for the auto-configuration program.
406940Ssam  */
416940Ssam int	dmfprobe(), dmfattach(), dmfrint(), dmfxint();
426940Ssam struct	uba_device *dmfinfo[NDMF];
436940Ssam u_short	dmfstd[] = { 0 };
446940Ssam struct	uba_driver dmfdriver =
456940Ssam 	{ dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
466940Ssam 
476940Ssam /*
486940Ssam  * In this driver, "dmf" (unqualified) refers to the async portion
496940Ssam  * of the dmf32, "dmfc" to the combo portion, "dmfs" to the sync
506940Ssam  * portion, "dmfl" to the lp portion, and "dmfd" to the dr portion.
516940Ssam  */
526940Ssam struct dmfdevice
536940Ssam {
546940Ssam 	short	dmfccsr0;		/* combo csr 0 */
556940Ssam 	short	dmfccsr1;		/* combo csr 1 */
566940Ssam 	short	dmfs[4];
576940Ssam 	short	dmfcsr;			/* control-status register */
586940Ssam 	short	dmflpr;			/* line parameter register */
596940Ssam 	short	dmfrbuf;		/* receiver buffer (ro) */
606940Ssam 	union {
616940Ssam 		u_short	dmfirw;		/* indirect register word */
626940Ssam 		u_char	dmfirc[2];	/*    "         "    bytes */
636940Ssam 	} dmfun;
646940Ssam 	short	dmfl[2];
656940Ssam 	short	dmfd[4];
666940Ssam };
676940Ssam 
686940Ssam #define	dmfrsp	dmfrbuf		/* receive silo parameter register (wo) */
696940Ssam #define	dmftbuf	dmfun.dmfirc[0]	/* transmit buffer */
706940Ssam #define	dmftsc	dmfun.dmfirc[0]	/* transmit silo count */
716940Ssam #define	dmfrms	dmfun.dmfirc[1]	/* receive modem status */
726940Ssam #define	dmflcr	dmfun.dmfirc[0]	/* line control register */
736940Ssam #define	dmftms	dmfun.dmfirc[1]	/* transmit modem status */
746940Ssam #define	dmftba	dmfun.dmfirw	/* transmit buffer address */
756940Ssam #define	dmftcc	dmfun.dmfirw	/* transmit character count */
766940Ssam 
776940Ssam /* bits in dmfcsr */
786940Ssam #define	DMF_TI	0100000		/* transmit interrupt */
796940Ssam #define	DMF_TIE	0040000		/* transmit interrupt enable */
806940Ssam #define	DMF_NXM	0020000		/* non-existant memory */
816940Ssam #define	DMF_LIN	0003400		/* transmit line number */
826940Ssam #define	DMF_RI	0000200		/* receiver interrupt */
836940Ssam #define	DMF_RIE	0000100		/* receiver interrupt enable */
846940Ssam #define	DMF_CLR	0000040		/* master reset */
856940Ssam #define	DMF_IAD	0000037		/* indirect address register */
866940Ssam 
876940Ssam #define	DMFIR_TBUF	000	/* select tbuf indirect register */
886940Ssam #define	DMFIR_LCR	010	/* select lcr indirect register */
896940Ssam #define	DMFIR_TBA	020	/* select tba indirect register */
906940Ssam #define	DMFIR_TCC	030	/* select tcc indirect register */
916940Ssam 
926940Ssam /* bits in dmflpr */
936940Ssam #define	BITS6	(01<<3)
946940Ssam #define	BITS7	(02<<3)
956940Ssam #define	BITS8	(03<<3)
966940Ssam #define	TWOSB	0200
976940Ssam #define	PENABLE	040
986940Ssam /* DEC manuals incorrectly say this bit causes generation of even parity. */
996940Ssam #define	OPAR	0100
1006940Ssam 
1016940Ssam #define	DMF_IE	(DMF_TIE|DMF_RIE)
1026940Ssam 
1036940Ssam #define	DMF_SILOCNT	32		/* size of DMF output silo (per line) */
1046940Ssam 
1056940Ssam /* bits in dmfrbuf */
1066940Ssam #define	DMF_DSC		0004000		/* data set change */
1076940Ssam #define	DMF_PE		0010000		/* parity error */
1086940Ssam #define	DMF_FE		0020000		/* framing error */
1096940Ssam #define	DMF_DO		0040000		/* data overrun */
1106940Ssam 
1116940Ssam /* bits in dmfrms */
1126940Ssam #define	DMF_USRR	0004		/* user modem signal (pin 25) */
1136940Ssam #define	DMF_SR		0010		/* secondary receive */
1146940Ssam #define	DMF_CTS		0020		/* clear to send */
1156940Ssam #define	DMF_CAR		0040		/* carrier detect */
1166940Ssam #define	DMF_RNG		0100		/* ring */
1176940Ssam #define	DMF_DSR		0200		/* data set ready */
1186940Ssam 
1196940Ssam /* bits in dmftms */
1206940Ssam #define	DMF_USRW	0001		/* user modem signal (pin 18) */
1216940Ssam #define	DMF_DTR		0002		/* data terminal ready */
1226940Ssam #define	DMF_RATE	0004		/* data signal rate select */
1236940Ssam #define	DMF_ST		0010		/* secondary transmit */
1246940Ssam #define	DMF_RTS		0020		/* request to send */
1256940Ssam #define	DMF_BRK		0040		/* pseudo break bit */
1266940Ssam #define	DMF_PREEMPT	0200		/* preempt output */
1276940Ssam 
1286940Ssam /* flags for modem control */
1296940Ssam #define	DMF_ON	(DMF_DTR|DMF_RTS)
1306940Ssam #define	DMF_OFF	0
1316940Ssam 
1326940Ssam /* bits in dmflcr */
1336940Ssam #define	DMF_MIE		0040		/* modem interrupt enable */
1346940Ssam #define	DMF_FLUSH	0020		/* flush transmit silo */
1356940Ssam #define	DMF_RBRK	0010		/* real break bit */
1366940Ssam #define	DMF_RE		0004		/* receive enable */
1376940Ssam #define	DMF_AUTOX	0002		/* auto XON/XOFF */
1386940Ssam #define	DMF_TE		0001		/* transmit enable */
1396940Ssam 
1406940Ssam #define	DMFLCR_ENA	(DMF_MIE|DMF_RE|DMF_TE)
1416940Ssam 
1426940Ssam /* bits in dm lsr, copied from dh.c */
1436940Ssam #define	DML_USR		0001000		/* usr modem sig, not a real DM bit */
1446940Ssam #define	DML_DSR		0000400		/* data set ready, not a real DM bit */
1456940Ssam #define	DML_RNG		0000200		/* ring */
1466940Ssam #define	DML_CAR		0000100		/* carrier detect */
1476940Ssam #define	DML_CTS		0000040		/* clear to send */
1486940Ssam #define	DML_SR		0000020		/* secondary receive */
1496940Ssam #define	DML_ST		0000010		/* secondary transmit */
1506940Ssam #define	DML_RTS		0000004		/* request to send */
1516940Ssam #define	DML_DTR		0000002		/* data terminal ready */
1526940Ssam #define	DML_LE		0000001		/* line enable */
1536940Ssam 
1546940Ssam /*
1556940Ssam  * Local variables for the driver
1566940Ssam  */
1576940Ssam char	dmf_speeds[] =
1586940Ssam 	{ 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 };
1596940Ssam 
1606940Ssam struct	tty dmf_tty[NDMF*8];
1616940Ssam char	dmfsoftCAR[NDMF];
1628778Sroot #ifndef lint
1638778Sroot int	ndmf = NDMF*8;			/* used by iostat */
1648778Sroot #endif
1656940Ssam int	dmfact;				/* mask of active dmf's */
1666940Ssam int	dmfstart(), ttrstrt();
1676940Ssam 
1686940Ssam #ifdef DMFDMA
1696940Ssam /*
1706940Ssam  * The clist space is mapped by the driver onto each UNIBUS.
1716940Ssam  * The UBACVT macro converts a clist space address for unibus uban
1726940Ssam  * into an i/o space address for the DMA routine.
1736940Ssam  */
1746940Ssam int	dmf_ubinfo[MAXNUBA];		/* info about allocated unibus map */
1756940Ssam static int cbase[MAXNUBA];		/* base address in unibus map */
1766940Ssam #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
1776940Ssam #endif
1786940Ssam 
1796940Ssam /*
1806940Ssam  * Routine for configuration to set dmf interrupt.
1816940Ssam  */
1826940Ssam /*ARGSUSED*/
1836940Ssam dmfprobe(reg, ctlr)
1846940Ssam 	caddr_t reg;
1856940Ssam 	int ctlr;
1866940Ssam {
1876940Ssam 	register int br, cvec;		/* these are ``value-result'' */
1886940Ssam 	register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg;
1896940Ssam 
1906940Ssam #ifdef lint
1916940Ssam 	br = 0; cvec = br; br = cvec;
1928808Sroot 	dmfxint(0); dmfrint(0);
1938808Sroot 	dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint();
1946940Ssam #endif
1956940Ssam 	br = 0x15;
1966940Ssam 	cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
1976940Ssam 	dmfaddr->dmfccsr0 = cvec >> 2;
1986940Ssam 	/* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */
1997412Skre 	return (sizeof (struct dmfdevice));
2006940Ssam }
2016940Ssam 
2026940Ssam /*
2036940Ssam  * Routine called to attach a dmf.
2046940Ssam  */
2056940Ssam dmfattach(ui)
2066940Ssam 	struct uba_device *ui;
2076940Ssam {
2086940Ssam 
2096940Ssam 	dmfsoftCAR[ui->ui_unit] = ui->ui_flags;
2106940Ssam }
2116940Ssam 
2126940Ssam 
2136940Ssam /*
2146940Ssam  * Open a DMF32 line, mapping the clist onto the uba if this
2156940Ssam  * is the first dmf on this uba.  Turn on this dmf if this is
2166940Ssam  * the first use of it.
2176940Ssam  */
2186940Ssam /*ARGSUSED*/
2196940Ssam dmfopen(dev, flag)
2206940Ssam 	dev_t dev;
2216940Ssam {
2226940Ssam 	register struct tty *tp;
2236940Ssam 	register int unit, dmf;
2246940Ssam 	register struct dmfdevice *addr;
2256940Ssam 	register struct uba_device *ui;
2266940Ssam 	int s;
2276940Ssam 
2286940Ssam 	unit = minor(dev);
2296940Ssam 	dmf = unit >> 3;
2308567Sroot 	if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0)
2318567Sroot 		return (ENXIO);
2326940Ssam 	tp = &dmf_tty[unit];
2338567Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
2348567Sroot 		return (EBUSY);
2356940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
2366940Ssam 	tp->t_addr = (caddr_t)addr;
2376940Ssam 	tp->t_oproc = dmfstart;
2386971Ssam 	tp->t_state |= TS_WOPEN;
2396940Ssam 	/*
2406940Ssam 	 * While setting up state for this uba and this dmf,
2416940Ssam 	 * block uba resets which can clear the state.
2426940Ssam 	 */
2436940Ssam 	s = spl5();
2446940Ssam #ifdef DMFDMA
2456940Ssam 	if (dmf_ubinfo[ui->ui_ubanum] == 0) {
2466940Ssam 		dmf_ubinfo[ui->ui_ubanum] =
2476940Ssam 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
2486940Ssam 			nclist*sizeof(struct cblock), 0);
2496940Ssam 		cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff;
2506940Ssam 	}
2516940Ssam #endif
2526940Ssam 	if ((dmfact&(1<<dmf)) == 0) {
2536940Ssam 		addr->dmfcsr |= DMF_IE;
2546940Ssam 		dmfact |= (1<<dmf);
2556940Ssam 		addr->dmfrsp = 1;	/* DON'T KNOW WHAT TO SET IT TO YET */
2566940Ssam 	}
2576940Ssam 	splx(s);
2586940Ssam 	/*
2596940Ssam 	 * If this is first open, initialze tty state to default.
2606940Ssam 	 */
2616971Ssam 	if ((tp->t_state&TS_ISOPEN) == 0) {
2626940Ssam 		ttychars(tp);
2636940Ssam 		if (tp->t_ispeed == 0) {
2646940Ssam 			tp->t_ispeed = B300;
2656940Ssam 			tp->t_ospeed = B300;
2666940Ssam 			tp->t_flags = ODDP|EVENP|ECHO;
2676940Ssam 		}
2686940Ssam 		dmfparam(unit);
2696940Ssam 	}
2706940Ssam 	/*
2716940Ssam 	 * Wait for carrier, then process line discipline specific open.
2726940Ssam 	 */
2736940Ssam 	if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) ||
2746940Ssam 	    (dmfsoftCAR[dmf] & (1<<(unit&07))))
2756971Ssam 		tp->t_state |= TS_CARR_ON;
2766940Ssam 	s = spl5();
2776971Ssam 	while ((tp->t_state & TS_CARR_ON) == 0) {
2786971Ssam 		tp->t_state |= TS_WOPEN;
2796940Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
2806940Ssam 	}
2816940Ssam 	splx(s);
2828567Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
2836940Ssam }
2846940Ssam 
2856940Ssam /*
2866940Ssam  * Close a DMF32 line.
2876940Ssam  */
2886940Ssam /*ARGSUSED*/
2896940Ssam dmfclose(dev, flag)
2906940Ssam 	dev_t dev;
2916940Ssam 	int flag;
2926940Ssam {
2936940Ssam 	register struct tty *tp;
2946940Ssam 	register unit;
2956940Ssam 
2966940Ssam 	unit = minor(dev);
2976940Ssam 	tp = &dmf_tty[unit];
2986940Ssam 	(*linesw[tp->t_line].l_close)(tp);
2998702Sroot 	(void) dmfmctl(unit, DMF_BRK, DMBIC);
3006971Ssam 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
3018702Sroot 		(void) dmfmctl(unit, DMF_OFF, DMSET);
3026940Ssam 	ttyclose(tp);
3036940Ssam }
3046940Ssam 
3057726Sroot dmfread(dev, uio)
3066940Ssam 	dev_t dev;
3077726Sroot 	struct uio *uio;
3086940Ssam {
3096940Ssam 	register struct tty *tp;
3106940Ssam 
3116940Ssam 	tp = &dmf_tty[minor(dev)];
3127726Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
3136940Ssam }
3146940Ssam 
3157832Sroot dmfwrite(dev, uio)
3166940Ssam 	dev_t dev;
3177832Sroot 	struct uio *uio;
3186940Ssam {
3196940Ssam 	register struct tty *tp;
3206940Ssam 
3216940Ssam 	tp = &dmf_tty[minor(dev)];
3228530Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
3236940Ssam }
3246940Ssam 
3256940Ssam /*
3266940Ssam  * DMF32 receiver interrupt.
3276940Ssam  */
3286940Ssam dmfrint(dmf)
3296940Ssam 	int dmf;
3306940Ssam {
3316940Ssam 	register struct tty *tp;
3326940Ssam 	register c;
3336940Ssam 	register struct dmfdevice *addr;
3346940Ssam 	register struct tty *tp0;
3356940Ssam 	register struct uba_device *ui;
3366940Ssam 	int overrun = 0;
3376940Ssam 
3386940Ssam 	ui = dmfinfo[dmf];
3396940Ssam 	if (ui == 0 || ui->ui_alive == 0)
3406940Ssam 		return;
3416940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
3426940Ssam 	tp0 = &dmf_tty[dmf<<3];
3436940Ssam 	/*
3446940Ssam 	 * Loop fetching characters from the silo for this
3456940Ssam 	 * dmf until there are no more in the silo.
3466940Ssam 	 */
3476940Ssam 	while ((c = addr->dmfrbuf) < 0) {
3486940Ssam 		tp = tp0 + ((c>>8)&07);
3496940Ssam 		if (c & DMF_DSC) {
3506940Ssam 			addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07);
3516940Ssam 			if (addr->dmfrms & DMF_CAR) {
3526971Ssam 				if ((tp->t_state & TS_CARR_ON) == 0) {
3536940Ssam 					wakeup((caddr_t)&tp->t_rawq);
3546971Ssam 					tp->t_state |= TS_CARR_ON;
3556940Ssam 				}
3566940Ssam 			} else {
3576971Ssam 				if (tp->t_state & TS_CARR_ON) {
3586940Ssam 					gsignal(tp->t_pgrp, SIGHUP);
3596940Ssam 					gsignal(tp->t_pgrp, SIGCONT);
3606940Ssam 					addr->dmfcsr = DMF_IE | DMFIR_LCR |
3616940Ssam 						((c>>8)&07);
3626940Ssam 					addr->dmftms = 0;
3636940Ssam 					flushtty(tp, FREAD|FWRITE);
3646940Ssam 				}
3656971Ssam 				tp->t_state &= ~TS_CARR_ON;
3666940Ssam 			}
3676940Ssam 			continue;
3686940Ssam 		}
3696971Ssam 		if ((tp->t_state&TS_ISOPEN)==0) {
3706940Ssam 			wakeup((caddr_t)tp);
3716940Ssam 			continue;
3726940Ssam 		}
3736940Ssam 		if (c & DMF_PE)
3746940Ssam 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
3756940Ssam 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
3766940Ssam 				continue;
3776940Ssam 		if ((c & DMF_DO) && overrun == 0) {
3786940Ssam 			printf("dmf%d: silo overflow\n", dmf);
3796940Ssam 			overrun = 1;
3806940Ssam 		}
3816940Ssam 		if (c & DMF_FE)
3826940Ssam 			/*
3836940Ssam 			 * At framing error (break) generate
3846940Ssam 			 * a null (in raw mode, for getty), or a
3856940Ssam 			 * interrupt (in cooked/cbreak mode).
3866940Ssam 			 */
3876940Ssam 			if (tp->t_flags&RAW)
3886940Ssam 				c = 0;
3896940Ssam 			else
3909550Ssam 				c = tp->t_intrc;
3916940Ssam #if NBK > 0
3926940Ssam 		if (tp->t_line == NETLDISC) {
3936940Ssam 			c &= 0177;
3946940Ssam 			BKINPUT(c, tp);
3956940Ssam 		} else
3966940Ssam #endif
3976940Ssam 			(*linesw[tp->t_line].l_rint)(c, tp);
3986940Ssam 	}
3996940Ssam }
4006940Ssam 
4016940Ssam /*
4026940Ssam  * Ioctl for DMF32.
4036940Ssam  */
4046940Ssam /*ARGSUSED*/
4057630Ssam dmfioctl(dev, cmd, data, flag)
4066940Ssam 	dev_t dev;
4077630Ssam 	caddr_t data;
4086940Ssam {
4096940Ssam 	register struct tty *tp;
4106940Ssam 	register int unit = minor(dev);
4118567Sroot 	int error;
4126940Ssam 
4136940Ssam 	tp = &dmf_tty[unit];
4148567Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
4158567Sroot 	if (error >= 0)
4168567Sroot 		return (error);
4178567Sroot 	error = ttioctl(tp, cmd, data, flag);
4188567Sroot 	if (error >= 0) {
4197630Ssam 		if (cmd == TIOCSETP || cmd == TIOCSETN)
4206940Ssam 			dmfparam(unit);
4218567Sroot 		return (error);
4228567Sroot 	}
4238567Sroot 	switch (cmd) {
4246940Ssam 
4256940Ssam 	case TIOCSBRK:
4268702Sroot 		(void) dmfmctl(dev, DMF_BRK, DMBIS);
4276940Ssam 		break;
4287630Ssam 
4296940Ssam 	case TIOCCBRK:
4308702Sroot 		(void) dmfmctl(dev, DMF_BRK, DMBIC);
4316940Ssam 		break;
4327630Ssam 
4336940Ssam 	case TIOCSDTR:
4348702Sroot 		(void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS);
4356940Ssam 		break;
4367630Ssam 
4376940Ssam 	case TIOCCDTR:
4388702Sroot 		(void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC);
4396940Ssam 		break;
4407630Ssam 
4416940Ssam 	case TIOCMSET:
4428702Sroot 		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET);
4436940Ssam 		break;
4447630Ssam 
4456940Ssam 	case TIOCMBIS:
4468702Sroot 		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS);
4476940Ssam 		break;
4487630Ssam 
4496940Ssam 	case TIOCMBIC:
4508702Sroot 		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC);
4516940Ssam 		break;
4527630Ssam 
4536940Ssam 	case TIOCMGET:
4547630Ssam 		*(int *)data = dmftodm(dmfmctl(dev, 0, DMGET));
4556940Ssam 		break;
4567630Ssam 
4576940Ssam 	default:
4588567Sroot 		return (ENOTTY);
4596940Ssam 	}
4608567Sroot 	return (0);
4616940Ssam }
4626940Ssam 
4636940Ssam dmtodmf(bits)
4646940Ssam 	register int bits;
4656940Ssam {
4666940Ssam 	register int b;
4676940Ssam 
4686940Ssam 	b = bits & 012;
4696940Ssam 	if (bits & DML_ST) b |= DMF_RATE;
4706940Ssam 	if (bits & DML_RTS) b |= DMF_RTS;
4716940Ssam 	if (bits & DML_USR) b |= DMF_USRW;
4726940Ssam 	return(b);
4736940Ssam }
4746940Ssam 
4756940Ssam dmftodm(bits)
4766940Ssam 	register int bits;
4776940Ssam {
4786940Ssam 	register int b;
4796940Ssam 
4806940Ssam 	b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE;
4816940Ssam 	if (bits & DMF_USRR) b |= DML_USR;
4826940Ssam 	if (bits & DMF_RTS) b |= DML_RTS;
4836940Ssam 	return(b);
4846940Ssam }
4856940Ssam 
4866940Ssam 
4876940Ssam /*
4886940Ssam  * Set parameters from open or stty into the DMF hardware
4896940Ssam  * registers.
4906940Ssam  */
4916940Ssam dmfparam(unit)
4926940Ssam 	register int unit;
4936940Ssam {
4946940Ssam 	register struct tty *tp;
4956940Ssam 	register struct dmfdevice *addr;
4966940Ssam 	register int lpar, lcr;
4976940Ssam 	int s;
4986940Ssam 
4996940Ssam 	tp = &dmf_tty[unit];
5006940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
5016940Ssam 	/*
5026940Ssam 	 * Block interrupts so parameters will be set
5036940Ssam 	 * before the line interrupts.
5046940Ssam 	 */
5056940Ssam 	s = spl5();
5066940Ssam 	addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE;
5076940Ssam 	if ((tp->t_ispeed)==0) {
5086971Ssam 		tp->t_state |= TS_HUPCLS;
5098702Sroot 		(void) dmfmctl(unit, DMF_OFF, DMSET);
5106940Ssam 		return;
5116940Ssam 	}
5126940Ssam 	lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8);
5136940Ssam 	lcr = DMFLCR_ENA;
5146940Ssam 	if ((tp->t_ispeed) == B134)
5156940Ssam 		lpar |= BITS6|PENABLE;
5169550Ssam 	else if (tp->t_flags & (RAW|LITOUT))
5176940Ssam 		lpar |= BITS8;
5186940Ssam 	else {
5196940Ssam 		lpar |= BITS7|PENABLE;
5206940Ssam 		/* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */
5216940Ssam 	}
5226940Ssam 	if ((tp->t_flags&EVENP) == 0)
5236940Ssam 		lpar |= OPAR;
5246940Ssam 	if ((tp->t_ospeed) == B110)
5256940Ssam 		lpar |= TWOSB;
5266940Ssam 	lpar |= (unit&07);
5276940Ssam 	addr->dmflpr = lpar;
5286940Ssam 	addr->dmflcr = lcr;
5296940Ssam 	splx(s);
5306940Ssam }
5316940Ssam 
5326940Ssam /*
5336940Ssam  * DMF32 transmitter interrupt.
5346940Ssam  * Restart the idle line.
5356940Ssam  */
5366940Ssam dmfxint(dmf)
5376940Ssam 	int dmf;
5386940Ssam {
5396940Ssam 	register struct tty *tp;
5406940Ssam 	register struct dmfdevice *addr;
5416940Ssam 	register struct uba_device *ui;
5426940Ssam 	register int unit, t;
5436940Ssam #ifdef DMFDMA
5446940Ssam 	short cntr;
5456940Ssam #endif
5466940Ssam 
5476940Ssam 	ui = dmfinfo[dmf];
5486940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
5496940Ssam 	while ((t = addr->dmfcsr) & DMF_TI) {
5506940Ssam 		unit = dmf*8 + ((t>>8)&07);
5516940Ssam 		tp = &dmf_tty[unit];
5526971Ssam 		tp->t_state &= ~TS_BUSY;
5536940Ssam 		if (t & DMF_NXM) {
5546940Ssam 			printf("dmf%d: NXM line %d\n", dmf, unit&7);
5556940Ssam 			/* SHOULD RESTART OR SOMETHING... */
5566940Ssam 		}
5576971Ssam 		if (tp->t_state&TS_FLUSH)
5586971Ssam 			tp->t_state &= ~TS_FLUSH;
5596940Ssam #ifdef DMFDMA
5606940Ssam 		else {
5616940Ssam 			addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07);
5626940Ssam 			if (addr->dmftsc == 0) {
5636940Ssam 				/*
5646940Ssam 				 * Do arithmetic in a short to make up
5656940Ssam 				 * for lost 16&17 bits.
5666940Ssam 				 */
5676940Ssam 				addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07);
5686940Ssam 				cntr = addr->dmftba -
5696940Ssam 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
5706940Ssam 				ndflush(&tp->t_outq, (int)cntr);
5716940Ssam 			}
5726940Ssam 		}
5736940Ssam #endif
5746940Ssam 		if (tp->t_line)
5756940Ssam 			(*linesw[tp->t_line].l_start)(tp);
5766940Ssam 		else
5776940Ssam 			dmfstart(tp);
5786940Ssam 	}
5796940Ssam }
5806940Ssam 
5816940Ssam /*
5826940Ssam  * Start (restart) transmission on the given DMF32 line.
5836940Ssam  */
5846940Ssam dmfstart(tp)
5856940Ssam 	register struct tty *tp;
5866940Ssam {
5876940Ssam 	register struct dmfdevice *addr;
5888607Sroot 	register int unit, nch;
5896940Ssam 	int s;
5906940Ssam 
5916940Ssam 	unit = minor(tp->t_dev);
5926940Ssam 	unit &= 07;
5936940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
5946940Ssam 
5956940Ssam 	/*
5966940Ssam 	 * Must hold interrupts in following code to prevent
5976940Ssam 	 * state of the tp from changing.
5986940Ssam 	 */
5996940Ssam 	s = spl5();
6006940Ssam 	/*
6016940Ssam 	 * If it's currently active, or delaying, no need to do anything.
6026940Ssam 	 */
6036971Ssam 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
6046940Ssam 		goto out;
6056940Ssam 	/*
6066940Ssam 	 * If there are still characters in the silo,
6076940Ssam 	 * just reenable the transmitter.
6086940Ssam 	 */
6096940Ssam 	addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
6106940Ssam 	if (addr->dmftsc) {
6116940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
6126940Ssam 		addr->dmflcr |= DMF_TE;
6136971Ssam 		tp->t_state |= TS_BUSY;
6146940Ssam 		goto out;
6156940Ssam 	}
6166940Ssam 	/*
6176940Ssam 	 * If there are sleepers, and output has drained below low
6186940Ssam 	 * water mark, wake up the sleepers.
6196940Ssam 	 */
6206971Ssam 	if ((tp->t_state&TS_ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
6216971Ssam 		tp->t_state &= ~TS_ASLEEP;
6226963Ssam 		wakeup((caddr_t)&tp->t_outq);
6236940Ssam 	}
6246940Ssam 	/*
6256940Ssam 	 * Now restart transmission unless the output queue is
6266940Ssam 	 * empty.
6276940Ssam 	 */
6286940Ssam 	if (tp->t_outq.c_cc == 0)
6296940Ssam 		goto out;
6309550Ssam 	if (tp->t_flags & (RAW|LITOUT))
6316940Ssam 		nch = ndqb(&tp->t_outq, 0);
6326940Ssam 	else {
6336940Ssam 		nch = ndqb(&tp->t_outq, 0200);
6346940Ssam 		/*
6356940Ssam 		 * If first thing on queue is a delay process it.
6366940Ssam 		 */
6376940Ssam 		if (nch == 0) {
6386940Ssam 			nch = getc(&tp->t_outq);
6396940Ssam 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
6406971Ssam 			tp->t_state |= TS_TIMEOUT;
6416940Ssam 			goto out;
6426940Ssam 		}
6436940Ssam 	}
6446940Ssam 	/*
6456940Ssam 	 * If characters to transmit, restart transmission.
6466940Ssam 	 */
6476940Ssam 	if (nch) {
6486940Ssam #ifdef DMFDMA
6496940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
6506940Ssam 		addr->dmflcr |= DMF_TE;
6516940Ssam 		car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);
6526940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_TBA | unit;
6536940Ssam 		addr->dmftba = car;
6546940Ssam 		addr->dmftcc = ((car>>2)&0xc000) | nch;
6556940Ssam #else
6566940Ssam 		register char *cp = tp->t_outq.c_cf;
6576940Ssam 		register int i;
6586940Ssam 
6596940Ssam 		nch = MIN(nch, DMF_SILOCNT);
6606940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
6616940Ssam 		addr->dmflcr |= DMF_TE;
6626940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
6636940Ssam 		for (i = 0; i < nch; i++)
6646940Ssam 			addr->dmftbuf = *cp++;
6656940Ssam 		ndflush(&tp->t_outq, nch);
6666940Ssam #endif
6676971Ssam 		tp->t_state |= TS_BUSY;
6686940Ssam 	}
6696940Ssam out:
6706940Ssam 	splx(s);
6716940Ssam }
6726940Ssam 
6736940Ssam /*
6746940Ssam  * Stop output on a line, e.g. for ^S/^Q or output flush.
6756940Ssam  */
6766940Ssam /*ARGSUSED*/
6776940Ssam dmfstop(tp, flag)
6786940Ssam 	register struct tty *tp;
6796940Ssam {
6806940Ssam 	register struct dmfdevice *addr;
6816940Ssam 	register int unit, s;
6826940Ssam 
6836940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
6846940Ssam 	/*
6856940Ssam 	 * Block input/output interrupts while messing with state.
6866940Ssam 	 */
6876940Ssam 	s = spl5();
6886971Ssam 	if (tp->t_state & TS_BUSY) {
6896940Ssam 		/*
6906940Ssam 		 * Device is transmitting; stop output
6916940Ssam 		 * by selecting the line and disabling
6926940Ssam 		 * the transmitter.  If this is a flush
6936940Ssam 		 * request then flush the output silo,
6946940Ssam 		 * otherwise we will pick up where we
6956940Ssam 		 * left off by enabling the transmitter.
6966940Ssam 		 */
6976940Ssam 		unit = minor(tp->t_dev);
6986940Ssam 		addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE;
6996940Ssam 		addr->dmflcr &= ~DMF_TE;
7006971Ssam 		if ((tp->t_state&TS_TTSTOP)==0) {
7016971Ssam 			tp->t_state |= TS_FLUSH;
7026940Ssam 			addr->dmflcr |= DMF_FLUSH;
7036940Ssam 		} else
7046971Ssam 			tp->t_state &= ~TS_BUSY;
7056940Ssam 	}
7066940Ssam 	splx(s);
7076940Ssam }
7086940Ssam 
7096940Ssam /*
7106940Ssam  * DMF32 modem control
7116940Ssam  */
7126940Ssam dmfmctl(dev, bits, how)
7136940Ssam 	dev_t dev;
7146940Ssam 	int bits, how;
7156940Ssam {
7166940Ssam 	register struct dmfdevice *dmfaddr;
7176940Ssam 	register int unit, mbits, lcr;
7186940Ssam 	int s;
7196940Ssam 
7206940Ssam 	unit = minor(dev);
7216940Ssam 	dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr);
7226940Ssam 	unit &= 07;
7236940Ssam 	s = spl5();
7246940Ssam 	dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
7256940Ssam 	mbits = dmfaddr->dmfrms << 8;
7266940Ssam 	dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
7276940Ssam 	mbits |= dmfaddr->dmftms;
7286940Ssam 	lcr = dmfaddr->dmflcr;
7296940Ssam 	switch (how) {
7306940Ssam 	case DMSET:
7316940Ssam 		mbits = bits;
7326940Ssam 		break;
7336940Ssam 
7346940Ssam 	case DMBIS:
7356940Ssam 		mbits |= bits;
7366940Ssam 		break;
7376940Ssam 
7386940Ssam 	case DMBIC:
7396940Ssam 		mbits &= ~bits;
7406940Ssam 		break;
7416940Ssam 
7426940Ssam 	case DMGET:
7436940Ssam 		(void) splx(s);
7446940Ssam 		return(mbits);
7456940Ssam 	}
7466940Ssam 	dmfaddr->dmftms = mbits&037;
7476940Ssam 	if (mbits & DMF_BRK)
7486940Ssam 		lcr |= DMF_RBRK;
7496940Ssam 	else
7506940Ssam 		lcr &= ~DMF_RBRK;
7516940Ssam 	dmfaddr->dmflcr = lcr;
7526940Ssam 	(void) splx(s);
7536940Ssam 	return(mbits);
7546940Ssam }
7556940Ssam 
7566940Ssam /*
7576940Ssam  * Reset state of driver if UBA reset was necessary.
7586940Ssam  * Reset the csr, lpr, and lcr registers on open lines, and
7596940Ssam  * restart transmitters.
7606940Ssam  */
7616940Ssam dmfreset(uban)
7626940Ssam 	int uban;
7636940Ssam {
7646940Ssam 	register int dmf, unit;
7656940Ssam 	register struct tty *tp;
7666940Ssam 	register struct uba_device *ui;
7676940Ssam 	register struct dmfdevice *addr;
7686940Ssam 	int i;
7696940Ssam 
7706940Ssam #ifdef DMFDMA
7716940Ssam 	if (dmf_ubinfo[uban] == 0)
7726940Ssam 		return;
7736940Ssam 	dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
7746940Ssam 	    nclist*sizeof (struct cblock), 0);
7756940Ssam 	cbase[uban] = dmf_ubinfo[uban]&0x3ffff;
7766940Ssam #endif
7776940Ssam 	for (dmf = 0; dmf < NDMF; dmf++) {
7786940Ssam 		ui = dmfinfo[dmf];
7796940Ssam 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
7806940Ssam 			continue;
7816940Ssam 		printf(" dmf%d", dmf);
7826940Ssam 		addr = (struct dmfdevice *)ui->ui_addr;
7836940Ssam 		addr->dmfcsr = DMF_IE;
7846940Ssam 		addr->dmfrsp = 1;
7856940Ssam 		unit = dmf * 8;
7866940Ssam 		for (i = 0; i < 8; i++) {
7876940Ssam 			tp = &dmf_tty[unit];
7886971Ssam 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
7896940Ssam 				dmfparam(unit);
7908702Sroot 				(void) dmfmctl(unit, DMF_ON, DMSET);
7916971Ssam 				tp->t_state &= ~TS_BUSY;
7926940Ssam 				dmfstart(tp);
7936940Ssam 			}
7946940Ssam 			unit++;
7956940Ssam 		}
7966940Ssam 	}
7976940Ssam }
7986940Ssam 
7996940Ssam /* stubs for interrupt routines for devices not yet supported */
8006940Ssam 
8016940Ssam dmfsrint() { printf("dmfsrint\n"); }
8026940Ssam 
8036940Ssam dmfsxint() { printf("dmfsxint\n"); }
8046940Ssam 
8056940Ssam dmfdaint() { printf("dmfdaint\n"); }
8066940Ssam 
8076940Ssam dmfdbint() { printf("dmfdbint\n"); }
8086940Ssam 
8096940Ssam dmflint() { printf("dmflint\n"); }
8106940Ssam #endif
811