xref: /csrg-svn/sys/vax/uba/dh.c (revision 2196)
1*2196Stoy /*	dh.c	4.9	01/19/81	*/
213Sbill 
31934Swnj #include "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"
231786Sbill #include "../h/mx.h"
2413Sbill 
25144Sbill /*
26144Sbill  * When running dz's using only SAE (silo alarm) on input
27144Sbill  * it is necessary to call dzrint() at clock interrupt time.
28144Sbill  * This is unsafe unless spl5()s in tty code are changed to
29144Sbill  * spl6()s to block clock interrupts.  Note that the dh driver
30144Sbill  * currently in use works the same way as the dz, even though
31144Sbill  * we could try to more intelligently manage its silo.
32144Sbill  * Thus don't take this out if you have no dz's unless you
33144Sbill  * change clock.c and dhtimer().
34144Sbill  */
35144Sbill #define	spl5	spl6
36144Sbill 
371561Sbill #define	UBACVT(x) (cbase + (short)((x)-(char *)cfree))
3813Sbill 
3913Sbill struct	tty dh11[NDH11];
40117Sbill int	dhact;
41280Sbill int	dhisilo;
4213Sbill int	ndh11	= NDH11;
4313Sbill int	dhstart();
4413Sbill int	ttrstrt();
45280Sbill int	dh_ubinfo;
46280Sbill int	cbase;
47280Sbill int	getcbase;
4813Sbill 
4913Sbill /*
5013Sbill  * Hardware control bits
5113Sbill  */
5213Sbill #define	BITS6	01
5313Sbill #define	BITS7	02
5413Sbill #define	BITS8	03
5513Sbill #define	TWOSB	04
5613Sbill #define	PENABLE	020
5713Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */
5813Sbill #define	OPAR	040
5913Sbill #define	HDUPLX	040000
6013Sbill 
6113Sbill #define	IENAB	030100
62105Sbill #define	NXM	02000
63105Sbill #define	CLRNXM	0400
6413Sbill #define	PERROR	010000
6513Sbill #define	FRERROR	020000
6613Sbill #define	OVERRUN	040000
6713Sbill #define	XINT	0100000
6813Sbill #define	SSPEED	7	/* standard speed: 300 baud */
6913Sbill 
7013Sbill /*
7113Sbill  * DM control bits
7213Sbill  */
7313Sbill #define	TURNON	03	/* CD lead + line enable */
7413Sbill #define	TURNOFF	01	/* line enable */
75168Sbill #define	DTR	02	/* data terminal ready */
7613Sbill #define	RQS	04	/* request to send */
7713Sbill 
7813Sbill /*
7913Sbill  * Software copy of last dhbar
8013Sbill  */
8113Sbill short	dhsar[(NDH11+15)/16];
8213Sbill 
8313Sbill struct device
8413Sbill {
8513Sbill 	union {
8613Sbill 		short	dhcsr;
8713Sbill 		char	dhcsrl;
8813Sbill 	} un;
8913Sbill 	short	dhnxch;
9013Sbill 	short	dhlpr;
9113Sbill 	unsigned short	dhcar;
9213Sbill 	short	dhbcr;
9313Sbill 	unsigned short	dhbar;
9413Sbill 	short	dhbreak;
9513Sbill 	short	dhsilo;
9613Sbill };
9713Sbill 
9813Sbill /*
9913Sbill  * Open a DH11 line.
10013Sbill  */
10113Sbill /*ARGSUSED*/
10213Sbill dhopen(dev, flag)
10313Sbill {
10413Sbill 	register struct tty *tp;
10513Sbill 	register d;
10613Sbill 	register struct device *addr;
10713Sbill 	int s;
10813Sbill 
10913Sbill 	d = minor(dev) & 0177;
11013Sbill 	if (d >= NDH11) {
11113Sbill 		u.u_error = ENXIO;
11213Sbill 		return;
11313Sbill 	}
11413Sbill 	tp = &dh11[d];
11513Sbill 	addr = DHADDR;
11613Sbill 	addr += d>>4;
11713Sbill 	tp->t_addr = (caddr_t)addr;
11813Sbill 	tp->t_oproc = dhstart;
11913Sbill 	tp->t_iproc = NULL;
12013Sbill 	tp->t_state |= WOPEN;
12113Sbill 	s = spl6();
122117Sbill 	if (!getcbase) {
123117Sbill 		getcbase++;
124717Sbill 		/* 512+ is a kludge to try to get around a hardware problem */
125717Sbill 		dh_ubinfo = uballoc((caddr_t)cfree, 512+NCLIST*sizeof(struct cblock), 0);
126280Sbill 		cbase = (short)dh_ubinfo;
12713Sbill 	}
12813Sbill 	splx(s);
12913Sbill 	addr->un.dhcsr |= IENAB;
130117Sbill 	dhact |= (1<<(d>>4));
13113Sbill 	if ((tp->t_state&ISOPEN) == 0) {
13213Sbill 		ttychars(tp);
133168Sbill 		if (tp->t_ispeed == 0) {
134168Sbill 			tp->t_ispeed = SSPEED;
135168Sbill 			tp->t_ospeed = SSPEED;
136168Sbill 			tp->t_flags = ODDP|EVENP|ECHO;
137168Sbill 		}
13813Sbill 		dhparam(d);
13913Sbill 	}
14013Sbill 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
14113Sbill 		u.u_error = EBUSY;
14213Sbill 		return;
14313Sbill 	}
14413Sbill 	dmopen(dev);
14513Sbill 	(*linesw[tp->t_line].l_open)(dev,tp);
14613Sbill }
14713Sbill 
14813Sbill /*
14913Sbill  * Close a DH11 line.
15013Sbill  */
15113Sbill /*ARGSUSED*/
15213Sbill dhclose(dev, flag)
15313Sbill dev_t dev;
15413Sbill int  flag;
15513Sbill {
15613Sbill 	register struct tty *tp;
15713Sbill 	register d;
15813Sbill 
15913Sbill 	d = minor(dev) & 0177;
16013Sbill 	tp = &dh11[d];
16113Sbill 	(*linesw[tp->t_line].l_close)(tp);
162*2196Stoy 	/*
163*2196Stoy 	 * Turn of the break bit in case somebody did a TIOCSBRK without
164*2196Stoy 	 * a TIOCCBRK.
165*2196Stoy 	 */
166*2196Stoy 	((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
16713Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
168168Sbill 		dmctl(d, TURNOFF, DMSET);
16913Sbill 	ttyclose(tp);
17013Sbill }
17113Sbill 
17213Sbill /*
17313Sbill  * Read from a DH11 line.
17413Sbill  */
17513Sbill dhread(dev)
17613Sbill {
17713Sbill register struct tty *tp;
17813Sbill 
17913Sbill 	tp = &dh11[minor(dev) & 0177];
18013Sbill 	(*linesw[tp->t_line].l_read)(tp);
18113Sbill }
18213Sbill 
18313Sbill /*
18413Sbill  * write on a DH11 line
18513Sbill  */
18613Sbill dhwrite(dev)
18713Sbill {
18813Sbill register struct tty *tp;
18913Sbill 
19013Sbill 	tp = &dh11[minor(dev) & 0177];
19113Sbill 	(*linesw[tp->t_line].l_write)(tp);
19213Sbill }
19313Sbill 
19413Sbill /*
19513Sbill  * DH11 receiver interrupt.
19613Sbill  */
19713Sbill dhrint(dev)
19813Sbill {
19913Sbill 	register struct tty *tp;
20013Sbill 	register short c;
20113Sbill 	register struct device *addr;
202117Sbill 	register struct tty *tp0;
203139Sbill 	int s;
20413Sbill 
205139Sbill 	s = spl6();	/* see comment in clock.c */
20613Sbill 	addr = DHADDR;
20713Sbill 	addr += minor(dev) & 0177;
208117Sbill 	tp0 = &dh11[((minor(dev)&0177)<<4)];
20913Sbill 	while ((c = addr->dhnxch) < 0) {	/* char. present */
210117Sbill 		tp = tp0 + ((c>>8)&017);
21113Sbill 		if (tp >= &dh11[NDH11])
21213Sbill 			continue;
21313Sbill 		if((tp->t_state&ISOPEN)==0) {
21413Sbill 			wakeup((caddr_t)tp);
21513Sbill 			continue;
21613Sbill 		}
21713Sbill 		if (c&PERROR)
21813Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
21913Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
22013Sbill 				continue;
22113Sbill 		if (c&OVERRUN)
22213Sbill 			printf("O");
22313Sbill 		if (c&FRERROR)		/* break */
22413Sbill 			if (tp->t_flags&RAW)
22513Sbill 				c = 0;	/* null (for getty) */
22613Sbill 			else
227168Sbill #ifdef IIASA
228168Sbill 				continue;
229168Sbill #else
230184Sbill 				c = tun.t_intrc;
231168Sbill #endif
232139Sbill 		if (tp->t_line == NETLDISC) {
233117Sbill 			c &= 0177;
234168Sbill 			BKINPUT(c, tp);
235117Sbill 		} else
236117Sbill 			(*linesw[tp->t_line].l_rint)(c,tp);
23713Sbill 	}
238139Sbill 	splx(s);
23913Sbill }
24013Sbill 
24113Sbill /*
24213Sbill  * stty/gtty for DH11
24313Sbill  */
24413Sbill /*ARGSUSED*/
24513Sbill dhioctl(dev, cmd, addr, flag)
24613Sbill caddr_t addr;
24713Sbill {
24813Sbill 	register struct tty *tp;
24913Sbill 
25013Sbill 	tp = &dh11[minor(dev) & 0177];
251113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
252113Sbill 	if (cmd==0)
253113Sbill 		return;
2541895Swnj 	if (ttioctl(tp, cmd, addr, flag)) {
25513Sbill 		if (cmd==TIOCSETP||cmd==TIOCSETN)
25613Sbill 			dhparam(dev);
257168Sbill 	} else switch(cmd) {
258168Sbill 	case TIOCSBRK:
259168Sbill 		((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017);
260168Sbill 		break;
261168Sbill 	case TIOCCBRK:
262168Sbill 		((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
263168Sbill 		break;
264168Sbill 	case TIOCSDTR:
265168Sbill 		dmctl(minor(dev), DTR|RQS, DMBIS);
266168Sbill 		break;
267168Sbill 	case TIOCCDTR:
268168Sbill 		dmctl(minor(dev), DTR|RQS, DMBIC);
269168Sbill 		break;
270168Sbill 	default:
27113Sbill 		u.u_error = ENOTTY;
272168Sbill 	}
27313Sbill }
27413Sbill 
27513Sbill /*
27613Sbill  * Set parameters from open or stty into the DH hardware
27713Sbill  * registers.
27813Sbill  */
27913Sbill dhparam(dev)
28013Sbill {
28113Sbill 	register struct tty *tp;
28213Sbill 	register struct device *addr;
28313Sbill 	register d;
284300Sbill 	int s;
28513Sbill 
28613Sbill 	d = minor(dev) & 0177;
28713Sbill 	tp = &dh11[d];
28813Sbill 	addr = (struct device *)tp->t_addr;
289300Sbill 	s = spl5();
29013Sbill 	addr->un.dhcsrl = (d&017) | IENAB;
29113Sbill 	/*
29213Sbill 	 * Hang up line?
29313Sbill 	 */
29413Sbill 	if ((tp->t_ispeed)==0) {
29513Sbill 		tp->t_state |= HUPCLS;
296168Sbill 		dmctl(d, TURNOFF, DMSET);
29713Sbill 		return;
29813Sbill 	}
29913Sbill 	d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
30013Sbill 	if ((tp->t_ispeed) == 4)		/* 134.5 baud */
30113Sbill 		d |= BITS6|PENABLE|HDUPLX;
30213Sbill 	else if (tp->t_flags&RAW)
30313Sbill 		d |= BITS8;
30413Sbill 	else
30513Sbill 		d |= BITS7|PENABLE;
30613Sbill 	if ((tp->t_flags&EVENP) == 0)
30713Sbill 		d |= OPAR;
30813Sbill 	if ((tp->t_ospeed) == 3)	/* 110 baud */
30913Sbill 		d |= TWOSB;
31013Sbill 	addr->dhlpr = d;
311300Sbill 	splx(s);
31213Sbill }
31313Sbill 
31413Sbill /*
31513Sbill  * DH11 transmitter interrupt.
31613Sbill  * Restart each line which used to be active but has
31713Sbill  * terminated transmission since the last interrupt.
31813Sbill  */
31913Sbill dhxint(dev)
32013Sbill {
32113Sbill 	register struct tty *tp;
32213Sbill 	register struct device *addr;
32313Sbill 	register d;
32413Sbill 	short ttybit, bar, *sbar;
325144Sbill 	int s;
32613Sbill 
327144Sbill 	s = spl6();	/* block the clock */
32813Sbill 	d = minor(dev) & 0177;
32913Sbill 	addr = DHADDR + d;
33013Sbill 	addr->un.dhcsr &= (short)~XINT;
331105Sbill 	if (addr->un.dhcsr & NXM) {
332105Sbill 		addr->un.dhcsr |= CLRNXM;
333105Sbill 		printf("dh clr NXM\n");
334105Sbill 	}
33513Sbill 	sbar = &dhsar[d];
33613Sbill 	bar = *sbar & ~addr->dhbar;
33713Sbill 	d <<= 4; ttybit = 1;
33813Sbill 
33913Sbill 	for(; bar; d++, ttybit <<= 1) {
34013Sbill 		if(bar&ttybit) {
34113Sbill 			*sbar &= ~ttybit;
34213Sbill 			bar &= ~ttybit;
34313Sbill 			tp = &dh11[d];
344113Sbill 			tp->t_state &= ~BUSY;
345113Sbill 			if (tp->t_state&FLUSH)
346113Sbill 				tp->t_state &= ~FLUSH;
347113Sbill 			else {
348113Sbill 				addr->un.dhcsrl = (d&017)|IENAB;
349219Sbill 				ndflush(&tp->t_outq,
3501569Sbill 				    (int)(short)addr->dhcar-UBACVT(tp->t_outq.c_cf));
351113Sbill 			}
352113Sbill 			if (tp->t_line)
35313Sbill 				(*linesw[tp->t_line].l_start)(tp);
354113Sbill 			else
35513Sbill 				dhstart(tp);
35613Sbill 		}
35713Sbill 	}
358144Sbill 	splx(s);
35913Sbill }
36013Sbill 
36113Sbill /*
36213Sbill  * Start (restart) transmission on the given DH11 line.
36313Sbill  */
36413Sbill dhstart(tp)
36513Sbill register struct tty *tp;
36613Sbill {
36713Sbill 	register struct device *addr;
36813Sbill 	register short nch;
36913Sbill 	int s, d;
37013Sbill 
37113Sbill 	/*
37213Sbill 	 * If it's currently active, or delaying,
37313Sbill 	 * no need to do anything.
37413Sbill 	 */
37513Sbill 	s = spl5();
37613Sbill 	d = tp-dh11;
37713Sbill 	addr = (struct device *)tp->t_addr;
37813Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
37913Sbill 		goto out;
38013Sbill 
38113Sbill 	/*
38213Sbill 	 * If the writer was sleeping on output overflow,
38313Sbill 	 * wake him when low tide is reached.
38413Sbill 	 */
385921Sbill 	if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) {
38613Sbill 		tp->t_state &= ~ASLEEP;
38713Sbill 		if (tp->t_chan)
388168Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
389168Sbill 		else
39013Sbill 			wakeup((caddr_t)&tp->t_outq);
39113Sbill 	}
39213Sbill 
39313Sbill 	if (tp->t_outq.c_cc == 0)
39413Sbill 		goto out;
39513Sbill 
39613Sbill 	/*
39713Sbill 	 * Find number of characters to transfer.
39813Sbill 	 */
39913Sbill 	if (tp->t_flags & RAW) {
40013Sbill 		nch = ndqb(&tp->t_outq, 0);
40113Sbill 	} else {
40213Sbill 		nch = ndqb(&tp->t_outq, 0200);
40313Sbill 		if (nch == 0) {
40413Sbill 			nch = getc(&tp->t_outq);
40513Sbill 			timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
40613Sbill 			tp->t_state |= TIMEOUT;
40713Sbill 			goto out;
40813Sbill 		}
40913Sbill 	}
41013Sbill 	/*
41113Sbill 	 * If any characters were set up, start transmission;
41213Sbill 	 */
41313Sbill 	if (nch) {
41413Sbill 		addr->un.dhcsrl = (d&017)|IENAB;
41513Sbill 		addr->dhcar = UBACVT(tp->t_outq.c_cf);
41613Sbill 		addr->dhbcr = -nch;
41713Sbill 		nch = 1<<(d&017);
41813Sbill 		addr->dhbar |= nch;
41913Sbill 		dhsar[d>>4] |= nch;
42013Sbill 		tp->t_state |= BUSY;
42113Sbill 	}
42213Sbill     out:
42313Sbill 	splx(s);
42413Sbill }
42513Sbill 
42613Sbill /*
42713Sbill  * Stop output on a line.
42813Sbill  * Assume call is made at spl6.
42913Sbill  */
43013Sbill /*ARGSUSED*/
43113Sbill dhstop(tp, flag)
43213Sbill register struct tty *tp;
43313Sbill {
434113Sbill 	register struct device *addr;
435113Sbill 	register d, s;
43613Sbill 
437113Sbill 	addr = (struct device *)tp->t_addr;
43813Sbill 	s = spl6();
439113Sbill 	if (tp->t_state & BUSY) {
440113Sbill 		d = minor(tp->t_dev);
441113Sbill 		addr->un.dhcsrl = (d&017) | IENAB;
44213Sbill 		if ((tp->t_state&TTSTOP)==0)
44313Sbill 			tp->t_state |= FLUSH;
444113Sbill 		addr->dhbcr = -1;
445113Sbill 	}
44613Sbill 	splx(s);
44713Sbill }
44813Sbill 
449117Sbill int	dhsilo = 16;
450168Sbill /*
451168Sbill  * Silo control is fixed strategy
452168Sbill  * here, paralleling only option available
453168Sbill  * on DZ-11.
454168Sbill  */
45513Sbill /*ARGSUSED*/
456168Sbill dhtimer()
45713Sbill {
458168Sbill 	register d;
459117Sbill 	register struct device *addr;
460117Sbill 
46113Sbill 	addr = DHADDR; d = 0;
46213Sbill 	do {
463117Sbill 		if (dhact & (1<<d)) {
464280Sbill 			if ((dhisilo & (1<<d)) == 0) {
465280Sbill 				addr->dhsilo = dhsilo;
466280Sbill 				dhisilo |= 1<<d;
467280Sbill 			}
468117Sbill 			dhrint(d);
469117Sbill 		}
470117Sbill 		d++;
47113Sbill 		addr++;
47213Sbill 	} while (d < (NDH11+15)/16);
47313Sbill }
474280Sbill 
475280Sbill /*
476280Sbill  * Reset state of driver if UBA reset was necessary.
477280Sbill  * Reset the csrl and lpr registers on open lines, and
478280Sbill  * restart transmitters.
479280Sbill  */
480280Sbill dhreset()
481280Sbill {
482280Sbill 	int d;
483280Sbill 	register struct tty *tp;
484280Sbill 	register struct device *addr;
485280Sbill 
486280Sbill 	if (getcbase == 0)
487280Sbill 		return;
488280Sbill 	printf(" dh");
489280Sbill 	dhisilo = 0;
4902053Swnj 	ubarelse(&dh_ubinfo);
491280Sbill 	dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0);
492280Sbill 	cbase = (short)dh_ubinfo;
493280Sbill 	d = 0;
494280Sbill 	do {
495280Sbill 		addr = DHADDR + d;
496280Sbill 		if (dhact & (1<<d))
497300Sbill 			addr->un.dhcsr |= IENAB;
498280Sbill 		d++;
499280Sbill 	} while (d < (NDH11+15)/16);
500300Sbill 	for (d = 0; d < NDH11; d++) {
501300Sbill 		tp = &dh11[d];
502300Sbill 		if (tp->t_state & (ISOPEN|WOPEN)) {
503300Sbill 			dhparam(d);
504300Sbill 			dmctl(d, TURNON, DMSET);
505300Sbill 			tp->t_state &= ~BUSY;
506300Sbill 			dhstart(tp);
507300Sbill 		}
508300Sbill 	}
509300Sbill 	dhtimer();
510280Sbill }
5111944Swnj #if DHDM > 0
5121944Swnj #include "../dev/dhdm.c"
5131944Swnj #else
5141944Swnj #include "../dev/dhfdm.c"
5151808Sbill #endif
5161944Swnj #endif
517