xref: /csrg-svn/sys/vax/uba/dh.c (revision 1569)
1*1569Sbill /*	dh.c	3.18	10/19/80	*/
213Sbill 
31561Sbill #include "../conf/dh.h"
41561Sbill #if NDH11 > 0
513Sbill /*
61561Sbill  * DH-11 driver
71561Sbill  *
81561Sbill  * Loaded with dhdm if there are DM-11's otherwise with dhfdm.
91561Sbill  *
101561Sbill  * NB: WE HAVEN'T TESTED dhdm CODE ON VAX.
1113Sbill  */
1213Sbill 
1313Sbill #include "../h/param.h"
1413Sbill #include "../h/conf.h"
1513Sbill #include "../h/dir.h"
1613Sbill #include "../h/user.h"
1713Sbill #include "../h/tty.h"
1813Sbill #include "../h/map.h"
1913Sbill #include "../h/pte.h"
2013Sbill #include "../h/uba.h"
21113Sbill #include "../h/bk.h"
221561Sbill #include "../h/clist.h"
2313Sbill 
24144Sbill /*
25144Sbill  * When running dz's using only SAE (silo alarm) on input
26144Sbill  * it is necessary to call dzrint() at clock interrupt time.
27144Sbill  * This is unsafe unless spl5()s in tty code are changed to
28144Sbill  * spl6()s to block clock interrupts.  Note that the dh driver
29144Sbill  * currently in use works the same way as the dz, even though
30144Sbill  * we could try to more intelligently manage its silo.
31144Sbill  * Thus don't take this out if you have no dz's unless you
32144Sbill  * change clock.c and dhtimer().
33144Sbill  */
34144Sbill #define	spl5	spl6
35144Sbill 
361561Sbill #define	UBACVT(x) (cbase + (short)((x)-(char *)cfree))
3713Sbill 
3813Sbill struct	tty dh11[NDH11];
39117Sbill int	dhact;
40280Sbill int	dhisilo;
4113Sbill int	ndh11	= NDH11;
4213Sbill int	dhstart();
4313Sbill int	ttrstrt();
44280Sbill int	dh_ubinfo;
45280Sbill int	cbase;
46280Sbill int	getcbase;
4713Sbill 
4813Sbill /*
4913Sbill  * Hardware control bits
5013Sbill  */
5113Sbill #define	BITS6	01
5213Sbill #define	BITS7	02
5313Sbill #define	BITS8	03
5413Sbill #define	TWOSB	04
5513Sbill #define	PENABLE	020
5613Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */
5713Sbill #define	OPAR	040
5813Sbill #define	HDUPLX	040000
5913Sbill 
6013Sbill #define	IENAB	030100
61105Sbill #define	NXM	02000
62105Sbill #define	CLRNXM	0400
6313Sbill #define	PERROR	010000
6413Sbill #define	FRERROR	020000
6513Sbill #define	OVERRUN	040000
6613Sbill #define	XINT	0100000
6713Sbill #define	SSPEED	7	/* standard speed: 300 baud */
6813Sbill 
6913Sbill /*
7013Sbill  * DM control bits
7113Sbill  */
7213Sbill #define	TURNON	03	/* CD lead + line enable */
7313Sbill #define	TURNOFF	01	/* line enable */
74168Sbill #define	DTR	02	/* data terminal ready */
7513Sbill #define	RQS	04	/* request to send */
7613Sbill 
7713Sbill /*
7813Sbill  * Software copy of last dhbar
7913Sbill  */
8013Sbill short	dhsar[(NDH11+15)/16];
8113Sbill 
8213Sbill struct device
8313Sbill {
8413Sbill 	union {
8513Sbill 		short	dhcsr;
8613Sbill 		char	dhcsrl;
8713Sbill 	} un;
8813Sbill 	short	dhnxch;
8913Sbill 	short	dhlpr;
9013Sbill 	unsigned short	dhcar;
9113Sbill 	short	dhbcr;
9213Sbill 	unsigned short	dhbar;
9313Sbill 	short	dhbreak;
9413Sbill 	short	dhsilo;
9513Sbill };
9613Sbill 
9713Sbill /*
9813Sbill  * Open a DH11 line.
9913Sbill  */
10013Sbill /*ARGSUSED*/
10113Sbill dhopen(dev, flag)
10213Sbill {
10313Sbill 	register struct tty *tp;
10413Sbill 	register d;
10513Sbill 	register struct device *addr;
10613Sbill 	int s;
10713Sbill 
10813Sbill 	d = minor(dev) & 0177;
10913Sbill 	if (d >= NDH11) {
11013Sbill 		u.u_error = ENXIO;
11113Sbill 		return;
11213Sbill 	}
11313Sbill 	tp = &dh11[d];
11413Sbill 	addr = DHADDR;
11513Sbill 	addr += d>>4;
11613Sbill 	tp->t_addr = (caddr_t)addr;
11713Sbill 	tp->t_oproc = dhstart;
11813Sbill 	tp->t_iproc = NULL;
11913Sbill 	tp->t_state |= WOPEN;
12013Sbill 	s = spl6();
121117Sbill 	if (!getcbase) {
122117Sbill 		getcbase++;
123717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
124717Sbill 		dh_ubinfo = uballoc((caddr_t)cfree, 512+NCLIST*sizeof(struct cblock), 0);
125280Sbill 		cbase = (short)dh_ubinfo;
12613Sbill 	}
12713Sbill 	splx(s);
12813Sbill 	addr->un.dhcsr |= IENAB;
129117Sbill 	dhact |= (1<<(d>>4));
13013Sbill 	if ((tp->t_state&ISOPEN) == 0) {
13113Sbill 		ttychars(tp);
132168Sbill 		if (tp->t_ispeed == 0) {
133168Sbill 			tp->t_ispeed = SSPEED;
134168Sbill 			tp->t_ospeed = SSPEED;
135168Sbill 			tp->t_flags = ODDP|EVENP|ECHO;
136168Sbill 		}
13713Sbill 		dhparam(d);
13813Sbill 	}
13913Sbill 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
14013Sbill 		u.u_error = EBUSY;
14113Sbill 		return;
14213Sbill 	}
14313Sbill 	dmopen(dev);
14413Sbill 	(*linesw[tp->t_line].l_open)(dev,tp);
14513Sbill }
14613Sbill 
14713Sbill /*
14813Sbill  * Close a DH11 line.
14913Sbill  */
15013Sbill /*ARGSUSED*/
15113Sbill dhclose(dev, flag)
15213Sbill dev_t dev;
15313Sbill int  flag;
15413Sbill {
15513Sbill 	register struct tty *tp;
15613Sbill 	register d;
15713Sbill 
15813Sbill 	d = minor(dev) & 0177;
15913Sbill 	tp = &dh11[d];
16013Sbill 	(*linesw[tp->t_line].l_close)(tp);
16113Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
162168Sbill 		dmctl(d, TURNOFF, DMSET);
16313Sbill 	ttyclose(tp);
16413Sbill }
16513Sbill 
16613Sbill /*
16713Sbill  * Read from a DH11 line.
16813Sbill  */
16913Sbill dhread(dev)
17013Sbill {
17113Sbill register struct tty *tp;
17213Sbill 
17313Sbill 	tp = &dh11[minor(dev) & 0177];
17413Sbill 	(*linesw[tp->t_line].l_read)(tp);
17513Sbill }
17613Sbill 
17713Sbill /*
17813Sbill  * write on a DH11 line
17913Sbill  */
18013Sbill dhwrite(dev)
18113Sbill {
18213Sbill register struct tty *tp;
18313Sbill 
18413Sbill 	tp = &dh11[minor(dev) & 0177];
18513Sbill 	(*linesw[tp->t_line].l_write)(tp);
18613Sbill }
18713Sbill 
18813Sbill /*
18913Sbill  * DH11 receiver interrupt.
19013Sbill  */
19113Sbill dhrint(dev)
19213Sbill {
19313Sbill 	register struct tty *tp;
19413Sbill 	register short c;
19513Sbill 	register struct device *addr;
196117Sbill 	register struct tty *tp0;
197139Sbill 	int s;
19813Sbill 
199139Sbill 	s = spl6();	/* see comment in clock.c */
20013Sbill 	addr = DHADDR;
20113Sbill 	addr += minor(dev) & 0177;
202117Sbill 	tp0 = &dh11[((minor(dev)&0177)<<4)];
20313Sbill 	while ((c = addr->dhnxch) < 0) {	/* char. present */
204117Sbill 		tp = tp0 + ((c>>8)&017);
20513Sbill 		if (tp >= &dh11[NDH11])
20613Sbill 			continue;
20713Sbill 		if((tp->t_state&ISOPEN)==0) {
20813Sbill 			wakeup((caddr_t)tp);
20913Sbill 			continue;
21013Sbill 		}
21113Sbill 		if (c&PERROR)
21213Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
21313Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
21413Sbill 				continue;
21513Sbill 		if (c&OVERRUN)
21613Sbill 			printf("O");
21713Sbill 		if (c&FRERROR)		/* break */
21813Sbill 			if (tp->t_flags&RAW)
21913Sbill 				c = 0;	/* null (for getty) */
22013Sbill 			else
221168Sbill #ifdef IIASA
222168Sbill 				continue;
223168Sbill #else
224184Sbill 				c = tun.t_intrc;
225168Sbill #endif
226139Sbill 		if (tp->t_line == NETLDISC) {
227117Sbill 			c &= 0177;
228168Sbill 			BKINPUT(c, tp);
229117Sbill 		} else
230117Sbill 			(*linesw[tp->t_line].l_rint)(c,tp);
23113Sbill 	}
232139Sbill 	splx(s);
23313Sbill }
23413Sbill 
23513Sbill /*
23613Sbill  * stty/gtty for DH11
23713Sbill  */
23813Sbill /*ARGSUSED*/
23913Sbill dhioctl(dev, cmd, addr, flag)
24013Sbill caddr_t addr;
24113Sbill {
24213Sbill 	register struct tty *tp;
24313Sbill 
24413Sbill 	tp = &dh11[minor(dev) & 0177];
245113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
246113Sbill 	if (cmd==0)
247113Sbill 		return;
248901Sbill 	if (ttioctl(cmd, tp, addr, dev, flag)) {
24913Sbill 		if (cmd==TIOCSETP||cmd==TIOCSETN)
25013Sbill 			dhparam(dev);
251168Sbill 	} else switch(cmd) {
252168Sbill 	case TIOCSBRK:
253168Sbill 		((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017);
254168Sbill 		break;
255168Sbill 	case TIOCCBRK:
256168Sbill 		((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
257168Sbill 		break;
258168Sbill 	case TIOCSDTR:
259168Sbill 		dmctl(minor(dev), DTR|RQS, DMBIS);
260168Sbill 		break;
261168Sbill 	case TIOCCDTR:
262168Sbill 		dmctl(minor(dev), DTR|RQS, DMBIC);
263168Sbill 		break;
264168Sbill 	default:
26513Sbill 		u.u_error = ENOTTY;
266168Sbill 	}
26713Sbill }
26813Sbill 
26913Sbill /*
27013Sbill  * Set parameters from open or stty into the DH hardware
27113Sbill  * registers.
27213Sbill  */
27313Sbill dhparam(dev)
27413Sbill {
27513Sbill 	register struct tty *tp;
27613Sbill 	register struct device *addr;
27713Sbill 	register d;
278300Sbill 	int s;
27913Sbill 
28013Sbill 	d = minor(dev) & 0177;
28113Sbill 	tp = &dh11[d];
28213Sbill 	addr = (struct device *)tp->t_addr;
283300Sbill 	s = spl5();
28413Sbill 	addr->un.dhcsrl = (d&017) | IENAB;
28513Sbill 	/*
28613Sbill 	 * Hang up line?
28713Sbill 	 */
28813Sbill 	if ((tp->t_ispeed)==0) {
28913Sbill 		tp->t_state |= HUPCLS;
290168Sbill 		dmctl(d, TURNOFF, DMSET);
29113Sbill 		return;
29213Sbill 	}
29313Sbill 	d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
29413Sbill 	if ((tp->t_ispeed) == 4)		/* 134.5 baud */
29513Sbill 		d |= BITS6|PENABLE|HDUPLX;
29613Sbill 	else if (tp->t_flags&RAW)
29713Sbill 		d |= BITS8;
29813Sbill 	else
29913Sbill 		d |= BITS7|PENABLE;
30013Sbill 	if ((tp->t_flags&EVENP) == 0)
30113Sbill 		d |= OPAR;
30213Sbill 	if ((tp->t_ospeed) == 3)	/* 110 baud */
30313Sbill 		d |= TWOSB;
30413Sbill 	addr->dhlpr = d;
305300Sbill 	splx(s);
30613Sbill }
30713Sbill 
30813Sbill /*
30913Sbill  * DH11 transmitter interrupt.
31013Sbill  * Restart each line which used to be active but has
31113Sbill  * terminated transmission since the last interrupt.
31213Sbill  */
31313Sbill dhxint(dev)
31413Sbill {
31513Sbill 	register struct tty *tp;
31613Sbill 	register struct device *addr;
31713Sbill 	register d;
31813Sbill 	short ttybit, bar, *sbar;
319144Sbill 	int s;
32013Sbill 
321144Sbill 	s = spl6();	/* block the clock */
32213Sbill 	d = minor(dev) & 0177;
32313Sbill 	addr = DHADDR + d;
32413Sbill 	addr->un.dhcsr &= (short)~XINT;
325105Sbill 	if (addr->un.dhcsr & NXM) {
326105Sbill 		addr->un.dhcsr |= CLRNXM;
327105Sbill 		printf("dh clr NXM\n");
328105Sbill 	}
32913Sbill 	sbar = &dhsar[d];
33013Sbill 	bar = *sbar & ~addr->dhbar;
33113Sbill 	d <<= 4; ttybit = 1;
33213Sbill 
33313Sbill 	for(; bar; d++, ttybit <<= 1) {
33413Sbill 		if(bar&ttybit) {
33513Sbill 			*sbar &= ~ttybit;
33613Sbill 			bar &= ~ttybit;
33713Sbill 			tp = &dh11[d];
338113Sbill 			tp->t_state &= ~BUSY;
339113Sbill 			if (tp->t_state&FLUSH)
340113Sbill 				tp->t_state &= ~FLUSH;
341113Sbill 			else {
342113Sbill 				addr->un.dhcsrl = (d&017)|IENAB;
343219Sbill 				ndflush(&tp->t_outq,
344*1569Sbill 				    (int)(short)addr->dhcar-UBACVT(tp->t_outq.c_cf));
345113Sbill 			}
346113Sbill 			if (tp->t_line)
34713Sbill 				(*linesw[tp->t_line].l_start)(tp);
348113Sbill 			else
34913Sbill 				dhstart(tp);
35013Sbill 		}
35113Sbill 	}
352144Sbill 	splx(s);
35313Sbill }
35413Sbill 
35513Sbill /*
35613Sbill  * Start (restart) transmission on the given DH11 line.
35713Sbill  */
35813Sbill dhstart(tp)
35913Sbill register struct tty *tp;
36013Sbill {
36113Sbill 	register struct device *addr;
36213Sbill 	register short nch;
36313Sbill 	int s, d;
36413Sbill 
36513Sbill 	/*
36613Sbill 	 * If it's currently active, or delaying,
36713Sbill 	 * no need to do anything.
36813Sbill 	 */
36913Sbill 	s = spl5();
37013Sbill 	d = tp-dh11;
37113Sbill 	addr = (struct device *)tp->t_addr;
37213Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
37313Sbill 		goto out;
37413Sbill 
37513Sbill 	/*
37613Sbill 	 * If the writer was sleeping on output overflow,
37713Sbill 	 * wake him when low tide is reached.
37813Sbill 	 */
379921Sbill 	if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) {
38013Sbill 		tp->t_state &= ~ASLEEP;
38113Sbill 		if (tp->t_chan)
382168Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
383168Sbill 		else
38413Sbill 			wakeup((caddr_t)&tp->t_outq);
38513Sbill 	}
38613Sbill 
38713Sbill 	if (tp->t_outq.c_cc == 0)
38813Sbill 		goto out;
38913Sbill 
39013Sbill 	/*
39113Sbill 	 * Find number of characters to transfer.
39213Sbill 	 */
39313Sbill 	if (tp->t_flags & RAW) {
39413Sbill 		nch = ndqb(&tp->t_outq, 0);
39513Sbill 	} else {
39613Sbill 		nch = ndqb(&tp->t_outq, 0200);
39713Sbill 		if (nch == 0) {
39813Sbill 			nch = getc(&tp->t_outq);
39913Sbill 			timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
40013Sbill 			tp->t_state |= TIMEOUT;
40113Sbill 			goto out;
40213Sbill 		}
40313Sbill 	}
40413Sbill 	/*
40513Sbill 	 * If any characters were set up, start transmission;
40613Sbill 	 */
40713Sbill 	if (nch) {
40813Sbill 		addr->un.dhcsrl = (d&017)|IENAB;
40913Sbill 		addr->dhcar = UBACVT(tp->t_outq.c_cf);
41013Sbill 		addr->dhbcr = -nch;
41113Sbill 		nch = 1<<(d&017);
41213Sbill 		addr->dhbar |= nch;
41313Sbill 		dhsar[d>>4] |= nch;
41413Sbill 		tp->t_state |= BUSY;
41513Sbill 	}
41613Sbill     out:
41713Sbill 	splx(s);
41813Sbill }
41913Sbill 
42013Sbill /*
42113Sbill  * Stop output on a line.
42213Sbill  * Assume call is made at spl6.
42313Sbill  */
42413Sbill /*ARGSUSED*/
42513Sbill dhstop(tp, flag)
42613Sbill register struct tty *tp;
42713Sbill {
428113Sbill 	register struct device *addr;
429113Sbill 	register d, s;
43013Sbill 
431113Sbill 	addr = (struct device *)tp->t_addr;
43213Sbill 	s = spl6();
433113Sbill 	if (tp->t_state & BUSY) {
434113Sbill 		d = minor(tp->t_dev);
435113Sbill 		addr->un.dhcsrl = (d&017) | IENAB;
43613Sbill 		if ((tp->t_state&TTSTOP)==0)
43713Sbill 			tp->t_state |= FLUSH;
438113Sbill 		addr->dhbcr = -1;
439113Sbill 	}
44013Sbill 	splx(s);
44113Sbill }
44213Sbill 
443117Sbill int	dhsilo = 16;
444168Sbill /*
445168Sbill  * Silo control is fixed strategy
446168Sbill  * here, paralleling only option available
447168Sbill  * on DZ-11.
448168Sbill  */
44913Sbill /*ARGSUSED*/
450168Sbill dhtimer()
45113Sbill {
452168Sbill 	register d;
453117Sbill 	register struct device *addr;
454117Sbill 
45513Sbill 	addr = DHADDR; d = 0;
45613Sbill 	do {
457117Sbill 		if (dhact & (1<<d)) {
458280Sbill 			if ((dhisilo & (1<<d)) == 0) {
459280Sbill 				addr->dhsilo = dhsilo;
460280Sbill 				dhisilo |= 1<<d;
461280Sbill 			}
462117Sbill 			dhrint(d);
463117Sbill 		}
464117Sbill 		d++;
46513Sbill 		addr++;
46613Sbill 	} while (d < (NDH11+15)/16);
46713Sbill }
468280Sbill 
469280Sbill /*
470280Sbill  * Reset state of driver if UBA reset was necessary.
471280Sbill  * Reset the csrl and lpr registers on open lines, and
472280Sbill  * restart transmitters.
473280Sbill  */
474280Sbill dhreset()
475280Sbill {
476280Sbill 	int d;
477280Sbill 	register struct tty *tp;
478280Sbill 	register struct device *addr;
479280Sbill 
480280Sbill 	if (getcbase == 0)
481280Sbill 		return;
482280Sbill 	printf(" dh");
483280Sbill 	dhisilo = 0;
484280Sbill 	ubafree(dh_ubinfo);
485280Sbill 	dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0);
486280Sbill 	cbase = (short)dh_ubinfo;
487280Sbill 	d = 0;
488280Sbill 	do {
489280Sbill 		addr = DHADDR + d;
490280Sbill 		if (dhact & (1<<d))
491300Sbill 			addr->un.dhcsr |= IENAB;
492280Sbill 		d++;
493280Sbill 	} while (d < (NDH11+15)/16);
494300Sbill 	for (d = 0; d < NDH11; d++) {
495300Sbill 		tp = &dh11[d];
496300Sbill 		if (tp->t_state & (ISOPEN|WOPEN)) {
497300Sbill 			dhparam(d);
498300Sbill 			dmctl(d, TURNON, DMSET);
499300Sbill 			tp->t_state &= ~BUSY;
500300Sbill 			dhstart(tp);
501300Sbill 		}
502300Sbill 	}
503300Sbill 	dhtimer();
504280Sbill }
505