xref: /csrg-svn/sys/vax/uba/dmf.c (revision 17562)
1*17562Sbloom /*	dmf.c	6.4	84/12/20	*/
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  */
189772Ssam #include "../machine/pte.h"
199772Ssam 
206940Ssam #include "bk.h"
2116063Skarels #include "uba.h"
2217124Sbloom #include "param.h"
2317124Sbloom #include "conf.h"
2417124Sbloom #include "dir.h"
2517124Sbloom #include "user.h"
2617124Sbloom #include "ioctl.h"
2717124Sbloom #include "tty.h"
2817124Sbloom #include "map.h"
2917124Sbloom #include "buf.h"
3017124Sbloom #include "vm.h"
3117124Sbloom #include "bkmac.h"
3217124Sbloom #include "clist.h"
3317124Sbloom #include "file.h"
3417124Sbloom #include "uio.h"
356940Ssam 
3617124Sbloom #include "ubareg.h"
3717124Sbloom #include "ubavar.h"
3817124Sbloom #include "dmfreg.h"
398473Sroot 
406940Ssam /*
416940Ssam  * Definition of the driver for the auto-configuration program.
426940Ssam  */
436940Ssam int	dmfprobe(), dmfattach(), dmfrint(), dmfxint();
446940Ssam struct	uba_device *dmfinfo[NDMF];
456940Ssam u_short	dmfstd[] = { 0 };
466940Ssam struct	uba_driver dmfdriver =
476940Ssam 	{ dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
486940Ssam 
496940Ssam /*
506940Ssam  * Local variables for the driver
516940Ssam  */
526940Ssam char	dmf_speeds[] =
536940Ssam 	{ 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 };
546940Ssam 
556940Ssam struct	tty dmf_tty[NDMF*8];
566940Ssam char	dmfsoftCAR[NDMF];
578778Sroot #ifndef lint
588778Sroot int	ndmf = NDMF*8;			/* used by iostat */
598778Sroot #endif
606940Ssam int	dmfact;				/* mask of active dmf's */
616940Ssam int	dmfstart(), ttrstrt();
626940Ssam 
636940Ssam #ifdef DMFDMA
646940Ssam /*
656940Ssam  * The clist space is mapped by the driver onto each UNIBUS.
666940Ssam  * The UBACVT macro converts a clist space address for unibus uban
676940Ssam  * into an i/o space address for the DMA routine.
686940Ssam  */
6916063Skarels int	dmf_ubinfo[NUBA];		/* info about allocated unibus map */
7016063Skarels static int cbase[NUBA];			/* base address in unibus map */
716940Ssam #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
726940Ssam #endif
736940Ssam 
746940Ssam /*
756940Ssam  * Routine for configuration to set dmf interrupt.
766940Ssam  */
776940Ssam /*ARGSUSED*/
786940Ssam dmfprobe(reg, ctlr)
796940Ssam 	caddr_t reg;
806940Ssam 	int ctlr;
816940Ssam {
826940Ssam 	register int br, cvec;		/* these are ``value-result'' */
836940Ssam 	register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg;
846940Ssam 
856940Ssam #ifdef lint
866940Ssam 	br = 0; cvec = br; br = cvec;
878808Sroot 	dmfxint(0); dmfrint(0);
888808Sroot 	dmfsrint(); dmfsxint(); dmfdaint(); dmfdbint(); dmflint();
896940Ssam #endif
906940Ssam 	br = 0x15;
916940Ssam 	cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
926940Ssam 	dmfaddr->dmfccsr0 = cvec >> 2;
936940Ssam 	/* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */
947412Skre 	return (sizeof (struct dmfdevice));
956940Ssam }
966940Ssam 
976940Ssam /*
986940Ssam  * Routine called to attach a dmf.
996940Ssam  */
1006940Ssam dmfattach(ui)
1016940Ssam 	struct uba_device *ui;
1026940Ssam {
1036940Ssam 
1046940Ssam 	dmfsoftCAR[ui->ui_unit] = ui->ui_flags;
1056940Ssam }
1066940Ssam 
1076940Ssam 
1086940Ssam /*
1096940Ssam  * Open a DMF32 line, mapping the clist onto the uba if this
1106940Ssam  * is the first dmf on this uba.  Turn on this dmf if this is
1116940Ssam  * the first use of it.
1126940Ssam  */
1136940Ssam /*ARGSUSED*/
1146940Ssam dmfopen(dev, flag)
1156940Ssam 	dev_t dev;
1166940Ssam {
1176940Ssam 	register struct tty *tp;
1186940Ssam 	register int unit, dmf;
1196940Ssam 	register struct dmfdevice *addr;
1206940Ssam 	register struct uba_device *ui;
1216940Ssam 	int s;
1226940Ssam 
1236940Ssam 	unit = minor(dev);
1246940Ssam 	dmf = unit >> 3;
1258567Sroot 	if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0)
1268567Sroot 		return (ENXIO);
1276940Ssam 	tp = &dmf_tty[unit];
1288567Sroot 	if (tp->t_state&TS_XCLUDE && u.u_uid!=0)
1298567Sroot 		return (EBUSY);
1306940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
1316940Ssam 	tp->t_addr = (caddr_t)addr;
1326940Ssam 	tp->t_oproc = dmfstart;
1336971Ssam 	tp->t_state |= TS_WOPEN;
1346940Ssam 	/*
1356940Ssam 	 * While setting up state for this uba and this dmf,
1366940Ssam 	 * block uba resets which can clear the state.
1376940Ssam 	 */
1386940Ssam 	s = spl5();
1396940Ssam #ifdef DMFDMA
1406940Ssam 	if (dmf_ubinfo[ui->ui_ubanum] == 0) {
1416940Ssam 		dmf_ubinfo[ui->ui_ubanum] =
1426940Ssam 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
1436940Ssam 			nclist*sizeof(struct cblock), 0);
1446940Ssam 		cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff;
1456940Ssam 	}
1466940Ssam #endif
1476940Ssam 	if ((dmfact&(1<<dmf)) == 0) {
1486940Ssam 		addr->dmfcsr |= DMF_IE;
1496940Ssam 		dmfact |= (1<<dmf);
1506940Ssam 		addr->dmfrsp = 1;	/* DON'T KNOW WHAT TO SET IT TO YET */
1516940Ssam 	}
1526940Ssam 	splx(s);
1536940Ssam 	/*
1546940Ssam 	 * If this is first open, initialze tty state to default.
1556940Ssam 	 */
1566971Ssam 	if ((tp->t_state&TS_ISOPEN) == 0) {
1576940Ssam 		ttychars(tp);
1586940Ssam 		if (tp->t_ispeed == 0) {
1596940Ssam 			tp->t_ispeed = B300;
1606940Ssam 			tp->t_ospeed = B300;
1616940Ssam 			tp->t_flags = ODDP|EVENP|ECHO;
1626940Ssam 		}
1636940Ssam 		dmfparam(unit);
1646940Ssam 	}
1656940Ssam 	/*
1666940Ssam 	 * Wait for carrier, then process line discipline specific open.
1676940Ssam 	 */
1686940Ssam 	if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) ||
1696940Ssam 	    (dmfsoftCAR[dmf] & (1<<(unit&07))))
1706971Ssam 		tp->t_state |= TS_CARR_ON;
1716940Ssam 	s = spl5();
1726971Ssam 	while ((tp->t_state & TS_CARR_ON) == 0) {
1736971Ssam 		tp->t_state |= TS_WOPEN;
1746940Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
1756940Ssam 	}
1766940Ssam 	splx(s);
1778567Sroot 	return ((*linesw[tp->t_line].l_open)(dev, tp));
1786940Ssam }
1796940Ssam 
1806940Ssam /*
1816940Ssam  * Close a DMF32 line.
1826940Ssam  */
1836940Ssam /*ARGSUSED*/
1846940Ssam dmfclose(dev, flag)
1856940Ssam 	dev_t dev;
1866940Ssam 	int flag;
1876940Ssam {
1886940Ssam 	register struct tty *tp;
1896940Ssam 	register unit;
1906940Ssam 
1916940Ssam 	unit = minor(dev);
1926940Ssam 	tp = &dmf_tty[unit];
1936940Ssam 	(*linesw[tp->t_line].l_close)(tp);
1948702Sroot 	(void) dmfmctl(unit, DMF_BRK, DMBIC);
1956971Ssam 	if (tp->t_state&TS_HUPCLS || (tp->t_state&TS_ISOPEN)==0)
1968702Sroot 		(void) dmfmctl(unit, DMF_OFF, DMSET);
1976940Ssam 	ttyclose(tp);
1986940Ssam }
1996940Ssam 
2007726Sroot dmfread(dev, uio)
2016940Ssam 	dev_t dev;
2027726Sroot 	struct uio *uio;
2036940Ssam {
2046940Ssam 	register struct tty *tp;
2056940Ssam 
2066940Ssam 	tp = &dmf_tty[minor(dev)];
2077726Sroot 	return ((*linesw[tp->t_line].l_read)(tp, uio));
2086940Ssam }
2096940Ssam 
2107832Sroot dmfwrite(dev, uio)
2116940Ssam 	dev_t dev;
2127832Sroot 	struct uio *uio;
2136940Ssam {
2146940Ssam 	register struct tty *tp;
2156940Ssam 
2166940Ssam 	tp = &dmf_tty[minor(dev)];
2178530Sroot 	return ((*linesw[tp->t_line].l_write)(tp, uio));
2186940Ssam }
2196940Ssam 
2206940Ssam /*
2216940Ssam  * DMF32 receiver interrupt.
2226940Ssam  */
2236940Ssam dmfrint(dmf)
2246940Ssam 	int dmf;
2256940Ssam {
2266940Ssam 	register struct tty *tp;
2276940Ssam 	register c;
2286940Ssam 	register struct dmfdevice *addr;
2296940Ssam 	register struct tty *tp0;
2306940Ssam 	register struct uba_device *ui;
23112449Ssam 	int overrun = 0, s;
2326940Ssam 
2336940Ssam 	ui = dmfinfo[dmf];
2346940Ssam 	if (ui == 0 || ui->ui_alive == 0)
2356940Ssam 		return;
2366940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
2376940Ssam 	tp0 = &dmf_tty[dmf<<3];
2386940Ssam 	/*
2396940Ssam 	 * Loop fetching characters from the silo for this
2406940Ssam 	 * dmf until there are no more in the silo.
2416940Ssam 	 */
2426940Ssam 	while ((c = addr->dmfrbuf) < 0) {
2436940Ssam 		tp = tp0 + ((c>>8)&07);
2446940Ssam 		if (c & DMF_DSC) {
24512449Ssam 			s = spl5();
2466940Ssam 			addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07);
2476940Ssam 			if (addr->dmfrms & DMF_CAR) {
2486971Ssam 				if ((tp->t_state & TS_CARR_ON) == 0) {
2496940Ssam 					wakeup((caddr_t)&tp->t_rawq);
2506971Ssam 					tp->t_state |= TS_CARR_ON;
2516940Ssam 				}
2526940Ssam 			} else {
2536971Ssam 				if (tp->t_state & TS_CARR_ON) {
2546940Ssam 					gsignal(tp->t_pgrp, SIGHUP);
2556940Ssam 					gsignal(tp->t_pgrp, SIGCONT);
2566940Ssam 					addr->dmfcsr = DMF_IE | DMFIR_LCR |
2576940Ssam 						((c>>8)&07);
2586940Ssam 					addr->dmftms = 0;
25912776Ssam 					ttyflush(tp, FREAD|FWRITE);
2606940Ssam 				}
2616971Ssam 				tp->t_state &= ~TS_CARR_ON;
2626940Ssam 			}
26312449Ssam 			splx(s);
2646940Ssam 			continue;
2656940Ssam 		}
2666971Ssam 		if ((tp->t_state&TS_ISOPEN)==0) {
2676940Ssam 			wakeup((caddr_t)tp);
2686940Ssam 			continue;
2696940Ssam 		}
2706940Ssam 		if (c & DMF_PE)
2716940Ssam 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
2726940Ssam 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
2736940Ssam 				continue;
2746940Ssam 		if ((c & DMF_DO) && overrun == 0) {
2756940Ssam 			printf("dmf%d: silo overflow\n", dmf);
2766940Ssam 			overrun = 1;
2776940Ssam 		}
2786940Ssam 		if (c & DMF_FE)
2796940Ssam 			/*
2806940Ssam 			 * At framing error (break) generate
2816940Ssam 			 * a null (in raw mode, for getty), or a
2826940Ssam 			 * interrupt (in cooked/cbreak mode).
2836940Ssam 			 */
2846940Ssam 			if (tp->t_flags&RAW)
2856940Ssam 				c = 0;
2866940Ssam 			else
2879550Ssam 				c = tp->t_intrc;
2886940Ssam #if NBK > 0
2896940Ssam 		if (tp->t_line == NETLDISC) {
2906940Ssam 			c &= 0177;
2916940Ssam 			BKINPUT(c, tp);
2926940Ssam 		} else
2936940Ssam #endif
2946940Ssam 			(*linesw[tp->t_line].l_rint)(c, tp);
2956940Ssam 	}
2966940Ssam }
2976940Ssam 
2986940Ssam /*
2996940Ssam  * Ioctl for DMF32.
3006940Ssam  */
3016940Ssam /*ARGSUSED*/
3027630Ssam dmfioctl(dev, cmd, data, flag)
3036940Ssam 	dev_t dev;
3047630Ssam 	caddr_t data;
3056940Ssam {
3066940Ssam 	register struct tty *tp;
3076940Ssam 	register int unit = minor(dev);
3088567Sroot 	int error;
3096940Ssam 
3106940Ssam 	tp = &dmf_tty[unit];
3118567Sroot 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
3128567Sroot 	if (error >= 0)
3138567Sroot 		return (error);
3148567Sroot 	error = ttioctl(tp, cmd, data, flag);
3158567Sroot 	if (error >= 0) {
316*17562Sbloom 		if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLBIS ||
317*17562Sbloom 		    cmd == TIOCLBIC || cmd == TIOCLSET)
3186940Ssam 			dmfparam(unit);
3198567Sroot 		return (error);
3208567Sroot 	}
3218567Sroot 	switch (cmd) {
3226940Ssam 
3236940Ssam 	case TIOCSBRK:
3248702Sroot 		(void) dmfmctl(dev, DMF_BRK, DMBIS);
3256940Ssam 		break;
3267630Ssam 
3276940Ssam 	case TIOCCBRK:
3288702Sroot 		(void) dmfmctl(dev, DMF_BRK, DMBIC);
3296940Ssam 		break;
3307630Ssam 
3316940Ssam 	case TIOCSDTR:
3328702Sroot 		(void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS);
3336940Ssam 		break;
3347630Ssam 
3356940Ssam 	case TIOCCDTR:
3368702Sroot 		(void) dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC);
3376940Ssam 		break;
3387630Ssam 
3396940Ssam 	case TIOCMSET:
3408702Sroot 		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMSET);
3416940Ssam 		break;
3427630Ssam 
3436940Ssam 	case TIOCMBIS:
3448702Sroot 		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIS);
3456940Ssam 		break;
3467630Ssam 
3476940Ssam 	case TIOCMBIC:
3488702Sroot 		(void) dmfmctl(dev, dmtodmf(*(int *)data), DMBIC);
3496940Ssam 		break;
3507630Ssam 
3516940Ssam 	case TIOCMGET:
3527630Ssam 		*(int *)data = dmftodm(dmfmctl(dev, 0, DMGET));
3536940Ssam 		break;
3547630Ssam 
3556940Ssam 	default:
3568567Sroot 		return (ENOTTY);
3576940Ssam 	}
3588567Sroot 	return (0);
3596940Ssam }
3606940Ssam 
3616940Ssam dmtodmf(bits)
3626940Ssam 	register int bits;
3636940Ssam {
3646940Ssam 	register int b;
3656940Ssam 
3666940Ssam 	b = bits & 012;
3676940Ssam 	if (bits & DML_ST) b |= DMF_RATE;
3686940Ssam 	if (bits & DML_RTS) b |= DMF_RTS;
3696940Ssam 	if (bits & DML_USR) b |= DMF_USRW;
3706940Ssam 	return(b);
3716940Ssam }
3726940Ssam 
3736940Ssam dmftodm(bits)
3746940Ssam 	register int bits;
3756940Ssam {
3766940Ssam 	register int b;
3776940Ssam 
3786940Ssam 	b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE;
3796940Ssam 	if (bits & DMF_USRR) b |= DML_USR;
3806940Ssam 	if (bits & DMF_RTS) b |= DML_RTS;
3816940Ssam 	return(b);
3826940Ssam }
3836940Ssam 
3846940Ssam 
3856940Ssam /*
3866940Ssam  * Set parameters from open or stty into the DMF hardware
3876940Ssam  * registers.
3886940Ssam  */
3896940Ssam dmfparam(unit)
3906940Ssam 	register int unit;
3916940Ssam {
3926940Ssam 	register struct tty *tp;
3936940Ssam 	register struct dmfdevice *addr;
3946940Ssam 	register int lpar, lcr;
3956940Ssam 	int s;
3966940Ssam 
3976940Ssam 	tp = &dmf_tty[unit];
3986940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
3996940Ssam 	/*
4006940Ssam 	 * Block interrupts so parameters will be set
4016940Ssam 	 * before the line interrupts.
4026940Ssam 	 */
4036940Ssam 	s = spl5();
4046940Ssam 	addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE;
4056940Ssam 	if ((tp->t_ispeed)==0) {
4066971Ssam 		tp->t_state |= TS_HUPCLS;
4078702Sroot 		(void) dmfmctl(unit, DMF_OFF, DMSET);
4086940Ssam 		return;
4096940Ssam 	}
4106940Ssam 	lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8);
4116940Ssam 	lcr = DMFLCR_ENA;
4126940Ssam 	if ((tp->t_ispeed) == B134)
4136940Ssam 		lpar |= BITS6|PENABLE;
4149550Ssam 	else if (tp->t_flags & (RAW|LITOUT))
4156940Ssam 		lpar |= BITS8;
4166940Ssam 	else {
4176940Ssam 		lpar |= BITS7|PENABLE;
4186940Ssam 		/* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */
4196940Ssam 	}
42012450Ssam 	if (tp->t_flags&EVENP)
42112450Ssam 		lpar |= EPAR;
4226940Ssam 	if ((tp->t_ospeed) == B110)
4236940Ssam 		lpar |= TWOSB;
4246940Ssam 	lpar |= (unit&07);
4256940Ssam 	addr->dmflpr = lpar;
42612449Ssam 	SETLCR(addr, lcr);
4276940Ssam 	splx(s);
4286940Ssam }
4296940Ssam 
4306940Ssam /*
4316940Ssam  * DMF32 transmitter interrupt.
4326940Ssam  * Restart the idle line.
4336940Ssam  */
4346940Ssam dmfxint(dmf)
4356940Ssam 	int dmf;
4366940Ssam {
4376940Ssam 	register struct tty *tp;
4386940Ssam 	register struct dmfdevice *addr;
4396940Ssam 	register struct uba_device *ui;
4406940Ssam 	register int unit, t;
4416940Ssam #ifdef DMFDMA
4426940Ssam 	short cntr;
44312449Ssam 	int s;
4446940Ssam #endif
4456940Ssam 
4466940Ssam 	ui = dmfinfo[dmf];
4476940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
4486940Ssam 	while ((t = addr->dmfcsr) & DMF_TI) {
4496940Ssam 		unit = dmf*8 + ((t>>8)&07);
4506940Ssam 		tp = &dmf_tty[unit];
4516971Ssam 		tp->t_state &= ~TS_BUSY;
4526940Ssam 		if (t & DMF_NXM) {
4536940Ssam 			printf("dmf%d: NXM line %d\n", dmf, unit&7);
4546940Ssam 			/* SHOULD RESTART OR SOMETHING... */
4556940Ssam 		}
4566971Ssam 		if (tp->t_state&TS_FLUSH)
4576971Ssam 			tp->t_state &= ~TS_FLUSH;
4586940Ssam #ifdef DMFDMA
4596940Ssam 		else {
46012449Ssam 			s = spl5();
4616940Ssam 			addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07);
4626940Ssam 			if (addr->dmftsc == 0) {
4636940Ssam 				/*
4646940Ssam 				 * Do arithmetic in a short to make up
4656940Ssam 				 * for lost 16&17 bits.
4666940Ssam 				 */
4676940Ssam 				addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07);
4686940Ssam 				cntr = addr->dmftba -
4696940Ssam 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
4706940Ssam 				ndflush(&tp->t_outq, (int)cntr);
4716940Ssam 			}
47212449Ssam 			splx(s);
4736940Ssam 		}
4746940Ssam #endif
4756940Ssam 		if (tp->t_line)
4766940Ssam 			(*linesw[tp->t_line].l_start)(tp);
4776940Ssam 		else
4786940Ssam 			dmfstart(tp);
4796940Ssam 	}
4806940Ssam }
4816940Ssam 
4826940Ssam /*
4836940Ssam  * Start (restart) transmission on the given DMF32 line.
4846940Ssam  */
4856940Ssam dmfstart(tp)
4866940Ssam 	register struct tty *tp;
4876940Ssam {
4886940Ssam 	register struct dmfdevice *addr;
4898607Sroot 	register int unit, nch;
4906940Ssam 	int s;
4916940Ssam 
4926940Ssam 	unit = minor(tp->t_dev);
4936940Ssam 	unit &= 07;
4946940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
4956940Ssam 
4966940Ssam 	/*
4976940Ssam 	 * Must hold interrupts in following code to prevent
4986940Ssam 	 * state of the tp from changing.
4996940Ssam 	 */
5006940Ssam 	s = spl5();
5016940Ssam 	/*
5026940Ssam 	 * If it's currently active, or delaying, no need to do anything.
5036940Ssam 	 */
5046971Ssam 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
5056940Ssam 		goto out;
5066940Ssam 	/*
5076940Ssam 	 * If there are still characters in the silo,
5086940Ssam 	 * just reenable the transmitter.
5096940Ssam 	 */
5106940Ssam 	addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
5116940Ssam 	if (addr->dmftsc) {
5126940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
51312449Ssam 		SETLCR(addr, addr->dmflcr|DMF_TE);
5146971Ssam 		tp->t_state |= TS_BUSY;
5156940Ssam 		goto out;
5166940Ssam 	}
5176940Ssam 	/*
5186940Ssam 	 * If there are sleepers, and output has drained below low
5196940Ssam 	 * water mark, wake up the sleepers.
5206940Ssam 	 */
5216971Ssam 	if ((tp->t_state&TS_ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
5226971Ssam 		tp->t_state &= ~TS_ASLEEP;
5236963Ssam 		wakeup((caddr_t)&tp->t_outq);
5246940Ssam 	}
5256940Ssam 	/*
5266940Ssam 	 * Now restart transmission unless the output queue is
5276940Ssam 	 * empty.
5286940Ssam 	 */
5296940Ssam 	if (tp->t_outq.c_cc == 0)
5306940Ssam 		goto out;
5319550Ssam 	if (tp->t_flags & (RAW|LITOUT))
5326940Ssam 		nch = ndqb(&tp->t_outq, 0);
5336940Ssam 	else {
5346940Ssam 		nch = ndqb(&tp->t_outq, 0200);
5356940Ssam 		/*
5366940Ssam 		 * If first thing on queue is a delay process it.
5376940Ssam 		 */
5386940Ssam 		if (nch == 0) {
5396940Ssam 			nch = getc(&tp->t_outq);
5406940Ssam 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
5416971Ssam 			tp->t_state |= TS_TIMEOUT;
5426940Ssam 			goto out;
5436940Ssam 		}
5446940Ssam 	}
5456940Ssam 	/*
5466940Ssam 	 * If characters to transmit, restart transmission.
5476940Ssam 	 */
5486940Ssam 	if (nch) {
5496940Ssam #ifdef DMFDMA
5506940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
55112449Ssam 		SETLCR(addr, addr->dmflcr|DMF_TE);
5526940Ssam 		car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);
5536940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_TBA | unit;
5546940Ssam 		addr->dmftba = car;
5556940Ssam 		addr->dmftcc = ((car>>2)&0xc000) | nch;
5566940Ssam #else
5576940Ssam 		register char *cp = tp->t_outq.c_cf;
5586940Ssam 		register int i;
5596940Ssam 
5606940Ssam 		nch = MIN(nch, DMF_SILOCNT);
5616940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
56212449Ssam 		SETLCR(addr, addr->dmflcr|DMF_TE);
5636940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
5646940Ssam 		for (i = 0; i < nch; i++)
5656940Ssam 			addr->dmftbuf = *cp++;
5666940Ssam 		ndflush(&tp->t_outq, nch);
5676940Ssam #endif
5686971Ssam 		tp->t_state |= TS_BUSY;
5696940Ssam 	}
5706940Ssam out:
5716940Ssam 	splx(s);
5726940Ssam }
5736940Ssam 
5746940Ssam /*
5756940Ssam  * Stop output on a line, e.g. for ^S/^Q or output flush.
5766940Ssam  */
5776940Ssam /*ARGSUSED*/
5786940Ssam dmfstop(tp, flag)
5796940Ssam 	register struct tty *tp;
5806940Ssam {
5816940Ssam 	register struct dmfdevice *addr;
5826940Ssam 	register int unit, s;
5836940Ssam 
5846940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
5856940Ssam 	/*
5866940Ssam 	 * Block input/output interrupts while messing with state.
5876940Ssam 	 */
5886940Ssam 	s = spl5();
5896971Ssam 	if (tp->t_state & TS_BUSY) {
5906940Ssam 		/*
5916940Ssam 		 * Device is transmitting; stop output
5926940Ssam 		 * by selecting the line and disabling
5936940Ssam 		 * the transmitter.  If this is a flush
5946940Ssam 		 * request then flush the output silo,
5956940Ssam 		 * otherwise we will pick up where we
5966940Ssam 		 * left off by enabling the transmitter.
5976940Ssam 		 */
5986940Ssam 		unit = minor(tp->t_dev);
5996940Ssam 		addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE;
60012449Ssam 		SETLCR(addr, addr->dmflcr &~ DMF_TE);
6016971Ssam 		if ((tp->t_state&TS_TTSTOP)==0) {
6026971Ssam 			tp->t_state |= TS_FLUSH;
60312449Ssam 			SETLCR(addr, addr->dmflcr|DMF_FLUSH);
6046940Ssam 		} else
6056971Ssam 			tp->t_state &= ~TS_BUSY;
6066940Ssam 	}
6076940Ssam 	splx(s);
6086940Ssam }
6096940Ssam 
6106940Ssam /*
6116940Ssam  * DMF32 modem control
6126940Ssam  */
6136940Ssam dmfmctl(dev, bits, how)
6146940Ssam 	dev_t dev;
6156940Ssam 	int bits, how;
6166940Ssam {
6176940Ssam 	register struct dmfdevice *dmfaddr;
6186940Ssam 	register int unit, mbits, lcr;
6196940Ssam 	int s;
6206940Ssam 
6216940Ssam 	unit = minor(dev);
6226940Ssam 	dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr);
6236940Ssam 	unit &= 07;
6246940Ssam 	s = spl5();
6256940Ssam 	dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
6266940Ssam 	mbits = dmfaddr->dmfrms << 8;
6276940Ssam 	dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
6286940Ssam 	mbits |= dmfaddr->dmftms;
6296940Ssam 	lcr = dmfaddr->dmflcr;
6306940Ssam 	switch (how) {
6316940Ssam 	case DMSET:
63212449Ssam 		mbits = (mbits &0xff00) | bits;
6336940Ssam 		break;
6346940Ssam 
6356940Ssam 	case DMBIS:
6366940Ssam 		mbits |= bits;
6376940Ssam 		break;
6386940Ssam 
6396940Ssam 	case DMBIC:
6406940Ssam 		mbits &= ~bits;
6416940Ssam 		break;
6426940Ssam 
6436940Ssam 	case DMGET:
6446940Ssam 		(void) splx(s);
6456940Ssam 		return(mbits);
6466940Ssam 	}
6476940Ssam 	if (mbits & DMF_BRK)
6486940Ssam 		lcr |= DMF_RBRK;
6496940Ssam 	else
6506940Ssam 		lcr &= ~DMF_RBRK;
65112449Ssam 	lcr = ((mbits & 037) << 8) | (lcr & 0xff);
65212449Ssam 	dmfaddr->dmfun.dmfirw = lcr;
6536940Ssam 	(void) splx(s);
6546940Ssam 	return(mbits);
6556940Ssam }
6566940Ssam 
6576940Ssam /*
6586940Ssam  * Reset state of driver if UBA reset was necessary.
6596940Ssam  * Reset the csr, lpr, and lcr registers on open lines, and
6606940Ssam  * restart transmitters.
6616940Ssam  */
6626940Ssam dmfreset(uban)
6636940Ssam 	int uban;
6646940Ssam {
6656940Ssam 	register int dmf, unit;
6666940Ssam 	register struct tty *tp;
6676940Ssam 	register struct uba_device *ui;
6686940Ssam 	register struct dmfdevice *addr;
6696940Ssam 	int i;
6706940Ssam 
6716940Ssam #ifdef DMFDMA
6726940Ssam 	if (dmf_ubinfo[uban] == 0)
6736940Ssam 		return;
6746940Ssam 	dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
6756940Ssam 	    nclist*sizeof (struct cblock), 0);
6766940Ssam 	cbase[uban] = dmf_ubinfo[uban]&0x3ffff;
6776940Ssam #endif
6786940Ssam 	for (dmf = 0; dmf < NDMF; dmf++) {
6796940Ssam 		ui = dmfinfo[dmf];
6806940Ssam 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
6816940Ssam 			continue;
6826940Ssam 		printf(" dmf%d", dmf);
6836940Ssam 		addr = (struct dmfdevice *)ui->ui_addr;
6846940Ssam 		addr->dmfcsr = DMF_IE;
6856940Ssam 		addr->dmfrsp = 1;
6866940Ssam 		unit = dmf * 8;
6876940Ssam 		for (i = 0; i < 8; i++) {
6886940Ssam 			tp = &dmf_tty[unit];
6896971Ssam 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
6906940Ssam 				dmfparam(unit);
6918702Sroot 				(void) dmfmctl(unit, DMF_ON, DMSET);
6926971Ssam 				tp->t_state &= ~TS_BUSY;
6936940Ssam 				dmfstart(tp);
6946940Ssam 			}
6956940Ssam 			unit++;
6966940Ssam 		}
6976940Ssam 	}
6986940Ssam }
6996940Ssam 
7006940Ssam /* stubs for interrupt routines for devices not yet supported */
7016940Ssam 
7026940Ssam dmfsrint() { printf("dmfsrint\n"); }
7036940Ssam 
7046940Ssam dmfsxint() { printf("dmfsxint\n"); }
7056940Ssam 
7066940Ssam dmfdaint() { printf("dmfdaint\n"); }
7076940Ssam 
7086940Ssam dmfdbint() { printf("dmfdbint\n"); }
7096940Ssam 
7106940Ssam dmflint() { printf("dmflint\n"); }
7116940Ssam #endif
712