xref: /csrg-svn/sys/vax/uba/dz.c (revision 2395)
1*2395Swnj /*	dz.c	4.10	02/10/81	*/
217Sbill 
31935Swnj #include "dz.h"
41562Sbill #if NDZ11 > 0
517Sbill /*
617Sbill  *  DZ-11 Driver
717Sbill  */
817Sbill #include "../h/param.h"
917Sbill #include "../h/systm.h"
1017Sbill #include "../h/tty.h"
1117Sbill #include "../h/dir.h"
1217Sbill #include "../h/user.h"
1317Sbill #include "../h/map.h"
1417Sbill #include "../h/pte.h"
15*2395Swnj #include "../h/buf.h"
1617Sbill #include "../h/uba.h"
1717Sbill #include "../h/conf.h"
1817Sbill #include "../h/pdma.h"
19114Sbill #include "../h/bk.h"
20871Sbill #include "../h/file.h"
211786Sbill #include "../h/mx.h"
22145Sbill 
23145Sbill /*
24145Sbill  * When running dz's using only SAE (silo alarm) on input
25145Sbill  * it is necessary to call dzrint() at clock interrupt time.
26145Sbill  * This is unsafe unless spl5()s in tty code are changed to
27145Sbill  * spl6()s to block clock interrupts.  Note that the dh driver
28145Sbill  * currently in use works the same way as the dz, even though
29145Sbill  * we could try to more intelligently manage its silo.
30145Sbill  * Thus don't take this out if you have no dz's unless you
31145Sbill  * change clock.c and dhtimer().
32*2395Swnj  *
33*2395Swnj  * SHOULD RATHER QUEUE SOFTWARE INTERRUPT AT CLOCK TIME.
34145Sbill  */
35145Sbill #define	spl5	spl6
3617Sbill 
37*2395Swnj int	dzcntrlr(), dzslave(), dzrint();
38*2395Swnj struct	uba_dinfo *dzinfo[NDZ11];
39*2395Swnj u_short	dzstd[] = { 0 };
40*2395Swnj int	(*dzivec[])() = { dzrint, 0 }; /* omit dzxint so we can do it here */
41*2395Swnj struct	uba_driver dzdriver =
42*2395Swnj 	{ dzcntrlr, dzslave, (int (*)())0, 0, 0, dzstd, dzinfo, dzivec };
43*2395Swnj 
44882Sbill #define NDZ 	(NDZ11*8)
4517Sbill 
4617Sbill #define BITS7	020
4717Sbill #define BITS8	030
4817Sbill #define TWOSB	040
4917Sbill #define PENABLE	0100
5017Sbill #define OPAR	0200
5117Sbill #define MSE	040		/* Master Scan Enable */
5217Sbill #define RIE	0100		/* Receiver Interrupt Enable */
53119Sbill #define	SAE	010000		/* Silo Alarm Enable */
54119Sbill #define TIE	040000		/* Transmit Interrupt Enable */
55119Sbill #define DZ_IEN	(MSE+RIE+TIE+SAE)
5617Sbill #define PERROR	010000
5717Sbill #define FRERROR	020000
58119Sbill #define	OVERRUN	040000
5917Sbill #define SSPEED	7		/* std speed = 300 baud */
6017Sbill 
6117Sbill #define	dzlpr	dzrbuf
6217Sbill #define dzmsr	dzbrk
6317Sbill #define ON	1
6417Sbill #define OFF	0
6517Sbill 
6617Sbill int	dzstart();
6717Sbill int	dzxint();
68*2395Swnj int	dzdma();
69114Sbill int	ttrstrt();
7017Sbill struct	tty dz_tty[NDZ];
7117Sbill int	dz_cnt = { NDZ };
72119Sbill int	dzact;
7317Sbill 
7417Sbill struct device {
7517Sbill 	short	dzcsr;
7617Sbill 	short	dzrbuf;
7717Sbill 	char	dztcr;
7817Sbill 	char	dzdtr;
7917Sbill 	char	dztbuf;
8017Sbill 	char	dzbrk;
8117Sbill };
8217Sbill 
83*2395Swnj struct	pdma dzpdma[NDZ];
8417Sbill char	dz_timer;
85*2395Swnj char	dz_speeds[] =
86*2395Swnj 	{ 0,020,021,022,023,024,0,025,026,027,030,032,034,036,0,0 };
87*2395Swnj char	dz_brk[NDZ11];
8817Sbill 
89*2395Swnj dzcntrlr(ui, reg)
90*2395Swnj 	struct uba_dinfo *ui;
91*2395Swnj 	caddr_t reg;
92*2395Swnj {
93*2395Swnj 
94*2395Swnj 	((struct device *)reg)->dzcsr |= IENABLE;
95*2395Swnj 	/* get it to interrupt */
96*2395Swnj }
97*2395Swnj 
98*2395Swnj dzslave(ui, reg, slaveno, uban)
99*2395Swnj 	register struct uba_dinfo *ui;
100*2395Swnj 	caddr_t reg;
101*2395Swnj {
102*2395Swnj 	register struct pdma *pdp = &dzpdma[ui->ui_unit*8];
103*2395Swnj 	register struct tty *tp = &dz_tty[ui->ui_unit*8];
104*2395Swnj 	register int cnt;
105*2395Swnj 	register int *urk = (int *)(&reg - 24);	/* white magic */
106*2395Swnj 	caddr_t cp;
107*2395Swnj 	int urk2;
108*2395Swnj 
109*2395Swnj 	for (cnt = 0; cnt < 8; cnt++) {
110*2395Swnj 		pdp->p_addr = (struct device *)reg;
111*2395Swnj 		pdp->p_arg = (int)tp;
112*2395Swnj 		pdp->p_fcn = dzxint;
113*2395Swnj 		pdp++, tp++;
114*2395Swnj 	}
115*2395Swnj 	if ((cp = calloc(12)) == 0)
116*2395Swnj 		panic("dz iv nm\n");
117*2395Swnj 	uba_hd[uban].uh_vec[*urk] = (int (*)())cp;	/* more white magic */
118*2395Swnj 	*cp++ = 0xbb; *cp++ = 0xff; *cp++ = 0xd0;	/* black magic */
119*2395Swnj 	*cp++ = ui->ui_unit&0x3f; *cp++ = 0x50;
120*2395Swnj 	*cp++ = 0x17; *cp++ = 0x9f;
121*2395Swnj 	urk2 = (int)dzdma;
122*2395Swnj 	for (cnt = 0; cnt < 4; cnt++)
123*2395Swnj 		*cp++ = urk2, urk2 >>= 4;		/* the spell ends */
124*2395Swnj 	return (1);
125*2395Swnj }
126*2395Swnj 
12717Sbill /*ARGSUSED*/
128*2395Swnj dzopen(dev, flag)
129*2395Swnj 	dev_t dev;
13017Sbill {
13117Sbill 	register struct tty *tp;
132*2395Swnj 	register int unit;
13317Sbill 	extern dzscan();
13417Sbill 
135*2395Swnj 	unit = minor(dev);
136*2395Swnj 	if (unit >= dz_cnt || dzpdma[unit].p_addr == 0) {
13717Sbill 		u.u_error = ENXIO;
13817Sbill 		return;
13917Sbill 	}
14017Sbill 	if (dz_timer == 0) {
14117Sbill 		dz_timer++;
14217Sbill 		timeout(dzscan, (caddr_t)0, 60);
14317Sbill 	}
144*2395Swnj 	tp = &dz_tty[unit];
145*2395Swnj 	tp->t_addr = (caddr_t)&dzpdma[unit];
14617Sbill 	tp->t_oproc = dzstart;
14717Sbill 	tp->t_iproc = NULL;
14817Sbill 	tp->t_state |= WOPEN;
14917Sbill 	if ((tp->t_state & ISOPEN) == 0) {
15017Sbill 		ttychars(tp);
15117Sbill 		tp->t_ospeed = tp->t_ispeed = SSPEED;
15217Sbill 		tp->t_flags = ODDP|EVENP|ECHO;
15317Sbill 		/*tp->t_state |= HUPCLS;*/
154*2395Swnj 		dzparam(unit);
15517Sbill 	} else if (tp->t_state&XCLUDE && u.u_uid != 0) {
15617Sbill 		u.u_error = EBUSY;
15717Sbill 		return;
15817Sbill 	}
159*2395Swnj 	dzmodem(unit, ON);
160114Sbill 	(void) spl5();
16117Sbill 	while ((tp->t_state & CARR_ON) == 0) {
16217Sbill 		tp->t_state |= WOPEN;
16317Sbill 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
16417Sbill 	}
165114Sbill 	(void) spl0();
166*2395Swnj 	(*linesw[tp->t_line].l_open)(dev, tp);
16717Sbill }
16817Sbill 
169*2395Swnj /*ARGSUSED*/
170*2395Swnj dzclose(dev, flag)
171*2395Swnj 	dev_t dev;
17217Sbill {
17317Sbill 	register struct tty *tp;
174*2395Swnj 	register int unit;
175*2395Swnj 	int dz;
17617Sbill 
177*2395Swnj 	unit = minor(dev);
178*2395Swnj 	dz = unit >> 3;
179*2395Swnj 	tp = &dz_tty[unit];
18017Sbill 	(*linesw[tp->t_line].l_close)(tp);
1812197Stoy 	((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
182*2395Swnj 	    (dz_brk[dz] &= ~(1 << (unit&07)));
18317Sbill 	if (tp->t_state & HUPCLS)
184*2395Swnj 		dzmodem(unit, OFF);
18517Sbill 	ttyclose(tp);
18617Sbill }
18717Sbill 
188*2395Swnj dzread(dev)
189*2395Swnj 	dev_t dev;
19017Sbill {
19117Sbill 	register struct tty *tp;
19217Sbill 
193*2395Swnj 	tp = &dz_tty[minor(dev)];
19417Sbill 	(*linesw[tp->t_line].l_read)(tp);
19517Sbill }
19617Sbill 
197*2395Swnj dzwrite(dev)
198*2395Swnj 	dev_t dev;
19917Sbill {
20017Sbill 	register struct tty *tp;
20117Sbill 
202*2395Swnj 	tp = &dz_tty[minor(dev)];
20317Sbill 	(*linesw[tp->t_line].l_write)(tp);
20417Sbill }
20517Sbill 
206119Sbill /*ARGSUSED*/
207*2395Swnj dzrint(dz)
208*2395Swnj 	int dz;
20917Sbill {
21017Sbill 	register struct tty *tp;
21117Sbill 	register int c;
21217Sbill 	register struct device *dzaddr;
213119Sbill 	register struct tty *tp0;
214*2395Swnj 	register int unit;
215140Sbill 	int s;
21617Sbill 
217140Sbill 	s = spl6();	/* see comment in clock.c */
218119Sbill 	/* as long as we are here, service them all */
219*2395Swnj 	for (unit = 0; unit < NDZ; unit += 8) {
220*2395Swnj 		if ((dzact & (1<<(unit>>3))) == 0)
22117Sbill 			continue;
222*2395Swnj 		dzaddr = dzpdma[unit].p_addr;
223*2395Swnj 		tp0 = &dz_tty[unit];
224119Sbill 		while ((c = dzaddr->dzrbuf) < 0) {	/* char present */
225119Sbill 			tp = tp0 + ((c>>8)&07);
226119Sbill 			if (tp >= &dz_tty[dz_cnt])
22717Sbill 				continue;
228119Sbill 			if ((tp->t_state & ISOPEN) == 0) {
229119Sbill 				wakeup((caddr_t)&tp->t_rawq);
230119Sbill 				continue;
231119Sbill 			}
232119Sbill 			if (c&FRERROR)
233119Sbill 				/* framing error = break */
234119Sbill 				if (tp->t_flags & RAW)
235119Sbill 					c = 0;		/* null for getty */
236119Sbill 				else
237170Sbill #ifdef IIASA
238170Sbill 					continue;
239170Sbill #else
240185Sbill 					c = tun.t_intrc;
241170Sbill #endif
242119Sbill 			if (c&OVERRUN)
243119Sbill 				printf("o");
244119Sbill 			if (c&PERROR)
245119Sbill 				/* parity error */
246119Sbill 				if (((tp->t_flags & (EVENP|ODDP)) == EVENP)
247119Sbill 				  || ((tp->t_flags & (EVENP|ODDP)) == ODDP))
248119Sbill 					continue;
249140Sbill 			if (tp->t_line == NETLDISC) {
250114Sbill 				c &= 0177;
251170Sbill 				BKINPUT(c, tp);
252114Sbill 			} else
253114Sbill 				(*linesw[tp->t_line].l_rint)(c, tp);
254119Sbill 		}
25517Sbill 	}
256140Sbill 	splx(s);
25717Sbill }
25817Sbill 
25917Sbill /*ARGSUSED*/
26017Sbill dzioctl(dev, cmd, addr, flag)
261*2395Swnj 	dev_t dev;
262*2395Swnj 	caddr_t addr;
26317Sbill {
26417Sbill 	register struct tty *tp;
265*2395Swnj 	register int unit = minor(dev);
266*2395Swnj 	register int dz = unit >> 3;
26717Sbill 
268*2395Swnj 	tp = &dz_tty[unit];
269114Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
270114Sbill 	if (cmd == 0)
271114Sbill 		return;
2721896Swnj 	if (ttioctl(tp, cmd, addr, flag)) {
27317Sbill 		if (cmd==TIOCSETP || cmd==TIOCSETN)
274*2395Swnj 			dzparam(unit);
275170Sbill 	} else switch(cmd) {
276*2395Swnj 
277170Sbill 	case TIOCSBRK:
278882Sbill 		((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
279*2395Swnj 			(dz_brk[dz] |= 1 << (unit&07));
280170Sbill 		break;
281170Sbill 	case TIOCCBRK:
282882Sbill 		((struct pdma *)(tp->t_addr))->p_addr->dzbrk =
283*2395Swnj 			(dz_brk[dz] &= ~(1 << (unit&07)));
284170Sbill 		break;
285170Sbill 	case TIOCSDTR:
286*2395Swnj 		dzmodem(unit, ON);
287170Sbill 		break;
288170Sbill 	case TIOCCDTR:
289*2395Swnj 		dzmodem(unit, OFF);
290170Sbill 		break;
291170Sbill 	default:
29217Sbill 		u.u_error = ENOTTY;
293170Sbill 	}
29417Sbill }
29517Sbill 
296*2395Swnj dzparam(unit)
297*2395Swnj 	register int unit;
29817Sbill {
29917Sbill 	register struct tty *tp;
30017Sbill 	register struct device *dzaddr;
301*2395Swnj 	register int lpr;
30217Sbill 
303*2395Swnj 	tp = &dz_tty[unit];
304*2395Swnj 	dzaddr = dzpdma[unit].p_addr;
30517Sbill 	dzaddr->dzcsr = DZ_IEN;
306*2395Swnj 	dzact |= (1<<(unit>>3));
30717Sbill 	if (tp->t_ispeed == 0) {
308*2395Swnj 		dzmodem(unit, OFF);		/* hang up line */
30917Sbill 		return;
31017Sbill 	}
311*2395Swnj 	lpr = (dz_speeds[tp->t_ispeed]<<8) | (unit & 07);
312882Sbill #ifndef IIASA
3132296Swnj 	if ((tp->t_local&LLITOUT) || (tp->t_flags&RAW))
31417Sbill 		lpr |= BITS8;
31517Sbill 	else
31617Sbill 		lpr |= (BITS7|PENABLE);
31717Sbill 	if ((tp->t_flags & EVENP) == 0)
31817Sbill 		lpr |= OPAR;
319882Sbill #else IIASA
320882Sbill 	if ((tp->t_flags & (EVENP|ODDP)) == (EVENP|ODDP))
321882Sbill 		lpr |= BITS8;
322882Sbill 	else if (tp->t_flags & EVENP)
323882Sbill 		lpr |= (BITS7|PENABLE);
324882Sbill 	else if (tp->t_flags & ODDP)
325882Sbill 		lpr |= (BITS7|OPAR|PENABLE);
326882Sbill 	else
327882Sbill 		lpr |= BITS7;
328882Sbill #endif IIASA
32917Sbill 	if (tp->t_ispeed == 3)
33017Sbill 		lpr |= TWOSB; 			/* 110 baud: 2 stop bits */
33117Sbill 	dzaddr->dzlpr = lpr;
33217Sbill }
33317Sbill 
33417Sbill dzxint(tp)
335*2395Swnj 	register struct tty *tp;
33617Sbill {
33717Sbill 	register struct pdma *dp;
338145Sbill 	register s;
339145Sbill 	s = spl6();	/* block the clock */
34017Sbill 
341*2395Swnj 	dp = (struct pdma *)tp->t_addr;
34217Sbill 	tp->t_state &= ~BUSY;
34317Sbill 	if (tp->t_state & FLUSH)
34417Sbill 		tp->t_state &= ~FLUSH;
34517Sbill 	else
346281Sbill 		ndflush(&tp->t_outq, dp->p_mem-tp->t_outq.c_cf);
34717Sbill 	if (tp->t_line)
34817Sbill 		(*linesw[tp->t_line].l_start)(tp);
34917Sbill 	else
35017Sbill 		dzstart(tp);
35117Sbill 	if (tp->t_outq.c_cc == 0 || (tp->t_state&BUSY)==0)
352*2395Swnj 		dp->p_addr->dztcr &= ~(1 << (minor(tp->t_dev)&07));
353145Sbill 	splx(s);
35417Sbill }
35517Sbill 
35617Sbill dzstart(tp)
357*2395Swnj 	register struct tty *tp;
35817Sbill {
35917Sbill 	register struct pdma *dp;
36017Sbill 	register struct device *dzaddr;
361*2395Swnj 	register int cc;
362*2395Swnj 	int s;
36317Sbill 
364*2395Swnj 	dp = (struct pdma *)tp->t_addr;
36517Sbill 	dzaddr = dp->p_addr;
366*2395Swnj 	s = spl5();
36717Sbill 	if (tp->t_state & (TIMEOUT|BUSY|TTSTOP))
36817Sbill 		goto out;
369921Sbill 	if (tp->t_state&ASLEEP && tp->t_outq.c_cc <= TTLOWAT(tp)) {
37017Sbill 		tp->t_state &= ~ASLEEP;
37117Sbill 		if (tp->t_chan)
37217Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
37317Sbill 		else
37417Sbill 			wakeup((caddr_t)&tp->t_outq);
37517Sbill 	}
37617Sbill 	if (tp->t_outq.c_cc == 0)
37717Sbill 		goto out;
37817Sbill 	if (tp->t_flags&RAW)
37917Sbill 		cc = ndqb(&tp->t_outq, 0);
38017Sbill 	else {
38117Sbill 		cc = ndqb(&tp->t_outq, 0200);
38217Sbill 		if (cc == 0) {
38317Sbill 			cc = getc(&tp->t_outq);
38417Sbill 			timeout(ttrstrt, (caddr_t)tp, (cc&0177) + 6);
38517Sbill 			tp->t_state |= TIMEOUT;
38617Sbill 			goto out;
38717Sbill 		}
38817Sbill 	}
38917Sbill 	tp->t_state |= BUSY;
39017Sbill 	dp->p_end = dp->p_mem = tp->t_outq.c_cf;
39117Sbill 	dp->p_end += cc;
392*2395Swnj 	dzaddr->dztcr |= 1 << (minor(tp->t_dev) & 07);
393*2395Swnj out:
394*2395Swnj 	splx(s);
39517Sbill }
39617Sbill 
39717Sbill /*
39817Sbill  * Stop output on a line.
39917Sbill  * Assume call is made at spl6.
40017Sbill  */
40117Sbill /*ARGSUSED*/
40217Sbill dzstop(tp, flag)
403*2395Swnj 	register struct tty *tp;
40417Sbill {
40517Sbill 	register struct pdma *dp;
40617Sbill 	register int s;
40717Sbill 
408*2395Swnj 	dp = (struct pdma *)tp->t_addr;
40917Sbill 	s = spl6();
41017Sbill 	if (tp->t_state & BUSY) {
41117Sbill 		dp->p_end = dp->p_mem;
412*2395Swnj 		if ((tp->t_state&TTSTOP)==0)
41317Sbill 			tp->t_state |= FLUSH;
41417Sbill 	}
41517Sbill 	splx(s);
41617Sbill }
41717Sbill 
418*2395Swnj dzmodem(unit, flag)
419*2395Swnj 	register int unit;
42017Sbill {
42117Sbill 	register struct device *dzaddr;
42217Sbill 	register char bit;
42317Sbill 
424*2395Swnj 	dzaddr = dzpdma[unit].p_addr;
425*2395Swnj 	bit = 1<<(unit&07);
42617Sbill 	if (flag == OFF)
42717Sbill 		dzaddr->dzdtr &= ~bit;
42817Sbill 	else
42917Sbill 		dzaddr->dzdtr |= bit;
43017Sbill }
43117Sbill 
43217Sbill dzscan()
43317Sbill {
43417Sbill 	register i;
43517Sbill 	register struct device *dzaddr;
43617Sbill 	register bit;
43717Sbill 	register struct tty *tp;
43817Sbill 
43917Sbill 	for (i = 0; i < dz_cnt ; i++) {
44017Sbill 		dzaddr = dzpdma[i].p_addr;
44117Sbill 		tp = &dz_tty[i];
44217Sbill 		bit = 1<<(i&07);
4432379Swnj 		if (dzaddr->dzmsr & bit || (i == 6 || i == 7)) {
44417Sbill 			/* carrier present */
44517Sbill 			if ((tp->t_state & CARR_ON) == 0) {
44617Sbill 				wakeup((caddr_t)&tp->t_rawq);
44717Sbill 				tp->t_state |= CARR_ON;
44817Sbill 			}
44917Sbill 		} else {
450*2395Swnj 			if ((tp->t_state&CARR_ON) && (tp->t_local&LNOHANG)==0) {
45117Sbill 				/* carrier lost */
452882Sbill 				if (tp->t_state&ISOPEN) {
453170Sbill 					gsignal(tp->t_pgrp, SIGHUP);
454205Sbill 					gsignal(tp->t_pgrp, SIGCONT);
455170Sbill 					dzaddr->dzdtr &= ~bit;
456871Sbill 					flushtty(tp, FREAD|FWRITE);
457170Sbill 				}
458170Sbill 				tp->t_state &= ~CARR_ON;
45917Sbill 			}
46017Sbill 		}
46117Sbill 	}
46217Sbill 	timeout(dzscan, (caddr_t)0, 2*HZ);
46317Sbill }
464119Sbill 
465119Sbill dztimer()
466119Sbill {
467119Sbill 
468119Sbill 	dzrint(0);
469119Sbill }
470281Sbill 
471281Sbill /*
472281Sbill  * Reset state of driver if UBA reset was necessary.
473301Sbill  * Reset parameters and restart transmission on open lines.
474281Sbill  */
475*2395Swnj dzreset(uban)
476281Sbill {
477*2395Swnj 	register int unit;
478281Sbill 	register struct tty *tp;
479281Sbill 
480*2395Swnj 	/*** WE SHOULD LOOK TO SEE IF WE CARE ABOUT UBA BEING RESET ***/
481*2395Swnj 
482281Sbill 	printf(" dz");
483*2395Swnj 	for (unit = 0; unit < NDZ; unit++) {
484*2395Swnj 		tp = &dz_tty[unit];
485281Sbill 		if (tp->t_state & (ISOPEN|WOPEN)) {
486*2395Swnj 			dzparam(unit);
487*2395Swnj 			dzmodem(unit, ON);
488301Sbill 			tp->t_state &= ~BUSY;
489301Sbill 			dzstart(tp);
490281Sbill 		}
491281Sbill 	}
492281Sbill 	dztimer();
493281Sbill }
4941562Sbill #endif
495