xref: /csrg-svn/sys/vax/uba/dhu.c (revision 20976)
1*20976Smckusick /*	dhu.c	4.1	85/05/20	*/
2*20976Smckusick 
3*20976Smckusick /*
4*20976Smckusick  * based on	dh.c 6.3	84/03/15
5*20976Smckusick  * and on	dmf.c	6.2	84/02/16
6*20976Smckusick  *
7*20976Smckusick  * Dave Johnson, Brown University Computer Science
8*20976Smckusick  *	ddj%brown@csnet-relay
9*20976Smckusick  */
10*20976Smckusick 
11*20976Smckusick #include "dhu.h"
12*20976Smckusick #if NDHU > 0
13*20976Smckusick /*
14*20976Smckusick  * DHU-11 driver
15*20976Smckusick  */
16*20976Smckusick #include "../machine/pte.h"
17*20976Smckusick 
18*20976Smckusick #include "bk.h"
19*20976Smckusick #include "param.h"
20*20976Smckusick #include "conf.h"
21*20976Smckusick #include "dir.h"
22*20976Smckusick #include "user.h"
23*20976Smckusick #include "proc.h"
24*20976Smckusick #include "ioctl.h"
25*20976Smckusick #include "tty.h"
26*20976Smckusick #include "map.h"
27*20976Smckusick #include "buf.h"
28*20976Smckusick #include "vm.h"
29*20976Smckusick #include "kernel.h"
30*20976Smckusick #include "syslog.h"
31*20976Smckusick 
32*20976Smckusick #include "uba.h"
33*20976Smckusick #include "ubareg.h"
34*20976Smckusick #include "ubavar.h"
35*20976Smckusick #include "dhureg.h"
36*20976Smckusick 
37*20976Smckusick #include "bkmac.h"
38*20976Smckusick #include "clist.h"
39*20976Smckusick #include "file.h"
40*20976Smckusick #include "uio.h"
41*20976Smckusick 
42*20976Smckusick /*
43*20976Smckusick  * Definition of the driver for the auto-configuration program.
44*20976Smckusick  */
45*20976Smckusick int	dhuprobe(), dhuattach(), dhurint(), dhuxint();
46*20976Smckusick struct	uba_device *dhuinfo[NDHU];
47*20976Smckusick u_short dhustd[] = { 160440, 160500 };	/* some common addresses */
48*20976Smckusick struct	uba_driver dhudriver =
49*20976Smckusick 	{ dhuprobe, 0, dhuattach, 0, dhustd, "dhu", dhuinfo };
50*20976Smckusick 
51*20976Smckusick #define	NDHULINE 	(NDHU*16)
52*20976Smckusick 
53*20976Smckusick #define	UNIT(x)	(minor(x))
54*20976Smckusick 
55*20976Smckusick #ifndef PORTSELECTOR
56*20976Smckusick #define ISPEED	B300
57*20976Smckusick #define IFLAGS	(EVENP|ODDP|ECHO)
58*20976Smckusick #else
59*20976Smckusick #define ISPEED	B4800
60*20976Smckusick #define IFLAGS	(EVENP|ODDP)
61*20976Smckusick #endif
62*20976Smckusick 
63*20976Smckusick /*
64*20976Smckusick  * default receive silo timeout value -- valid values are 2..255
65*20976Smckusick  * number of ms. to delay between first char received and receive interrupt
66*20976Smckusick  *
67*20976Smckusick  * A value of 20 gives same response as ABLE dh/dm with silo alarm = 0
68*20976Smckusick  */
69*20976Smckusick #define	DHU_DEF_TIMO	20
70*20976Smckusick 
71*20976Smckusick /*
72*20976Smckusick  * Other values for silo timeout register defined here but not used:
73*20976Smckusick  * receive interrupt only on modem control or silo alarm (3/4 full)
74*20976Smckusick  */
75*20976Smckusick #define DHU_POLL_TIMO	0
76*20976Smckusick /*
77*20976Smckusick  * receive interrupt immediately on receive character
78*20976Smckusick  */
79*20976Smckusick #define DHU_NO_TIMO	1
80*20976Smckusick 
81*20976Smckusick /*
82*20976Smckusick  * Local variables for the driver
83*20976Smckusick  */
84*20976Smckusick /*
85*20976Smckusick  * Baud rates: no 50, 200, or 38400 baud; all other rates are from "Group B".
86*20976Smckusick  *	EXTA => 19200 baud
87*20976Smckusick  *	EXTB => 2000 baud
88*20976Smckusick  */
89*20976Smckusick char	dhu_speeds[] =
90*20976Smckusick 	{ 0, 0, 1, 2, 3, 4, 0, 5, 6, 7, 8, 10, 11, 13, 14, 9 };
91*20976Smckusick 
92*20976Smckusick short	dhusoftCAR[NDHU];
93*20976Smckusick 
94*20976Smckusick struct	tty dhu_tty[NDHULINE];
95*20976Smckusick int	ndhu = NDHULINE;
96*20976Smckusick int	dhuact;				/* mask of active dhu's */
97*20976Smckusick int	dhustart(), ttrstrt();
98*20976Smckusick 
99*20976Smckusick /*
100*20976Smckusick  * The clist space is mapped by the driver onto each UNIBUS.
101*20976Smckusick  * The UBACVT macro converts a clist space address for unibus uban
102*20976Smckusick  * into an i/o space address for the DMA routine.
103*20976Smckusick  */
104*20976Smckusick int	dhu_ubinfo[NUBA];	/* info about allocated unibus map */
105*20976Smckusick static int cbase[NUBA];		/* base address in unibus map */
106*20976Smckusick #define UBACVT(x, uban) 	(cbase[uban] + ((x)-(char *)cfree))
107*20976Smckusick 
108*20976Smckusick /*
109*20976Smckusick  * Routine for configuration to force a dhu to interrupt.
110*20976Smckusick  */
111*20976Smckusick /*ARGSUSED*/
112*20976Smckusick dhuprobe(reg)
113*20976Smckusick 	caddr_t reg;
114*20976Smckusick {
115*20976Smckusick 	register int br, cvec;		/* these are ``value-result'' */
116*20976Smckusick 	register struct dhudevice *dhuaddr = (struct dhudevice *)reg;
117*20976Smckusick 	int i;
118*20976Smckusick 
119*20976Smckusick #ifdef lint
120*20976Smckusick 	br = 0; cvec = br; br = cvec;
121*20976Smckusick 	if (ndhu == 0) ndhu = 1;
122*20976Smckusick 	dhurint(0); dhuxint(0);
123*20976Smckusick #endif
124*20976Smckusick 	/*
125*20976Smckusick 	 * The basic idea here is:
126*20976Smckusick 	 *	do a self-test by setting the Master-Reset bit
127*20976Smckusick 	 *	if this fails, then return
128*20976Smckusick 	 *	if successful, there will be 8 diagnostic codes in RX FIFO
129*20976Smckusick 	 *	therefore ask for a  Received-Data-Available interrupt
130*20976Smckusick 	 *	wait for it...
131*20976Smckusick 	 *	reset the interrupt-enable bit and flush out the diag. codes
132*20976Smckusick 	 */
133*20976Smckusick 	dhuaddr->dhucsr = DHU_CS_MCLR;
134*20976Smckusick 	for (i = 0; i < 1000; i++) {
135*20976Smckusick 		DELAY(10000);
136*20976Smckusick 		if ((dhuaddr->dhucsr&DHU_CS_MCLR) == 0)
137*20976Smckusick 			break;
138*20976Smckusick 	}
139*20976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_MCLR)
140*20976Smckusick 		return(0);
141*20976Smckusick 	if (dhuaddr->dhucsr&DHU_CS_DFAIL)
142*20976Smckusick 		return(0);
143*20976Smckusick 	dhuaddr->dhucsr = DHU_CS_RIE;
144*20976Smckusick 	DELAY(1000);
145*20976Smckusick 	dhuaddr->dhucsr = 0;
146*20976Smckusick 	while (dhuaddr->dhurbuf < 0)
147*20976Smckusick 		/* void */;
148*20976Smckusick 	return (sizeof(struct dhudevice));
149*20976Smckusick }
150*20976Smckusick 
151*20976Smckusick /*
152*20976Smckusick  * Routine called to attach a dhu.
153*20976Smckusick  */
154*20976Smckusick dhuattach(ui)
155*20976Smckusick 	struct uba_device *ui;
156*20976Smckusick {
157*20976Smckusick 
158*20976Smckusick 	dhusoftCAR[ui->ui_unit] = ui->ui_flags;
159*20976Smckusick }
160*20976Smckusick 
161*20976Smckusick /*
162*20976Smckusick  * Open a DHU11 line, mapping the clist onto the uba if this
163*20976Smckusick  * is the first dhu on this uba.  Turn on this dhu if this is
164*20976Smckusick  * the first use of it.
165*20976Smckusick  */
166*20976Smckusick /*ARGSUSED*/
167*20976Smckusick dhuopen(dev, flag)
168*20976Smckusick 	dev_t dev;
169*20976Smckusick {
170*20976Smckusick 	register struct tty *tp;
171*20976Smckusick 	register int unit, dhu;
172*20976Smckusick 	register struct dhudevice *addr;
173*20976Smckusick 	register struct uba_device *ui;
174*20976Smckusick 	int s;
175*20976Smckusick 
176*20976Smckusick 	unit = UNIT(dev);
177*20976Smckusick 	dhu = unit >> 4;
178*20976Smckusick 	if (unit >= NDHULINE || (ui = dhuinfo[dhu])== 0 || ui->ui_alive == 0)
179*20976Smckusick 		return (ENXIO);
180*20976Smckusick 	tp = &dhu_tty[unit];
181*20976Smckusick 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
182*20976Smckusick 		return (EBUSY);
183*20976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
184*20976Smckusick 	tp->t_addr = (caddr_t)addr;
185*20976Smckusick 	tp->t_oproc = dhustart;
186*20976Smckusick 	/*
187*20976Smckusick 	 * While setting up state for this uba and this dhu,
188*20976Smckusick 	 * block uba resets which can clear the state.
189*20976Smckusick 	 */
190*20976Smckusick 	s = spl5();
191*20976Smckusick 	if (dhu_ubinfo[ui->ui_ubanum] == 0) {
192*20976Smckusick 		dhu_ubinfo[ui->ui_ubanum] =
193*20976Smckusick 		    uballoc(ui->ui_ubanum, (caddr_t)cfree,
194*20976Smckusick 			nclist*sizeof(struct cblock), 0);
195*20976Smckusick 		cbase[ui->ui_ubanum] = dhu_ubinfo[ui->ui_ubanum]&0x3ffff;
196*20976Smckusick 	}
197*20976Smckusick 	if ((dhuact&(1<<dhu)) == 0) {
198*20976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
199*20976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
200*20976Smckusick 		dhuact |= (1<<dhu);
201*20976Smckusick 		/* anything else to configure whole board */
202*20976Smckusick 	}
203*20976Smckusick 	(void) splx(s);
204*20976Smckusick 	/*
205*20976Smckusick 	 * If this is first open, initialize tty state to default.
206*20976Smckusick 	 */
207*20976Smckusick 	if ((tp->t_state&TS_ISOPEN) == 0) {
208*20976Smckusick 		ttychars(tp);
209*20976Smckusick #ifndef PORTSELECTOR
210*20976Smckusick 		if (tp->t_ispeed == 0) {
211*20976Smckusick #else
212*20976Smckusick 			tp->t_state |= TS_HUPCLS;
213*20976Smckusick #endif PORTSELECTOR
214*20976Smckusick 			tp->t_ispeed = ISPEED;
215*20976Smckusick 			tp->t_ospeed = ISPEED;
216*20976Smckusick 			tp->t_flags = IFLAGS;
217*20976Smckusick #ifndef PORTSELECTOR
218*20976Smckusick 		}
219*20976Smckusick #endif PORTSELECTOR
220*20976Smckusick 		tp->t_dev = dev;
221*20976Smckusick 		dhuparam(unit);
222*20976Smckusick 	}
223*20976Smckusick 	/*
224*20976Smckusick 	 * Wait for carrier, then process line discipline specific open.
225*20976Smckusick 	 */
226*20976Smckusick 	s = spl5();
227*20976Smckusick 	if ((dhumctl(dev, DHU_ON, DMSET) & DHU_CAR) ||
228*20976Smckusick 	    (dhusoftCAR[dhu] & (1<<(unit&0xf))))
229*20976Smckusick 		tp->t_state |= TS_CARR_ON;
230*20976Smckusick 	while ((tp->t_state & TS_CARR_ON) == 0) {
231*20976Smckusick 		tp->t_state |= TS_WOPEN;
232*20976Smckusick 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
233*20976Smckusick 	}
234*20976Smckusick 	(void) splx(s);
235*20976Smckusick 	return ((*linesw[tp->t_line].l_open)(dev, tp));
236*20976Smckusick }
237*20976Smckusick 
238*20976Smckusick /*
239*20976Smckusick  * Close a DHU11 line, turning off the modem control.
240*20976Smckusick  */
241*20976Smckusick /*ARGSUSED*/
242*20976Smckusick dhuclose(dev, flag)
243*20976Smckusick 	dev_t dev;
244*20976Smckusick 	int flag;
245*20976Smckusick {
246*20976Smckusick 	register struct tty *tp;
247*20976Smckusick 	register unit;
248*20976Smckusick 
249*20976Smckusick 	unit = UNIT(dev);
250*20976Smckusick 	tp = &dhu_tty[unit];
251*20976Smckusick 	(*linesw[tp->t_line].l_close)(tp);
252*20976Smckusick 	(void) dhumctl(unit, DHU_BRK, DMBIC);
253*20976Smckusick 	if ((tp->t_state&(TS_HUPCLS|TS_WOPEN)) || (tp->t_state&TS_ISOPEN)==0)
254*20976Smckusick #ifdef PORTSELECTOR
255*20976Smckusick 	{
256*20976Smckusick 		extern int wakeup();
257*20976Smckusick 
258*20976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
259*20976Smckusick 		/* Hold DTR low for 0.5 seconds */
260*20976Smckusick 		timeout(wakeup, (caddr_t) &tp->t_dev, hz/2);
261*20976Smckusick 		sleep((caddr_t) &tp->t_dev, PZERO);
262*20976Smckusick 	}
263*20976Smckusick #else
264*20976Smckusick 		(void) dhumctl(unit, DHU_OFF, DMSET);
265*20976Smckusick #endif PORTSELECTOR
266*20976Smckusick 	ttyclose(tp);
267*20976Smckusick }
268*20976Smckusick 
269*20976Smckusick dhuread(dev, uio)
270*20976Smckusick 	dev_t dev;
271*20976Smckusick 	struct uio *uio;
272*20976Smckusick {
273*20976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
274*20976Smckusick 
275*20976Smckusick 	return ((*linesw[tp->t_line].l_read)(tp, uio));
276*20976Smckusick }
277*20976Smckusick 
278*20976Smckusick dhuwrite(dev, uio)
279*20976Smckusick 	dev_t dev;
280*20976Smckusick 	struct uio *uio;
281*20976Smckusick {
282*20976Smckusick 	register struct tty *tp = &dhu_tty[UNIT(dev)];
283*20976Smckusick 
284*20976Smckusick 	return ((*linesw[tp->t_line].l_write)(tp, uio));
285*20976Smckusick }
286*20976Smckusick 
287*20976Smckusick /*
288*20976Smckusick  * DHU11 receiver interrupt.
289*20976Smckusick  */
290*20976Smckusick dhurint(dhu)
291*20976Smckusick 	int dhu;
292*20976Smckusick {
293*20976Smckusick 	register struct tty *tp;
294*20976Smckusick 	register c;
295*20976Smckusick 	register struct dhudevice *addr;
296*20976Smckusick 	register struct tty *tp0;
297*20976Smckusick 	register struct uba_device *ui;
298*20976Smckusick 	register line;
299*20976Smckusick 	int overrun = 0;
300*20976Smckusick 
301*20976Smckusick 	ui = dhuinfo[dhu];
302*20976Smckusick 	if (ui == 0 || ui->ui_alive == 0)
303*20976Smckusick 		return;
304*20976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
305*20976Smckusick 	tp0 = &dhu_tty[dhu<<4];
306*20976Smckusick 	/*
307*20976Smckusick 	 * Loop fetching characters from the silo for this
308*20976Smckusick 	 * dhu until there are no more in the silo.
309*20976Smckusick 	 */
310*20976Smckusick 	while ((c = addr->dhurbuf) < 0) {	/* (c & DHU_RB_VALID) == on */
311*20976Smckusick 		line = DHU_RX_LINE(c);
312*20976Smckusick 		tp = tp0 + line;
313*20976Smckusick 		if ((c & DHU_RB_STAT) == DHU_RB_STAT) {
314*20976Smckusick 			/*
315*20976Smckusick 			 * modem changed or diag info
316*20976Smckusick 			 */
317*20976Smckusick 			if (c & DHU_RB_DIAG) {
318*20976Smckusick 				/* decode diagnostic messages */
319*20976Smckusick 				continue;
320*20976Smckusick 			}
321*20976Smckusick 			if ((tp->t_state & TS_WOPEN) == 0 &&
322*20976Smckusick 			    (tp->t_flags & MDMBUF)) {
323*20976Smckusick 				if (c & DHU_ST_DCD) {
324*20976Smckusick 					tp->t_state &= ~TS_TTSTOP;
325*20976Smckusick 					ttstart(tp);
326*20976Smckusick 				} else if ((tp->t_state & TS_TTSTOP) == 0) {
327*20976Smckusick 					tp->t_state |= TS_TTSTOP;
328*20976Smckusick 					dhustop(tp, 0);
329*20976Smckusick 				}
330*20976Smckusick 			} else if ((c & DHU_ST_DCD) == 0 &&
331*20976Smckusick 				   (dhusoftCAR[dhu] & (1<<line)) == 0) {
332*20976Smckusick 				if ((tp->t_state & TS_WOPEN) == 0 &&
333*20976Smckusick 				    (tp->t_flags & NOHANG) == 0) {
334*20976Smckusick 					gsignal(tp->t_pgrp, SIGHUP);
335*20976Smckusick 					gsignal(tp->t_pgrp, SIGCONT);
336*20976Smckusick 					(void) dhumctl((dhu<<4)|line,
337*20976Smckusick 								DHU_OFF, DMSET);
338*20976Smckusick 					ttyflush(tp, FREAD|FWRITE);
339*20976Smckusick 				}
340*20976Smckusick 				tp->t_state &= ~TS_CARR_ON;
341*20976Smckusick 			} else {
342*20976Smckusick 				if ((tp->t_state & TS_CARR_ON) == 0) {
343*20976Smckusick 					tp->t_state |= TS_CARR_ON;
344*20976Smckusick 					wakeup((caddr_t)&tp->t_rawq);
345*20976Smckusick 				}
346*20976Smckusick 			}
347*20976Smckusick 			continue;
348*20976Smckusick 		}
349*20976Smckusick 		if ((tp->t_state&TS_ISOPEN) == 0) {
350*20976Smckusick 			wakeup((caddr_t)&tp->t_rawq);
351*20976Smckusick #ifdef PORTSELECTOR
352*20976Smckusick 			if ((tp->t_state&TS_WOPEN) == 0)
353*20976Smckusick #endif
354*20976Smckusick 			continue;
355*20976Smckusick 		}
356*20976Smckusick 		if (c & DHU_RB_PE)
357*20976Smckusick 			if ((tp->t_flags&(EVENP|ODDP)) == EVENP ||
358*20976Smckusick 			    (tp->t_flags&(EVENP|ODDP)) == ODDP)
359*20976Smckusick 				continue;
360*20976Smckusick 		if ((c & DHU_RB_DO) && overrun == 0) {
361*20976Smckusick 			log(KERN_RECOV, "dhu%d: silo overflow\n", dhu);
362*20976Smckusick 			overrun = 1;
363*20976Smckusick 		}
364*20976Smckusick 		if (c & DHU_RB_FE)
365*20976Smckusick 			/*
366*20976Smckusick 			 * At framing error (break) generate
367*20976Smckusick 			 * a null (in raw mode, for getty), or a
368*20976Smckusick 			 * interrupt (in cooked/cbreak mode).
369*20976Smckusick 			 */
370*20976Smckusick 			if (tp->t_flags&RAW)
371*20976Smckusick 				c = 0;
372*20976Smckusick 			else
373*20976Smckusick 				c = tp->t_intrc;
374*20976Smckusick #if NBK > 0
375*20976Smckusick 		if (tp->t_line == NETLDISC) {
376*20976Smckusick 			c &= 0x7f;
377*20976Smckusick 			BKINPUT(c, tp);
378*20976Smckusick 		} else
379*20976Smckusick #endif
380*20976Smckusick 			(*linesw[tp->t_line].l_rint)(c, tp);
381*20976Smckusick 	}
382*20976Smckusick }
383*20976Smckusick 
384*20976Smckusick /*
385*20976Smckusick  * Ioctl for DHU11.
386*20976Smckusick  */
387*20976Smckusick /*ARGSUSED*/
388*20976Smckusick dhuioctl(dev, cmd, data, flag)
389*20976Smckusick 	caddr_t data;
390*20976Smckusick {
391*20976Smckusick 	register struct tty *tp;
392*20976Smckusick 	register int unit = UNIT(dev);
393*20976Smckusick 	register dhu = unit>>4;
394*20976Smckusick 	register bit = (1<<(unit&0xf));
395*20976Smckusick 	int error;
396*20976Smckusick 
397*20976Smckusick 	tp = &dhu_tty[unit];
398*20976Smckusick 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
399*20976Smckusick 	if (error >= 0)
400*20976Smckusick 		return (error);
401*20976Smckusick 	error = ttioctl(tp, cmd, data, flag);
402*20976Smckusick 	if (error >= 0) {
403*20976Smckusick 		if (cmd == TIOCSETP || cmd == TIOCSETN || cmd == TIOCLSET ||
404*20976Smckusick 		    cmd == TIOCLBIC || cmd == TIOCLBIS)
405*20976Smckusick 			dhuparam(unit);
406*20976Smckusick 		return (error);
407*20976Smckusick 	}
408*20976Smckusick 
409*20976Smckusick 	switch (cmd) {
410*20976Smckusick 	case TIOCSBRK:
411*20976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIS);
412*20976Smckusick 		break;
413*20976Smckusick 
414*20976Smckusick 	case TIOCCBRK:
415*20976Smckusick 		(void) dhumctl(unit, DHU_BRK, DMBIC);
416*20976Smckusick 		break;
417*20976Smckusick 
418*20976Smckusick 	case TIOCSDTR:
419*20976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIS);
420*20976Smckusick 		break;
421*20976Smckusick 
422*20976Smckusick 	case TIOCCDTR:
423*20976Smckusick 		(void) dhumctl(unit, DHU_DTR|DHU_RTS, DMBIC);
424*20976Smckusick 		break;
425*20976Smckusick 
426*20976Smckusick 	case TIOCMSET:
427*20976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMSET);
428*20976Smckusick 		break;
429*20976Smckusick 
430*20976Smckusick 	case TIOCMBIS:
431*20976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIS);
432*20976Smckusick 		break;
433*20976Smckusick 
434*20976Smckusick 	case TIOCMBIC:
435*20976Smckusick 		(void) dhumctl(dev, dmtodhu(*(int *)data), DMBIC);
436*20976Smckusick 		break;
437*20976Smckusick 
438*20976Smckusick 	case TIOCMGET:
439*20976Smckusick 		*(int *)data = dhutodm(dhumctl(dev, 0, DMGET));
440*20976Smckusick 		break;
441*20976Smckusick 	default:
442*20976Smckusick 		return (ENOTTY);
443*20976Smckusick 	}
444*20976Smckusick 	return (0);
445*20976Smckusick }
446*20976Smckusick 
447*20976Smckusick dmtodhu(bits)
448*20976Smckusick 	register int bits;
449*20976Smckusick {
450*20976Smckusick 	register int b = 0;
451*20976Smckusick 
452*20976Smckusick 	if (bits & DML_RTS) b |= DHU_RTS;
453*20976Smckusick 	if (bits & DML_DTR) b |= DHU_DTR;
454*20976Smckusick 	if (bits & DML_LE) b |= DHU_LE;
455*20976Smckusick 	return(b);
456*20976Smckusick }
457*20976Smckusick 
458*20976Smckusick dhutodm(bits)
459*20976Smckusick 	register int bits;
460*20976Smckusick {
461*20976Smckusick 	register int b = 0;
462*20976Smckusick 
463*20976Smckusick 	if (bits & DHU_DSR) b |= DML_DSR;
464*20976Smckusick 	if (bits & DHU_RNG) b |= DML_RNG;
465*20976Smckusick 	if (bits & DHU_CAR) b |= DML_CAR;
466*20976Smckusick 	if (bits & DHU_CTS) b |= DML_CTS;
467*20976Smckusick 	if (bits & DHU_RTS) b |= DML_RTS;
468*20976Smckusick 	if (bits & DHU_DTR) b |= DML_DTR;
469*20976Smckusick 	if (bits & DHU_LE) b |= DML_LE;
470*20976Smckusick 	return(b);
471*20976Smckusick }
472*20976Smckusick 
473*20976Smckusick 
474*20976Smckusick /*
475*20976Smckusick  * Set parameters from open or stty into the DHU hardware
476*20976Smckusick  * registers.
477*20976Smckusick  */
478*20976Smckusick dhuparam(unit)
479*20976Smckusick 	register int unit;
480*20976Smckusick {
481*20976Smckusick 	register struct tty *tp;
482*20976Smckusick 	register struct dhudevice *addr;
483*20976Smckusick 	register int lpar;
484*20976Smckusick 	int s;
485*20976Smckusick 
486*20976Smckusick 	tp = &dhu_tty[unit];
487*20976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
488*20976Smckusick 	/*
489*20976Smckusick 	 * Block interrupts so parameters will be set
490*20976Smckusick 	 * before the line interrupts.
491*20976Smckusick 	 */
492*20976Smckusick 	s = spl5();
493*20976Smckusick 	if ((tp->t_ispeed) == 0) {
494*20976Smckusick 		tp->t_state |= TS_HUPCLS;
495*20976Smckusick 		(void)dhumctl(unit, DHU_OFF, DMSET);
496*20976Smckusick 		splx(s);
497*20976Smckusick 		return;
498*20976Smckusick 	}
499*20976Smckusick 	lpar = (dhu_speeds[tp->t_ospeed]<<12) | (dhu_speeds[tp->t_ispeed]<<8);
500*20976Smckusick 	if ((tp->t_ispeed) == B134)
501*20976Smckusick 		lpar |= DHU_LP_BITS6|DHU_LP_PENABLE;
502*20976Smckusick 	else if (tp->t_flags & (RAW|LITOUT))
503*20976Smckusick 		lpar |= DHU_LP_BITS8;
504*20976Smckusick 	else
505*20976Smckusick 		lpar |= DHU_LP_BITS7|DHU_LP_PENABLE;
506*20976Smckusick 	if (tp->t_flags&EVENP)
507*20976Smckusick 		lpar |= DHU_LP_EPAR;
508*20976Smckusick 	if ((tp->t_ospeed) == B110)
509*20976Smckusick 		lpar |= DHU_LP_TWOSB;
510*20976Smckusick 	addr->dhucsr = DHU_SELECT(unit) | DHU_IE;
511*20976Smckusick 	addr->dhulpr = lpar;
512*20976Smckusick 	splx(s);
513*20976Smckusick }
514*20976Smckusick 
515*20976Smckusick /*
516*20976Smckusick  * DHU11 transmitter interrupt.
517*20976Smckusick  * Restart each line which used to be active but has
518*20976Smckusick  * terminated transmission since the last interrupt.
519*20976Smckusick  */
520*20976Smckusick dhuxint(dhu)
521*20976Smckusick 	int dhu;
522*20976Smckusick {
523*20976Smckusick 	register struct tty *tp;
524*20976Smckusick 	register struct dhudevice *addr;
525*20976Smckusick 	register struct tty *tp0;
526*20976Smckusick 	register struct uba_device *ui;
527*20976Smckusick 	register int line, t;
528*20976Smckusick 	u_short cntr;
529*20976Smckusick 
530*20976Smckusick 	ui = dhuinfo[dhu];
531*20976Smckusick 	tp0 = &dhu_tty[dhu<<4];
532*20976Smckusick 	addr = (struct dhudevice *)ui->ui_addr;
533*20976Smckusick 	while ((t = addr->dhucsrh) & DHU_CSH_TI) {
534*20976Smckusick 		line = DHU_TX_LINE(t);
535*20976Smckusick 		tp = tp0 + line;
536*20976Smckusick 		tp->t_state &= ~TS_BUSY;
537*20976Smckusick 		if (t & DHU_CSH_NXM) {
538*20976Smckusick 			printf("dhu(%d,%d): NXM fault\n", dhu, line);
539*20976Smckusick 			/* SHOULD RESTART OR SOMETHING... */
540*20976Smckusick 		}
541*20976Smckusick 		if (tp->t_state&TS_FLUSH)
542*20976Smckusick 			tp->t_state &= ~TS_FLUSH;
543*20976Smckusick 		else {
544*20976Smckusick 			addr->dhucsrl = DHU_SELECT(line) | DHU_IE;
545*20976Smckusick 			/*
546*20976Smckusick 			 * Do arithmetic in a short to make up
547*20976Smckusick 			 * for lost 16&17 bits.
548*20976Smckusick 			 */
549*20976Smckusick 			cntr = addr->dhubar1 -
550*20976Smckusick 			    UBACVT(tp->t_outq.c_cf, ui->ui_ubanum);
551*20976Smckusick 			ndflush(&tp->t_outq, (int)cntr);
552*20976Smckusick 		}
553*20976Smckusick 		if (tp->t_line)
554*20976Smckusick 			(*linesw[tp->t_line].l_start)(tp);
555*20976Smckusick 		else
556*20976Smckusick 			dhustart(tp);
557*20976Smckusick 	}
558*20976Smckusick }
559*20976Smckusick 
560*20976Smckusick /*
561*20976Smckusick  * Start (restart) transmission on the given DHU11 line.
562*20976Smckusick  */
563*20976Smckusick dhustart(tp)
564*20976Smckusick 	register struct tty *tp;
565*20976Smckusick {
566*20976Smckusick 	register struct dhudevice *addr;
567*20976Smckusick 	register int car, dhu, unit, nch;
568*20976Smckusick 	int s;
569*20976Smckusick 
570*20976Smckusick 	unit = minor(tp->t_dev);
571*20976Smckusick 	dhu = unit >> 4;
572*20976Smckusick 	unit &= 0xf;
573*20976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
574*20976Smckusick 
575*20976Smckusick 	/*
576*20976Smckusick 	 * Must hold interrupts in following code to prevent
577*20976Smckusick 	 * state of the tp from changing.
578*20976Smckusick 	 */
579*20976Smckusick 	s = spl5();
580*20976Smckusick 	/*
581*20976Smckusick 	 * If it's currently active, or delaying, no need to do anything.
582*20976Smckusick 	 */
583*20976Smckusick 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
584*20976Smckusick 		goto out;
585*20976Smckusick 	/*
586*20976Smckusick 	 * If there are sleepers, and output has drained below low
587*20976Smckusick 	 * water mark, wake up the sleepers..
588*20976Smckusick 	 */
589*20976Smckusick 	if (tp->t_outq.c_cc<=TTLOWAT(tp)) {
590*20976Smckusick 		if (tp->t_state&TS_ASLEEP) {
591*20976Smckusick 			tp->t_state &= ~TS_ASLEEP;
592*20976Smckusick 			wakeup((caddr_t)&tp->t_outq);
593*20976Smckusick 		}
594*20976Smckusick 		if (tp->t_wsel) {
595*20976Smckusick 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
596*20976Smckusick 			tp->t_wsel = 0;
597*20976Smckusick 			tp->t_state &= ~TS_WCOLL;
598*20976Smckusick 		}
599*20976Smckusick 	}
600*20976Smckusick 	/*
601*20976Smckusick 	 * Now restart transmission unless the output queue is
602*20976Smckusick 	 * empty.
603*20976Smckusick 	 */
604*20976Smckusick 	if (tp->t_outq.c_cc == 0)
605*20976Smckusick 		goto out;
606*20976Smckusick 	if (tp->t_flags & (RAW|LITOUT))
607*20976Smckusick 		nch = ndqb(&tp->t_outq, 0);
608*20976Smckusick 	else {
609*20976Smckusick 		nch = ndqb(&tp->t_outq, 0200);
610*20976Smckusick 		/*
611*20976Smckusick 		 * If first thing on queue is a delay process it.
612*20976Smckusick 		 */
613*20976Smckusick 		if (nch == 0) {
614*20976Smckusick 			nch = getc(&tp->t_outq);
615*20976Smckusick 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
616*20976Smckusick 			tp->t_state |= TS_TIMEOUT;
617*20976Smckusick 			goto out;
618*20976Smckusick 		}
619*20976Smckusick 	}
620*20976Smckusick 	/*
621*20976Smckusick 	 * If characters to transmit, restart transmission.
622*20976Smckusick 	 */
623*20976Smckusick 	if (nch) {
624*20976Smckusick 		car = UBACVT(tp->t_outq.c_cf, dhuinfo[dhu]->ui_ubanum);
625*20976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
626*20976Smckusick 		addr->dhulcr &= ~DHU_LC_TXABORT;
627*20976Smckusick 		addr->dhubcr = nch;
628*20976Smckusick 		addr->dhubar1 = car;
629*20976Smckusick 		addr->dhubar2 = ((car >> DHU_XBA_SHIFT) & DHU_BA2_XBA) |
630*20976Smckusick 					DHU_BA2_DMAGO;
631*20976Smckusick 		tp->t_state |= TS_BUSY;
632*20976Smckusick 	}
633*20976Smckusick out:
634*20976Smckusick 	splx(s);
635*20976Smckusick }
636*20976Smckusick 
637*20976Smckusick /*
638*20976Smckusick  * Stop output on a line, e.g. for ^S/^Q or output flush.
639*20976Smckusick  */
640*20976Smckusick /*ARGSUSED*/
641*20976Smckusick dhustop(tp, flag)
642*20976Smckusick 	register struct tty *tp;
643*20976Smckusick {
644*20976Smckusick 	register struct dhudevice *addr;
645*20976Smckusick 	register int unit, s;
646*20976Smckusick 
647*20976Smckusick 	addr = (struct dhudevice *)tp->t_addr;
648*20976Smckusick 	/*
649*20976Smckusick 	 * Block input/output interrupts while messing with state.
650*20976Smckusick 	 */
651*20976Smckusick 	s = spl5();
652*20976Smckusick 	if (tp->t_state & TS_BUSY) {
653*20976Smckusick 		/*
654*20976Smckusick 		 * Device is transmitting; stop output
655*20976Smckusick 		 * by selecting the line and setting the
656*20976Smckusick 		 * abort xmit bit.  We will get an xmit interrupt,
657*20976Smckusick 		 * where we will figure out where to continue the
658*20976Smckusick 		 * next time the transmitter is enabled.  If
659*20976Smckusick 		 * TS_FLUSH is set, the outq will be flushed.
660*20976Smckusick 		 * In either case, dhustart will clear the TXABORT bit.
661*20976Smckusick 		 */
662*20976Smckusick 		unit = minor(tp->t_dev);
663*20976Smckusick 		addr->dhucsrl = DHU_SELECT(unit) | DHU_IE;
664*20976Smckusick 		addr->dhulcr |= DHU_LC_TXABORT;
665*20976Smckusick 		if ((tp->t_state&TS_TTSTOP)==0)
666*20976Smckusick 			tp->t_state |= TS_FLUSH;
667*20976Smckusick 	}
668*20976Smckusick 	(void) splx(s);
669*20976Smckusick }
670*20976Smckusick 
671*20976Smckusick /*
672*20976Smckusick  * DHU11 modem control
673*20976Smckusick  */
674*20976Smckusick dhumctl(dev, bits, how)
675*20976Smckusick 	dev_t dev;
676*20976Smckusick 	int bits, how;
677*20976Smckusick {
678*20976Smckusick 	register struct dhudevice *dhuaddr;
679*20976Smckusick 	register int unit, mbits, lcr;
680*20976Smckusick 	int s;
681*20976Smckusick 
682*20976Smckusick 	unit = UNIT(dev);
683*20976Smckusick 	dhuaddr = (struct dhudevice *)(dhu_tty[unit].t_addr);
684*20976Smckusick 	unit &= 0xf;
685*20976Smckusick 	s = spl5();
686*20976Smckusick 	dhuaddr->dhucsr = DHU_SELECT(unit) | DHU_IE;
687*20976Smckusick 	/*
688*20976Smckusick 	 * combine byte from stat register (read only, bits 16..23)
689*20976Smckusick 	 * with lcr register (read write, bits 0..15).
690*20976Smckusick 	 */
691*20976Smckusick 	mbits = dhuaddr->dhulcr | (dhuaddr->dhustat << 16);
692*20976Smckusick 	switch (how) {
693*20976Smckusick 	case DMSET:
694*20976Smckusick 		mbits = (mbits & 0xff0000) | bits;
695*20976Smckusick 		break;
696*20976Smckusick 
697*20976Smckusick 	case DMBIS:
698*20976Smckusick 		mbits |= bits;
699*20976Smckusick 		break;
700*20976Smckusick 
701*20976Smckusick 	case DMBIC:
702*20976Smckusick 		mbits &= ~bits;
703*20976Smckusick 		break;
704*20976Smckusick 
705*20976Smckusick 	case DMGET:
706*20976Smckusick 		(void) splx(s);
707*20976Smckusick 		return(mbits);
708*20976Smckusick 	}
709*20976Smckusick 	dhuaddr->dhulcr = (mbits & 0xffff) | DHU_LC_RXEN;
710*20976Smckusick 	dhuaddr->dhulcr2 = DHU_LC2_TXEN;
711*20976Smckusick 	(void) splx(s);
712*20976Smckusick 	return(mbits);
713*20976Smckusick }
714*20976Smckusick 
715*20976Smckusick /*
716*20976Smckusick  * Reset state of driver if UBA reset was necessary.
717*20976Smckusick  * Reset the line and modem control registers.
718*20976Smckusick  * restart transmitters.
719*20976Smckusick  */
720*20976Smckusick dhureset(uban)
721*20976Smckusick 	int uban;
722*20976Smckusick {
723*20976Smckusick 	register int dhu, unit;
724*20976Smckusick 	register struct tty *tp;
725*20976Smckusick 	register struct uba_device *ui;
726*20976Smckusick 	register struct dhudevice *addr;
727*20976Smckusick 	int i;
728*20976Smckusick 	register int s;
729*20976Smckusick 
730*20976Smckusick 	if (dhu_ubinfo[uban] == 0)
731*20976Smckusick 		return;
732*20976Smckusick 	dhu_ubinfo[uban] = uballoc(uban, (caddr_t)cfree,
733*20976Smckusick 				    nclist*sizeof (struct cblock), 0);
734*20976Smckusick 	cbase[uban] = dhu_ubinfo[uban]&0x3ffff;
735*20976Smckusick 	for (dhu = 0; dhu < NDHU; dhu++) {
736*20976Smckusick 		ui = dhuinfo[dhu];
737*20976Smckusick 		if (ui == 0 || ui->ui_alive == 0 || ui->ui_ubanum != uban)
738*20976Smckusick 			continue;
739*20976Smckusick 		printf(" dhu%d", dhu);
740*20976Smckusick 		addr = (struct dhudevice *)ui->ui_addr;
741*20976Smckusick 		addr->dhucsr = DHU_SELECT(0) | DHU_IE;
742*20976Smckusick 		addr->dhutimo = DHU_DEF_TIMO;
743*20976Smckusick 		unit = dhu * 16;
744*20976Smckusick 		for (i = 0; i < 16; i++) {
745*20976Smckusick 			tp = &dhu_tty[unit];
746*20976Smckusick 			if (tp->t_state & (TS_ISOPEN|TS_WOPEN)) {
747*20976Smckusick 				dhuparam(unit);
748*20976Smckusick 				(void)dhumctl(unit, DHU_ON, DMSET);
749*20976Smckusick 				tp->t_state &= ~TS_BUSY;
750*20976Smckusick 				dhustart(tp);
751*20976Smckusick 			}
752*20976Smckusick 			unit++;
753*20976Smckusick 		}
754*20976Smckusick 	}
755*20976Smckusick }
756*20976Smckusick #endif
757