xref: /csrg-svn/sys/vax/uba/dmf.c (revision 6940)
1*6940Ssam /*	dmf.c	4.1	82/05/26	*/
2*6940Ssam 
3*6940Ssam #include "dmf.h"
4*6940Ssam #if NDMF > 0
5*6940Ssam /*
6*6940Ssam  * DMF32 driver
7*6940Ssam  *
8*6940Ssam  * TODO:
9*6940Ssam  *	test with modem
10*6940Ssam  *	load as much as possible into silo
11*6940Ssam  *	get correct numbers for receive silo parameter timeout
12*6940Ssam  *	use auto XON/XOFF
13*6940Ssam  *	test reset code
14*6940Ssam  *	test with more than one unit
15*6940Ssam  *	optimize for efficient DMA and dynamically
16*6940Ssam  *	  decide between silo and DMA mode
17*6940Ssam  */
18*6940Ssam #include "bk.h"
19*6940Ssam #include "../h/param.h"
20*6940Ssam #include "../h/conf.h"
21*6940Ssam #include "../h/dir.h"
22*6940Ssam #include "../h/user.h"
23*6940Ssam #include "../h/tty.h"
24*6940Ssam #include "../h/map.h"
25*6940Ssam #include "../h/pte.h"
26*6940Ssam #include "../h/buf.h"
27*6940Ssam #include "../h/vm.h"
28*6940Ssam #include "../h/ubareg.h"
29*6940Ssam #include "../h/ubavar.h"
30*6940Ssam #include "../h/bk.h"
31*6940Ssam #include "../h/clist.h"
32*6940Ssam #include "../h/mx.h"
33*6940Ssam #include "../h/file.h"
34*6940Ssam 
35*6940Ssam /*
36*6940Ssam  * Definition of the driver for the auto-configuration program.
37*6940Ssam  */
38*6940Ssam int	dmfprobe(), dmfattach(), dmfrint(), dmfxint();
39*6940Ssam struct	uba_device *dmfinfo[NDMF];
40*6940Ssam u_short	dmfstd[] = { 0 };
41*6940Ssam struct	uba_driver dmfdriver =
42*6940Ssam 	{ dmfprobe, 0, dmfattach, 0, dmfstd, "dmf", dmfinfo };
43*6940Ssam 
44*6940Ssam /*
45*6940Ssam  * In this driver, "dmf" (unqualified) refers to the async portion
46*6940Ssam  * of the dmf32, "dmfc" to the combo portion, "dmfs" to the sync
47*6940Ssam  * portion, "dmfl" to the lp portion, and "dmfd" to the dr portion.
48*6940Ssam  */
49*6940Ssam struct dmfdevice
50*6940Ssam {
51*6940Ssam 	short	dmfccsr0;		/* combo csr 0 */
52*6940Ssam 	short	dmfccsr1;		/* combo csr 1 */
53*6940Ssam 	short	dmfs[4];
54*6940Ssam 	short	dmfcsr;			/* control-status register */
55*6940Ssam 	short	dmflpr;			/* line parameter register */
56*6940Ssam 	short	dmfrbuf;		/* receiver buffer (ro) */
57*6940Ssam 	union {
58*6940Ssam 		u_short	dmfirw;		/* indirect register word */
59*6940Ssam 		u_char	dmfirc[2];	/*    "         "    bytes */
60*6940Ssam 	} dmfun;
61*6940Ssam 	short	dmfl[2];
62*6940Ssam 	short	dmfd[4];
63*6940Ssam };
64*6940Ssam 
65*6940Ssam #define	dmfrsp	dmfrbuf		/* receive silo parameter register (wo) */
66*6940Ssam #define	dmftbuf	dmfun.dmfirc[0]	/* transmit buffer */
67*6940Ssam #define	dmftsc	dmfun.dmfirc[0]	/* transmit silo count */
68*6940Ssam #define	dmfrms	dmfun.dmfirc[1]	/* receive modem status */
69*6940Ssam #define	dmflcr	dmfun.dmfirc[0]	/* line control register */
70*6940Ssam #define	dmftms	dmfun.dmfirc[1]	/* transmit modem status */
71*6940Ssam #define	dmftba	dmfun.dmfirw	/* transmit buffer address */
72*6940Ssam #define	dmftcc	dmfun.dmfirw	/* transmit character count */
73*6940Ssam 
74*6940Ssam /* bits in dmfcsr */
75*6940Ssam #define	DMF_TI	0100000		/* transmit interrupt */
76*6940Ssam #define	DMF_TIE	0040000		/* transmit interrupt enable */
77*6940Ssam #define	DMF_NXM	0020000		/* non-existant memory */
78*6940Ssam #define	DMF_LIN	0003400		/* transmit line number */
79*6940Ssam #define	DMF_RI	0000200		/* receiver interrupt */
80*6940Ssam #define	DMF_RIE	0000100		/* receiver interrupt enable */
81*6940Ssam #define	DMF_CLR	0000040		/* master reset */
82*6940Ssam #define	DMF_IAD	0000037		/* indirect address register */
83*6940Ssam 
84*6940Ssam #define	DMFIR_TBUF	000	/* select tbuf indirect register */
85*6940Ssam #define	DMFIR_LCR	010	/* select lcr indirect register */
86*6940Ssam #define	DMFIR_TBA	020	/* select tba indirect register */
87*6940Ssam #define	DMFIR_TCC	030	/* select tcc indirect register */
88*6940Ssam 
89*6940Ssam /* bits in dmflpr */
90*6940Ssam #define	BITS6	(01<<3)
91*6940Ssam #define	BITS7	(02<<3)
92*6940Ssam #define	BITS8	(03<<3)
93*6940Ssam #define	TWOSB	0200
94*6940Ssam #define	PENABLE	040
95*6940Ssam /* DEC manuals incorrectly say this bit causes generation of even parity. */
96*6940Ssam #define	OPAR	0100
97*6940Ssam 
98*6940Ssam #define	DMF_IE	(DMF_TIE|DMF_RIE)
99*6940Ssam 
100*6940Ssam #define	DMF_SILOCNT	32		/* size of DMF output silo (per line) */
101*6940Ssam 
102*6940Ssam /* bits in dmfrbuf */
103*6940Ssam #define	DMF_DSC		0004000		/* data set change */
104*6940Ssam #define	DMF_PE		0010000		/* parity error */
105*6940Ssam #define	DMF_FE		0020000		/* framing error */
106*6940Ssam #define	DMF_DO		0040000		/* data overrun */
107*6940Ssam 
108*6940Ssam /* bits in dmfrms */
109*6940Ssam #define	DMF_USRR	0004		/* user modem signal (pin 25) */
110*6940Ssam #define	DMF_SR		0010		/* secondary receive */
111*6940Ssam #define	DMF_CTS		0020		/* clear to send */
112*6940Ssam #define	DMF_CAR		0040		/* carrier detect */
113*6940Ssam #define	DMF_RNG		0100		/* ring */
114*6940Ssam #define	DMF_DSR		0200		/* data set ready */
115*6940Ssam 
116*6940Ssam /* bits in dmftms */
117*6940Ssam #define	DMF_USRW	0001		/* user modem signal (pin 18) */
118*6940Ssam #define	DMF_DTR		0002		/* data terminal ready */
119*6940Ssam #define	DMF_RATE	0004		/* data signal rate select */
120*6940Ssam #define	DMF_ST		0010		/* secondary transmit */
121*6940Ssam #define	DMF_RTS		0020		/* request to send */
122*6940Ssam #define	DMF_BRK		0040		/* pseudo break bit */
123*6940Ssam #define	DMF_PREEMPT	0200		/* preempt output */
124*6940Ssam 
125*6940Ssam /* flags for modem control */
126*6940Ssam #define	DMF_ON	(DMF_DTR|DMF_RTS)
127*6940Ssam #define	DMF_OFF	0
128*6940Ssam 
129*6940Ssam /* bits in dmflcr */
130*6940Ssam #define	DMF_MIE		0040		/* modem interrupt enable */
131*6940Ssam #define	DMF_FLUSH	0020		/* flush transmit silo */
132*6940Ssam #define	DMF_RBRK	0010		/* real break bit */
133*6940Ssam #define	DMF_RE		0004		/* receive enable */
134*6940Ssam #define	DMF_AUTOX	0002		/* auto XON/XOFF */
135*6940Ssam #define	DMF_TE		0001		/* transmit enable */
136*6940Ssam 
137*6940Ssam #define	DMFLCR_ENA	(DMF_MIE|DMF_RE|DMF_TE)
138*6940Ssam 
139*6940Ssam /* bits in dm lsr, copied from dh.c */
140*6940Ssam #define	DML_USR		0001000		/* usr modem sig, not a real DM bit */
141*6940Ssam #define	DML_DSR		0000400		/* data set ready, not a real DM bit */
142*6940Ssam #define	DML_RNG		0000200		/* ring */
143*6940Ssam #define	DML_CAR		0000100		/* carrier detect */
144*6940Ssam #define	DML_CTS		0000040		/* clear to send */
145*6940Ssam #define	DML_SR		0000020		/* secondary receive */
146*6940Ssam #define	DML_ST		0000010		/* secondary transmit */
147*6940Ssam #define	DML_RTS		0000004		/* request to send */
148*6940Ssam #define	DML_DTR		0000002		/* data terminal ready */
149*6940Ssam #define	DML_LE		0000001		/* line enable */
150*6940Ssam 
151*6940Ssam /*
152*6940Ssam  * Local variables for the driver
153*6940Ssam  */
154*6940Ssam char	dmf_speeds[] =
155*6940Ssam 	{ 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 010, 012, 014, 016, 017, 0 };
156*6940Ssam 
157*6940Ssam struct	tty dmf_tty[NDMF*8];
158*6940Ssam char	dmfsoftCAR[NDMF];
159*6940Ssam int	ndmf = NDMF*8;
160*6940Ssam int	dmfact;				/* mask of active dmf's */
161*6940Ssam int	dmfstart(), ttrstrt();
162*6940Ssam 
163*6940Ssam #ifdef DMFDMA
164*6940Ssam /*
165*6940Ssam  * The clist space is mapped by the driver onto each UNIBUS.
166*6940Ssam  * The UBACVT macro converts a clist space address for unibus uban
167*6940Ssam  * into an i/o space address for the DMA routine.
168*6940Ssam  */
169*6940Ssam int	dmf_ubinfo[MAXNUBA];		/* info about allocated unibus map */
170*6940Ssam static int cbase[MAXNUBA];		/* base address in unibus map */
171*6940Ssam #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
172*6940Ssam #endif
173*6940Ssam 
174*6940Ssam /*
175*6940Ssam  * Routine for configuration to set dmf interrupt.
176*6940Ssam  */
177*6940Ssam /*ARGSUSED*/
178*6940Ssam dmfprobe(reg, ctlr)
179*6940Ssam 	caddr_t reg;
180*6940Ssam 	int ctlr;
181*6940Ssam {
182*6940Ssam 	register int br, cvec;		/* these are ``value-result'' */
183*6940Ssam 	register struct dmfdevice *dmfaddr = (struct dmfdevice *)reg;
184*6940Ssam 
185*6940Ssam #ifdef lint
186*6940Ssam 	br = 0; cvec = br; br = cvec;
187*6940Ssam #endif
188*6940Ssam 	br = 0x15;
189*6940Ssam 	cvec = (uba_hd[numuba].uh_lastiv -= 4*8);
190*6940Ssam 	dmfaddr->dmfccsr0 = cvec >> 2;
191*6940Ssam 	/* NEED TO SAVE IT SOMEWHERE FOR OTHER DEVICES */
192*6940Ssam 	return (1);
193*6940Ssam }
194*6940Ssam 
195*6940Ssam /*
196*6940Ssam  * Routine called to attach a dmf.
197*6940Ssam  */
198*6940Ssam dmfattach(ui)
199*6940Ssam 	struct uba_device *ui;
200*6940Ssam {
201*6940Ssam 
202*6940Ssam 	dmfsoftCAR[ui->ui_unit] = ui->ui_flags;
203*6940Ssam }
204*6940Ssam 
205*6940Ssam 
206*6940Ssam /*
207*6940Ssam  * Open a DMF32 line, mapping the clist onto the uba if this
208*6940Ssam  * is the first dmf on this uba.  Turn on this dmf if this is
209*6940Ssam  * the first use of it.
210*6940Ssam  */
211*6940Ssam /*ARGSUSED*/
212*6940Ssam dmfopen(dev, flag)
213*6940Ssam 	dev_t dev;
214*6940Ssam {
215*6940Ssam 	register struct tty *tp;
216*6940Ssam 	register int unit, dmf;
217*6940Ssam 	register struct dmfdevice *addr;
218*6940Ssam 	register struct uba_device *ui;
219*6940Ssam 	int s;
220*6940Ssam 
221*6940Ssam 	unit = minor(dev);
222*6940Ssam 	dmf = unit >> 3;
223*6940Ssam 	if (unit >= NDMF*8 || (ui = dmfinfo[dmf])== 0 || ui->ui_alive == 0) {
224*6940Ssam 		u.u_error = ENXIO;
225*6940Ssam 		return;
226*6940Ssam 	}
227*6940Ssam 	tp = &dmf_tty[unit];
228*6940Ssam 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
229*6940Ssam 		u.u_error = EBUSY;
230*6940Ssam 		return;
231*6940Ssam 	}
232*6940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
233*6940Ssam 	tp->t_addr = (caddr_t)addr;
234*6940Ssam 	tp->t_oproc = dmfstart;
235*6940Ssam 	tp->t_iproc = NULL;
236*6940Ssam 	tp->t_state |= WOPEN;
237*6940Ssam 	/*
238*6940Ssam 	 * While setting up state for this uba and this dmf,
239*6940Ssam 	 * block uba resets which can clear the state.
240*6940Ssam 	 */
241*6940Ssam 	s = spl5();
242*6940Ssam #ifdef DMFDMA
243*6940Ssam 	if (dmf_ubinfo[ui->ui_ubanum] == 0) {
244*6940Ssam 		dmf_ubinfo[ui->ui_ubanum] =
245*6940Ssam 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
246*6940Ssam 			nclist*sizeof(struct cblock), 0);
247*6940Ssam 		cbase[ui->ui_ubanum] = dmf_ubinfo[ui->ui_ubanum]&0x3ffff;
248*6940Ssam 	}
249*6940Ssam #endif
250*6940Ssam 	if ((dmfact&(1<<dmf)) == 0) {
251*6940Ssam 		addr->dmfcsr |= DMF_IE;
252*6940Ssam 		dmfact |= (1<<dmf);
253*6940Ssam 		addr->dmfrsp = 1;	/* DON'T KNOW WHAT TO SET IT TO YET */
254*6940Ssam 	}
255*6940Ssam 	splx(s);
256*6940Ssam 	/*
257*6940Ssam 	 * If this is first open, initialze tty state to default.
258*6940Ssam 	 */
259*6940Ssam 	if ((tp->t_state&ISOPEN) == 0) {
260*6940Ssam 		ttychars(tp);
261*6940Ssam 		if (tp->t_ispeed == 0) {
262*6940Ssam 			tp->t_ispeed = B300;
263*6940Ssam 			tp->t_ospeed = B300;
264*6940Ssam 			tp->t_flags = ODDP|EVENP|ECHO;
265*6940Ssam 		}
266*6940Ssam 		dmfparam(unit);
267*6940Ssam 	}
268*6940Ssam 	/*
269*6940Ssam 	 * Wait for carrier, then process line discipline specific open.
270*6940Ssam 	 */
271*6940Ssam 	if ((dmfmctl(dev, DMF_ON, DMSET) & (DMF_CAR<<8)) ||
272*6940Ssam 	    (dmfsoftCAR[dmf] & (1<<(unit&07))))
273*6940Ssam 		tp->t_state |= CARR_ON;
274*6940Ssam 	s = spl5();
275*6940Ssam 	while ((tp->t_state & CARR_ON) == 0) {
276*6940Ssam 		tp->t_state |= WOPEN;
277*6940Ssam 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
278*6940Ssam 	}
279*6940Ssam 	splx(s);
280*6940Ssam 	(*linesw[tp->t_line].l_open)(dev, tp);
281*6940Ssam }
282*6940Ssam 
283*6940Ssam /*
284*6940Ssam  * Close a DMF32 line.
285*6940Ssam  */
286*6940Ssam /*ARGSUSED*/
287*6940Ssam dmfclose(dev, flag)
288*6940Ssam 	dev_t dev;
289*6940Ssam 	int flag;
290*6940Ssam {
291*6940Ssam 	register struct tty *tp;
292*6940Ssam 	register unit;
293*6940Ssam 
294*6940Ssam 	unit = minor(dev);
295*6940Ssam 	tp = &dmf_tty[unit];
296*6940Ssam 	(*linesw[tp->t_line].l_close)(tp);
297*6940Ssam 	dmfmctl(unit, DMF_BRK, DMBIC);
298*6940Ssam 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
299*6940Ssam 		dmfmctl(unit, DMF_OFF, DMSET);
300*6940Ssam 	ttyclose(tp);
301*6940Ssam }
302*6940Ssam 
303*6940Ssam dmfread(dev)
304*6940Ssam 	dev_t dev;
305*6940Ssam {
306*6940Ssam 	register struct tty *tp;
307*6940Ssam 
308*6940Ssam 	tp = &dmf_tty[minor(dev)];
309*6940Ssam 	(*linesw[tp->t_line].l_read)(tp);
310*6940Ssam }
311*6940Ssam 
312*6940Ssam dmfwrite(dev)
313*6940Ssam 	dev_t dev;
314*6940Ssam {
315*6940Ssam 	register struct tty *tp;
316*6940Ssam 
317*6940Ssam 	tp = &dmf_tty[minor(dev)];
318*6940Ssam 	(*linesw[tp->t_line].l_write)(tp);
319*6940Ssam }
320*6940Ssam 
321*6940Ssam /*
322*6940Ssam  * DMF32 receiver interrupt.
323*6940Ssam  */
324*6940Ssam dmfrint(dmf)
325*6940Ssam 	int dmf;
326*6940Ssam {
327*6940Ssam 	register struct tty *tp;
328*6940Ssam 	register c;
329*6940Ssam 	register struct dmfdevice *addr;
330*6940Ssam 	register struct tty *tp0;
331*6940Ssam 	register struct uba_device *ui;
332*6940Ssam 	int overrun = 0;
333*6940Ssam 
334*6940Ssam 	ui = dmfinfo[dmf];
335*6940Ssam 	if (ui == 0 || ui->ui_alive == 0)
336*6940Ssam 		return;
337*6940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
338*6940Ssam 	tp0 = &dmf_tty[dmf<<3];
339*6940Ssam 	/*
340*6940Ssam 	 * Loop fetching characters from the silo for this
341*6940Ssam 	 * dmf until there are no more in the silo.
342*6940Ssam 	 */
343*6940Ssam 	while ((c = addr->dmfrbuf) < 0) {
344*6940Ssam 		tp = tp0 + ((c>>8)&07);
345*6940Ssam 		if (c & DMF_DSC) {
346*6940Ssam 			addr->dmfcsr = DMF_IE | DMFIR_TBUF | ((c>>8)&07);
347*6940Ssam 			if (addr->dmfrms & DMF_CAR) {
348*6940Ssam 				if ((tp->t_state & CARR_ON) == 0) {
349*6940Ssam 					wakeup((caddr_t)&tp->t_rawq);
350*6940Ssam 					tp->t_state |= CARR_ON;
351*6940Ssam 				}
352*6940Ssam 			} else {
353*6940Ssam 				if (tp->t_state & CARR_ON) {
354*6940Ssam 					gsignal(tp->t_pgrp, SIGHUP);
355*6940Ssam 					gsignal(tp->t_pgrp, SIGCONT);
356*6940Ssam 					addr->dmfcsr = DMF_IE | DMFIR_LCR |
357*6940Ssam 						((c>>8)&07);
358*6940Ssam 					addr->dmftms = 0;
359*6940Ssam 					flushtty(tp, FREAD|FWRITE);
360*6940Ssam 				}
361*6940Ssam 				tp->t_state &= ~CARR_ON;
362*6940Ssam 			}
363*6940Ssam 			continue;
364*6940Ssam 		}
365*6940Ssam 		if ((tp->t_state&ISOPEN)==0) {
366*6940Ssam 			wakeup((caddr_t)tp);
367*6940Ssam 			continue;
368*6940Ssam 		}
369*6940Ssam 		if (c & DMF_PE)
370*6940Ssam 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
371*6940Ssam 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
372*6940Ssam 				continue;
373*6940Ssam 		if ((c & DMF_DO) && overrun == 0) {
374*6940Ssam 			printf("dmf%d: silo overflow\n", dmf);
375*6940Ssam 			overrun = 1;
376*6940Ssam 		}
377*6940Ssam 		if (c & DMF_FE)
378*6940Ssam 			/*
379*6940Ssam 			 * At framing error (break) generate
380*6940Ssam 			 * a null (in raw mode, for getty), or a
381*6940Ssam 			 * interrupt (in cooked/cbreak mode).
382*6940Ssam 			 */
383*6940Ssam 			if (tp->t_flags&RAW)
384*6940Ssam 				c = 0;
385*6940Ssam 			else
386*6940Ssam 				c = tun.t_intrc;
387*6940Ssam #if NBK > 0
388*6940Ssam 		if (tp->t_line == NETLDISC) {
389*6940Ssam 			c &= 0177;
390*6940Ssam 			BKINPUT(c, tp);
391*6940Ssam 		} else
392*6940Ssam #endif
393*6940Ssam 			(*linesw[tp->t_line].l_rint)(c, tp);
394*6940Ssam 	}
395*6940Ssam }
396*6940Ssam 
397*6940Ssam /*
398*6940Ssam  * Ioctl for DMF32.
399*6940Ssam  */
400*6940Ssam /*ARGSUSED*/
401*6940Ssam dmfioctl(dev, cmd, addr, flag)
402*6940Ssam 	dev_t dev;
403*6940Ssam 	caddr_t addr;
404*6940Ssam {
405*6940Ssam 	register struct tty *tp;
406*6940Ssam 	register int unit = minor(dev);
407*6940Ssam 	register int dmf = unit >> 3;
408*6940Ssam 	register struct device *dmfaddr;
409*6940Ssam 	int temp;
410*6940Ssam 
411*6940Ssam 	tp = &dmf_tty[unit];
412*6940Ssam 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
413*6940Ssam 	if (cmd == 0)
414*6940Ssam 		return;
415*6940Ssam 	if (ttioctl(tp, cmd, addr, flag)) {
416*6940Ssam 		if (cmd==TIOCSETP || cmd==TIOCSETN)
417*6940Ssam 			dmfparam(unit);
418*6940Ssam 	} else switch(cmd) {
419*6940Ssam 
420*6940Ssam 	case TIOCSBRK:
421*6940Ssam 		dmfmctl(dev, DMF_BRK, DMBIS);
422*6940Ssam 		break;
423*6940Ssam 	case TIOCCBRK:
424*6940Ssam 		dmfmctl(dev, DMF_BRK, DMBIC);
425*6940Ssam 		break;
426*6940Ssam 	case TIOCSDTR:
427*6940Ssam 		dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIS);
428*6940Ssam 		break;
429*6940Ssam 	case TIOCCDTR:
430*6940Ssam 		dmfmctl(dev, DMF_DTR|DMF_RTS, DMBIC);
431*6940Ssam 		break;
432*6940Ssam 	case TIOCMSET:
433*6940Ssam 		if (copyin(addr, (caddr_t) &temp, sizeof(temp)))
434*6940Ssam 			u.u_error = EFAULT;
435*6940Ssam 		else
436*6940Ssam 			dmfmctl(dev, dmtodmf(temp), DMSET);
437*6940Ssam 		break;
438*6940Ssam 	case TIOCMBIS:
439*6940Ssam 		if (copyin(addr, (caddr_t) &temp, sizeof(temp)))
440*6940Ssam 			u.u_error = EFAULT;
441*6940Ssam 		else
442*6940Ssam 			dmfmctl(dev, dmtodmf(temp), DMBIS);
443*6940Ssam 		break;
444*6940Ssam 	case TIOCMBIC:
445*6940Ssam 		if (copyin(addr, (caddr_t) &temp, sizeof(temp)))
446*6940Ssam 			u.u_error = EFAULT;
447*6940Ssam 		else
448*6940Ssam 			dmfmctl(dev, dmtodmf(temp), DMBIC);
449*6940Ssam 		break;
450*6940Ssam 	case TIOCMGET:
451*6940Ssam 		temp = dmftodm(dmfmctl(dev, 0, DMGET));
452*6940Ssam 		if (copyout((caddr_t) &temp, addr, sizeof(temp)))
453*6940Ssam 			u.u_error = EFAULT;
454*6940Ssam 		break;
455*6940Ssam 	default:
456*6940Ssam 		u.u_error = ENOTTY;
457*6940Ssam 	}
458*6940Ssam }
459*6940Ssam 
460*6940Ssam dmtodmf(bits)
461*6940Ssam 	register int bits;
462*6940Ssam {
463*6940Ssam 	register int b;
464*6940Ssam 
465*6940Ssam 	b = bits & 012;
466*6940Ssam 	if (bits & DML_ST) b |= DMF_RATE;
467*6940Ssam 	if (bits & DML_RTS) b |= DMF_RTS;
468*6940Ssam 	if (bits & DML_USR) b |= DMF_USRW;
469*6940Ssam 	return(b);
470*6940Ssam }
471*6940Ssam 
472*6940Ssam dmftodm(bits)
473*6940Ssam 	register int bits;
474*6940Ssam {
475*6940Ssam 	register int b;
476*6940Ssam 
477*6940Ssam 	b = (bits & 012) | ((bits >> 7) & 0760) | DML_LE;
478*6940Ssam 	if (bits & DMF_USRR) b |= DML_USR;
479*6940Ssam 	if (bits & DMF_RTS) b |= DML_RTS;
480*6940Ssam 	return(b);
481*6940Ssam }
482*6940Ssam 
483*6940Ssam 
484*6940Ssam /*
485*6940Ssam  * Set parameters from open or stty into the DMF hardware
486*6940Ssam  * registers.
487*6940Ssam  */
488*6940Ssam dmfparam(unit)
489*6940Ssam 	register int unit;
490*6940Ssam {
491*6940Ssam 	register struct tty *tp;
492*6940Ssam 	register struct dmfdevice *addr;
493*6940Ssam 	register int lpar, lcr;
494*6940Ssam 	int s;
495*6940Ssam 
496*6940Ssam 	tp = &dmf_tty[unit];
497*6940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
498*6940Ssam 	/*
499*6940Ssam 	 * Block interrupts so parameters will be set
500*6940Ssam 	 * before the line interrupts.
501*6940Ssam 	 */
502*6940Ssam 	s = spl5();
503*6940Ssam 	addr->dmfcsr = (unit&07) | DMFIR_LCR | DMF_IE;
504*6940Ssam 	if ((tp->t_ispeed)==0) {
505*6940Ssam 		tp->t_state |= HUPCLS;
506*6940Ssam 		dmfmctl(unit, DMF_OFF, DMSET);
507*6940Ssam 		return;
508*6940Ssam 	}
509*6940Ssam 	lpar = (dmf_speeds[tp->t_ospeed]<<12) | (dmf_speeds[tp->t_ispeed]<<8);
510*6940Ssam 	lcr = DMFLCR_ENA;
511*6940Ssam 	if ((tp->t_ispeed) == B134)
512*6940Ssam 		lpar |= BITS6|PENABLE;
513*6940Ssam 	else if ((tp->t_flags&RAW) || (tp->t_local&LLITOUT))
514*6940Ssam 		lpar |= BITS8;
515*6940Ssam 	else {
516*6940Ssam 		lpar |= BITS7|PENABLE;
517*6940Ssam 		/* CHECK FOR XON/XOFF AND SET lcr |= DMF_AUTOX; */
518*6940Ssam 	}
519*6940Ssam 	if ((tp->t_flags&EVENP) == 0)
520*6940Ssam 		lpar |= OPAR;
521*6940Ssam 	if ((tp->t_ospeed) == B110)
522*6940Ssam 		lpar |= TWOSB;
523*6940Ssam 	lpar |= (unit&07);
524*6940Ssam 	addr->dmflpr = lpar;
525*6940Ssam 	addr->dmflcr = lcr;
526*6940Ssam 	splx(s);
527*6940Ssam }
528*6940Ssam 
529*6940Ssam /*
530*6940Ssam  * DMF32 transmitter interrupt.
531*6940Ssam  * Restart the idle line.
532*6940Ssam  */
533*6940Ssam dmfxint(dmf)
534*6940Ssam 	int dmf;
535*6940Ssam {
536*6940Ssam 	register struct tty *tp;
537*6940Ssam 	register struct dmfdevice *addr;
538*6940Ssam 	register struct uba_device *ui;
539*6940Ssam 	register int unit, t;
540*6940Ssam #ifdef DMFDMA
541*6940Ssam 	short cntr;
542*6940Ssam #endif
543*6940Ssam 
544*6940Ssam 	ui = dmfinfo[dmf];
545*6940Ssam 	addr = (struct dmfdevice *)ui->ui_addr;
546*6940Ssam 	while ((t = addr->dmfcsr) & DMF_TI) {
547*6940Ssam 		unit = dmf*8 + ((t>>8)&07);
548*6940Ssam 		tp = &dmf_tty[unit];
549*6940Ssam 		tp->t_state &= ~BUSY;
550*6940Ssam 		if (t & DMF_NXM) {
551*6940Ssam 			printf("dmf%d: NXM line %d\n", dmf, unit&7);
552*6940Ssam 			/* SHOULD RESTART OR SOMETHING... */
553*6940Ssam 		}
554*6940Ssam 		if (tp->t_state&FLUSH)
555*6940Ssam 			tp->t_state &= ~FLUSH;
556*6940Ssam #ifdef DMFDMA
557*6940Ssam 		else {
558*6940Ssam 			addr->dmfcsr = DMFIR_TBUF | DMF_IE | (unit&07);
559*6940Ssam 			if (addr->dmftsc == 0) {
560*6940Ssam 				/*
561*6940Ssam 				 * Do arithmetic in a short to make up
562*6940Ssam 				 * for lost 16&17 bits.
563*6940Ssam 				 */
564*6940Ssam 				addr->dmfcsr = DMFIR_TBA | DMF_IE | (unit&07);
565*6940Ssam 				cntr = addr->dmftba -
566*6940Ssam 				    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
567*6940Ssam 				ndflush(&tp->t_outq, (int)cntr);
568*6940Ssam 			}
569*6940Ssam 		}
570*6940Ssam #endif
571*6940Ssam 		if (tp->t_line)
572*6940Ssam 			(*linesw[tp->t_line].l_start)(tp);
573*6940Ssam 		else
574*6940Ssam 			dmfstart(tp);
575*6940Ssam 	}
576*6940Ssam }
577*6940Ssam 
578*6940Ssam /*
579*6940Ssam  * Start (restart) transmission on the given DMF32 line.
580*6940Ssam  */
581*6940Ssam dmfstart(tp)
582*6940Ssam 	register struct tty *tp;
583*6940Ssam {
584*6940Ssam 	register struct dmfdevice *addr;
585*6940Ssam 	register int car, dmf, unit, nch;
586*6940Ssam 	int s;
587*6940Ssam 
588*6940Ssam 	unit = minor(tp->t_dev);
589*6940Ssam 	dmf = unit >> 3;
590*6940Ssam 	unit &= 07;
591*6940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
592*6940Ssam 
593*6940Ssam 	/*
594*6940Ssam 	 * Must hold interrupts in following code to prevent
595*6940Ssam 	 * state of the tp from changing.
596*6940Ssam 	 */
597*6940Ssam 	s = spl5();
598*6940Ssam 	/*
599*6940Ssam 	 * If it's currently active, or delaying, no need to do anything.
600*6940Ssam 	 */
601*6940Ssam 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
602*6940Ssam 		goto out;
603*6940Ssam 	/*
604*6940Ssam 	 * If there are still characters in the silo,
605*6940Ssam 	 * just reenable the transmitter.
606*6940Ssam 	 */
607*6940Ssam 	addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
608*6940Ssam 	if (addr->dmftsc) {
609*6940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
610*6940Ssam 		addr->dmflcr |= DMF_TE;
611*6940Ssam 		tp->t_state |= BUSY;
612*6940Ssam 		goto out;
613*6940Ssam 	}
614*6940Ssam 	/*
615*6940Ssam 	 * If there are sleepers, and output has drained below low
616*6940Ssam 	 * water mark, wake up the sleepers.
617*6940Ssam 	 */
618*6940Ssam 	if ((tp->t_state&ASLEEP) && tp->t_outq.c_cc<=TTLOWAT(tp)) {
619*6940Ssam 		tp->t_state &= ~ASLEEP;
620*6940Ssam 		if (tp->t_chan)
621*6940Ssam 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
622*6940Ssam 		else
623*6940Ssam 			wakeup((caddr_t)&tp->t_outq);
624*6940Ssam 	}
625*6940Ssam 	/*
626*6940Ssam 	 * Now restart transmission unless the output queue is
627*6940Ssam 	 * empty.
628*6940Ssam 	 */
629*6940Ssam 	if (tp->t_outq.c_cc == 0)
630*6940Ssam 		goto out;
631*6940Ssam 	if (tp->t_flags&RAW || tp->t_local&LLITOUT)
632*6940Ssam 		nch = ndqb(&tp->t_outq, 0);
633*6940Ssam 	else {
634*6940Ssam 		nch = ndqb(&tp->t_outq, 0200);
635*6940Ssam 		/*
636*6940Ssam 		 * If first thing on queue is a delay process it.
637*6940Ssam 		 */
638*6940Ssam 		if (nch == 0) {
639*6940Ssam 			nch = getc(&tp->t_outq);
640*6940Ssam 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
641*6940Ssam 			tp->t_state |= TIMEOUT;
642*6940Ssam 			goto out;
643*6940Ssam 		}
644*6940Ssam 	}
645*6940Ssam 	/*
646*6940Ssam 	 * If characters to transmit, restart transmission.
647*6940Ssam 	 */
648*6940Ssam 	if (nch) {
649*6940Ssam #ifdef DMFDMA
650*6940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
651*6940Ssam 		addr->dmflcr |= DMF_TE;
652*6940Ssam 		car = UBACVT(tp->t_outq.c_cf, dmfinfo[dmf]->ui_ubanum);
653*6940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_TBA | unit;
654*6940Ssam 		addr->dmftba = car;
655*6940Ssam 		addr->dmftcc = ((car>>2)&0xc000) | nch;
656*6940Ssam #else
657*6940Ssam 		register char *cp = tp->t_outq.c_cf;
658*6940Ssam 		register int i;
659*6940Ssam 
660*6940Ssam 		nch = MIN(nch, DMF_SILOCNT);
661*6940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
662*6940Ssam 		addr->dmflcr |= DMF_TE;
663*6940Ssam 		addr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
664*6940Ssam 		for (i = 0; i < nch; i++)
665*6940Ssam 			addr->dmftbuf = *cp++;
666*6940Ssam 		ndflush(&tp->t_outq, nch);
667*6940Ssam #endif
668*6940Ssam 		tp->t_state |= BUSY;
669*6940Ssam 	}
670*6940Ssam out:
671*6940Ssam 	splx(s);
672*6940Ssam }
673*6940Ssam 
674*6940Ssam /*
675*6940Ssam  * Stop output on a line, e.g. for ^S/^Q or output flush.
676*6940Ssam  */
677*6940Ssam /*ARGSUSED*/
678*6940Ssam dmfstop(tp, flag)
679*6940Ssam 	register struct tty *tp;
680*6940Ssam {
681*6940Ssam 	register struct dmfdevice *addr;
682*6940Ssam 	register int unit, s;
683*6940Ssam 
684*6940Ssam 	addr = (struct dmfdevice *)tp->t_addr;
685*6940Ssam 	/*
686*6940Ssam 	 * Block input/output interrupts while messing with state.
687*6940Ssam 	 */
688*6940Ssam 	s = spl5();
689*6940Ssam 	if (tp->t_state & BUSY) {
690*6940Ssam 		/*
691*6940Ssam 		 * Device is transmitting; stop output
692*6940Ssam 		 * by selecting the line and disabling
693*6940Ssam 		 * the transmitter.  If this is a flush
694*6940Ssam 		 * request then flush the output silo,
695*6940Ssam 		 * otherwise we will pick up where we
696*6940Ssam 		 * left off by enabling the transmitter.
697*6940Ssam 		 */
698*6940Ssam 		unit = minor(tp->t_dev);
699*6940Ssam 		addr->dmfcsr = DMFIR_LCR | (unit&07) | DMF_IE;
700*6940Ssam 		addr->dmflcr &= ~DMF_TE;
701*6940Ssam 		if ((tp->t_state&TTSTOP)==0) {
702*6940Ssam 			tp->t_state |= FLUSH;
703*6940Ssam 			addr->dmflcr |= DMF_FLUSH;
704*6940Ssam 		} else
705*6940Ssam 			tp->t_state &= ~BUSY;
706*6940Ssam 	}
707*6940Ssam 	splx(s);
708*6940Ssam }
709*6940Ssam 
710*6940Ssam /*
711*6940Ssam  * DMF32 modem control
712*6940Ssam  */
713*6940Ssam dmfmctl(dev, bits, how)
714*6940Ssam 	dev_t dev;
715*6940Ssam 	int bits, how;
716*6940Ssam {
717*6940Ssam 	register struct dmfdevice *dmfaddr;
718*6940Ssam 	register int unit, mbits, lcr;
719*6940Ssam 	int s;
720*6940Ssam 
721*6940Ssam 	unit = minor(dev);
722*6940Ssam 	dmfaddr = (struct dmfdevice *)(dmf_tty[unit].t_addr);
723*6940Ssam 	unit &= 07;
724*6940Ssam 	s = spl5();
725*6940Ssam 	dmfaddr->dmfcsr = DMF_IE | DMFIR_TBUF | unit;
726*6940Ssam 	mbits = dmfaddr->dmfrms << 8;
727*6940Ssam 	dmfaddr->dmfcsr = DMF_IE | DMFIR_LCR | unit;
728*6940Ssam 	mbits |= dmfaddr->dmftms;
729*6940Ssam 	lcr = dmfaddr->dmflcr;
730*6940Ssam 	switch (how) {
731*6940Ssam 	case DMSET:
732*6940Ssam 		mbits = bits;
733*6940Ssam 		break;
734*6940Ssam 
735*6940Ssam 	case DMBIS:
736*6940Ssam 		mbits |= bits;
737*6940Ssam 		break;
738*6940Ssam 
739*6940Ssam 	case DMBIC:
740*6940Ssam 		mbits &= ~bits;
741*6940Ssam 		break;
742*6940Ssam 
743*6940Ssam 	case DMGET:
744*6940Ssam 		(void) splx(s);
745*6940Ssam 		return(mbits);
746*6940Ssam 	}
747*6940Ssam 	dmfaddr->dmftms = mbits&037;
748*6940Ssam 	if (mbits & DMF_BRK)
749*6940Ssam 		lcr |= DMF_RBRK;
750*6940Ssam 	else
751*6940Ssam 		lcr &= ~DMF_RBRK;
752*6940Ssam 	dmfaddr->dmflcr = lcr;
753*6940Ssam 	(void) splx(s);
754*6940Ssam 	return(mbits);
755*6940Ssam }
756*6940Ssam 
757*6940Ssam /*
758*6940Ssam  * Reset state of driver if UBA reset was necessary.
759*6940Ssam  * Reset the csr, lpr, and lcr registers on open lines, and
760*6940Ssam  * restart transmitters.
761*6940Ssam  */
762*6940Ssam dmfreset(uban)
763*6940Ssam 	int uban;
764*6940Ssam {
765*6940Ssam 	register int dmf, unit;
766*6940Ssam 	register struct tty *tp;
767*6940Ssam 	register struct uba_device *ui;
768*6940Ssam 	register struct dmfdevice *addr;
769*6940Ssam 	int i;
770*6940Ssam 
771*6940Ssam #ifdef DMFDMA
772*6940Ssam 	if (dmf_ubinfo[uban] == 0)
773*6940Ssam 		return;
774*6940Ssam 	ubarelse(uban, &dmf_ubinfo[uban]);
775*6940Ssam 	dmf_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
776*6940Ssam 	    nclist*sizeof (struct cblock), 0);
777*6940Ssam 	cbase[uban] = dmf_ubinfo[uban]&0x3ffff;
778*6940Ssam #endif
779*6940Ssam 	for (dmf = 0; dmf < NDMF; dmf++) {
780*6940Ssam 		ui = dmfinfo[dmf];
781*6940Ssam 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
782*6940Ssam 			continue;
783*6940Ssam 		printf(" dmf%d", dmf);
784*6940Ssam 		addr = (struct dmfdevice *)ui->ui_addr;
785*6940Ssam 		addr->dmfcsr = DMF_IE;
786*6940Ssam 		addr->dmfrsp = 1;
787*6940Ssam 		unit = dmf * 8;
788*6940Ssam 		for (i = 0; i < 8; i++) {
789*6940Ssam 			tp = &dmf_tty[unit];
790*6940Ssam 			if (tp->t_state & (ISOPEN|WOPEN)) {
791*6940Ssam 				dmfparam(unit);
792*6940Ssam 				dmfmctl(unit, DMF_ON, DMSET);
793*6940Ssam 				tp->t_state &= ~BUSY;
794*6940Ssam 				dmfstart(tp);
795*6940Ssam 			}
796*6940Ssam 			unit++;
797*6940Ssam 		}
798*6940Ssam 	}
799*6940Ssam }
800*6940Ssam 
801*6940Ssam /* stubs for interrupt routines for devices not yet supported */
802*6940Ssam 
803*6940Ssam dmfsrint() { printf("dmfsrint\n"); }
804*6940Ssam 
805*6940Ssam dmfsxint() { printf("dmfsxint\n"); }
806*6940Ssam 
807*6940Ssam dmfdaint() { printf("dmfdaint\n"); }
808*6940Ssam 
809*6940Ssam dmfdbint() { printf("dmfdbint\n"); }
810*6940Ssam 
811*6940Ssam dmflint() { printf("dmflint\n"); }
812*6940Ssam #endif
813