xref: /csrg-svn/sys/vax/uba/dh.c (revision 113)
1*113Sbill /*	dh.c	3.3	10/14/12	*/
213Sbill 
313Sbill /*
413Sbill  *	DH-11 driver
513Sbill  *	This driver calls on the DHDM driver.
613Sbill  *	If the DH has no DM11-BB, then the latter will
713Sbill  *	be fake. To insure loading of the correct DM code,
813Sbill  *	lib2 should have dhdm.o, dh.o and dhfdm.o in that order.
913Sbill  */
1013Sbill 
1113Sbill #include "../h/param.h"
1213Sbill #include "../h/conf.h"
1313Sbill #include "../h/dir.h"
1413Sbill #include "../h/user.h"
1513Sbill #include "../h/tty.h"
1613Sbill #include "../h/map.h"
1713Sbill #include "../h/pte.h"
1813Sbill #include "../h/uba.h"
19*113Sbill #include "../h/bk.h"
2013Sbill 
2113Sbill #define	DHADDR	((struct device *)(UBA0_DEV + 0160020))
2213Sbill #define	NDH11	16	/* number of lines */
2313Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree))
2413Sbill 
2513Sbill struct cblock {
2613Sbill 	struct cblock *c_next;
2713Sbill 	char	c_info[CBSIZE];
2813Sbill };
2913Sbill 
3013Sbill struct	tty dh11[NDH11];
3113Sbill int	dhchars[(NDH11+15)/16];
3213Sbill int	ndh11	= NDH11;
3313Sbill int	dhstart();
3413Sbill int	ttrstrt();
3513Sbill int cbase;
3613Sbill extern struct cblock cfree[];
3713Sbill 
3813Sbill /*
3913Sbill  * Hardware control bits
4013Sbill  */
4113Sbill #define	BITS6	01
4213Sbill #define	BITS7	02
4313Sbill #define	BITS8	03
4413Sbill #define	TWOSB	04
4513Sbill #define	PENABLE	020
4613Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */
4713Sbill #define	OPAR	040
4813Sbill #define	HDUPLX	040000
4913Sbill 
5013Sbill #define	IENAB	030100
51105Sbill #define	NXM	02000
52105Sbill #define	CLRNXM	0400
5313Sbill #define	PERROR	010000
5413Sbill #define	FRERROR	020000
5513Sbill #define	OVERRUN	040000
5613Sbill #define	XINT	0100000
5713Sbill #define	SSPEED	7	/* standard speed: 300 baud */
5813Sbill 
5913Sbill #ifdef ERNIE
6013Sbill #define	DHTIME	2		/* Since Berknet packets are only 100 chars */
6113Sbill #else
6213Sbill #define	DHTIME	6
6313Sbill #endif
6413Sbill extern int dhtimer();
6513Sbill 
6613Sbill /*
6713Sbill  * DM control bits
6813Sbill  */
6913Sbill #define	TURNON	03	/* CD lead + line enable */
7013Sbill #define	TURNOFF	01	/* line enable */
7113Sbill #define	RQS	04	/* request to send */
7213Sbill 
7313Sbill /*
7413Sbill  * Software copy of last dhbar
7513Sbill  */
7613Sbill short	dhsar[(NDH11+15)/16];
7713Sbill 
7813Sbill struct device
7913Sbill {
8013Sbill 	union {
8113Sbill 		short	dhcsr;
8213Sbill 		char	dhcsrl;
8313Sbill 	} un;
8413Sbill 	short	dhnxch;
8513Sbill 	short	dhlpr;
8613Sbill 	unsigned short	dhcar;
8713Sbill 	short	dhbcr;
8813Sbill 	unsigned short	dhbar;
8913Sbill 	short	dhbreak;
9013Sbill 	short	dhsilo;
9113Sbill };
9213Sbill 
9313Sbill /*
9413Sbill  * Open a DH11 line.
9513Sbill  */
9613Sbill /*ARGSUSED*/
9713Sbill dhopen(dev, flag)
9813Sbill {
9913Sbill 	register struct tty *tp;
10013Sbill 	register d;
10113Sbill 	register struct device *addr;
10213Sbill 	static	timer_on;
10313Sbill 	int s;
10413Sbill 
10513Sbill 	d = minor(dev) & 0177;
10613Sbill 	if (d >= NDH11) {
10713Sbill 		u.u_error = ENXIO;
10813Sbill 		return;
10913Sbill 	}
11013Sbill 	tp = &dh11[d];
11113Sbill 	addr = DHADDR;
11213Sbill 	addr += d>>4;
11313Sbill 	tp->t_addr = (caddr_t)addr;
11413Sbill 	tp->t_oproc = dhstart;
11513Sbill 	tp->t_iproc = NULL;
11613Sbill 	tp->t_state |= WOPEN;
11713Sbill 	s = spl6();
11813Sbill 	if (!timer_on) {
11913Sbill 		timer_on++;
12013Sbill 		timeout(dhtimer, (caddr_t)0, DHTIME);
12113Sbill 		cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0);
12213Sbill 	}
12313Sbill 	splx(s);
12413Sbill 	addr->un.dhcsr |= IENAB;
12513Sbill 	if ((tp->t_state&ISOPEN) == 0) {
12613Sbill 		ttychars(tp);
12713Sbill 		tp->t_ispeed = SSPEED;
12813Sbill 		tp->t_ospeed = SSPEED;
12913Sbill 		tp->t_flags = ODDP|EVENP|ECHO;
13013Sbill 		dhparam(d);
13113Sbill 	}
13213Sbill 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
13313Sbill 		u.u_error = EBUSY;
13413Sbill 		return;
13513Sbill 	}
13613Sbill 	dmopen(dev);
13713Sbill 	(*linesw[tp->t_line].l_open)(dev,tp);
13813Sbill }
13913Sbill 
14013Sbill /*
14113Sbill  * Close a DH11 line.
14213Sbill  */
14313Sbill /*ARGSUSED*/
14413Sbill dhclose(dev, flag)
14513Sbill dev_t dev;
14613Sbill int  flag;
14713Sbill {
14813Sbill 	register struct tty *tp;
14913Sbill 	register d;
15013Sbill 
15113Sbill 	d = minor(dev) & 0177;
15213Sbill 	tp = &dh11[d];
15313Sbill 	(*linesw[tp->t_line].l_close)(tp);
15413Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
15513Sbill 		dmctl(d, TURNOFF);
15613Sbill 	ttyclose(tp);
15713Sbill }
15813Sbill 
15913Sbill /*
16013Sbill  * Read from a DH11 line.
16113Sbill  */
16213Sbill dhread(dev)
16313Sbill {
16413Sbill register struct tty *tp;
16513Sbill 
16613Sbill 	tp = &dh11[minor(dev) & 0177];
16713Sbill 	(*linesw[tp->t_line].l_read)(tp);
16813Sbill }
16913Sbill 
17013Sbill /*
17113Sbill  * write on a DH11 line
17213Sbill  */
17313Sbill dhwrite(dev)
17413Sbill {
17513Sbill register struct tty *tp;
17613Sbill 
17713Sbill 	tp = &dh11[minor(dev) & 0177];
17813Sbill 	(*linesw[tp->t_line].l_write)(tp);
17913Sbill }
18013Sbill 
18113Sbill /*
18213Sbill  * DH11 receiver interrupt.
18313Sbill  */
18413Sbill dhrint(dev)
18513Sbill {
18613Sbill 	register struct tty *tp;
18713Sbill 	register short c;
18813Sbill 	register struct device *addr;
18913Sbill 
19013Sbill 	addr = DHADDR;
19113Sbill 	addr += minor(dev) & 0177;
19213Sbill 	while ((c = addr->dhnxch) < 0) {	/* char. present */
19313Sbill 		tp = &dh11[((minor(dev)&0177)<<4) + ((c>>8)&017)];
19413Sbill 		dhchars[minor(dev)&0177]++;
19513Sbill 		if (tp >= &dh11[NDH11])
19613Sbill 			continue;
19713Sbill 		if((tp->t_state&ISOPEN)==0) {
19813Sbill 			wakeup((caddr_t)tp);
19913Sbill 			continue;
20013Sbill 		}
20113Sbill 		if (c&PERROR)
20213Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
20313Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
20413Sbill 				continue;
20513Sbill 		if (c&OVERRUN)
20613Sbill 			printf("O");
20713Sbill 		if (c&FRERROR)		/* break */
20813Sbill 			if (tp->t_flags&RAW)
20913Sbill 				c = 0;	/* null (for getty) */
21013Sbill 			else
21113Sbill 				c = 0177;	/* DEL (intr) */
212*113Sbill #ifdef BERKNET
213*113Sbill 			if (tp->t_line == BNETLDIS) {
214*113Sbill 				c &= 0177;
215*113Sbill 				NETINPUT(c, tp);
216*113Sbill 			} else
217*113Sbill #endif
218*113Sbill 				(*linesw[tp->t_line].l_rint)(c,tp);
21913Sbill 	}
22013Sbill }
22113Sbill 
22213Sbill /*
22313Sbill  * stty/gtty for DH11
22413Sbill  */
22513Sbill /*ARGSUSED*/
22613Sbill dhioctl(dev, cmd, addr, flag)
22713Sbill caddr_t addr;
22813Sbill {
22913Sbill 	register struct tty *tp;
23013Sbill 
23113Sbill 	tp = &dh11[minor(dev) & 0177];
232*113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
233*113Sbill 	if (cmd==0)
234*113Sbill 		return;
23513Sbill 	if (ttioccomm(cmd, tp, addr, dev)) {
23613Sbill 		if (cmd==TIOCSETP||cmd==TIOCSETN)
23713Sbill 			dhparam(dev);
23813Sbill 	} else if (cmd==TIOCSBRK) {
23913Sbill 		/* send a break */
24013Sbill 		register int linebit = 1 << (dev&017);
24113Sbill 		extern dhunbrk();
24213Sbill 
24313Sbill 		wflushtty(tp);
24413Sbill 		spl5();
24513Sbill 		((struct device *)tp->t_addr)->dhbreak |= linebit;
24613Sbill 		tp->t_state |= TIMEOUT;
24713Sbill 		timeout(dhunbrk, (caddr_t)tp, 25);	/* 300-500 ms */
24813Sbill 		while (((struct device *)tp->t_addr)->dhbreak & linebit)
24913Sbill 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
25013Sbill 		tp->t_state &= ~TIMEOUT;
25113Sbill 		spl0();
25213Sbill 		flushtty(tp);
25313Sbill 		return;
25413Sbill 	} else
25513Sbill 		u.u_error = ENOTTY;
25613Sbill }
25713Sbill 
25813Sbill dhunbrk(tp)
25913Sbill register struct tty *tp;
26013Sbill {
26113Sbill 
26213Sbill 	((struct device *)tp->t_addr)->dhbreak &= ~ (1 << (minor(tp->t_dev)&017));
26313Sbill 	wakeup((caddr_t)&tp->t_rawq);
26413Sbill }
26513Sbill 
26613Sbill /*
26713Sbill  * Set parameters from open or stty into the DH hardware
26813Sbill  * registers.
26913Sbill  */
27013Sbill dhparam(dev)
27113Sbill {
27213Sbill 	register struct tty *tp;
27313Sbill 	register struct device *addr;
27413Sbill 	register d;
27513Sbill 
27613Sbill 	d = minor(dev) & 0177;
27713Sbill 	tp = &dh11[d];
27813Sbill 	addr = (struct device *)tp->t_addr;
27913Sbill 	spl5();
28013Sbill 	addr->un.dhcsrl = (d&017) | IENAB;
28113Sbill 	/*
28213Sbill 	 * Hang up line?
28313Sbill 	 */
28413Sbill 	if ((tp->t_ispeed)==0) {
28513Sbill 		tp->t_state |= HUPCLS;
28613Sbill 		dmctl(d, TURNOFF);
28713Sbill 		return;
28813Sbill 	}
28913Sbill 	d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
29013Sbill 	if ((tp->t_ispeed) == 4)		/* 134.5 baud */
29113Sbill 		d |= BITS6|PENABLE|HDUPLX;
29213Sbill 	else if (tp->t_flags&RAW)
29313Sbill 		d |= BITS8;
29413Sbill 	else
29513Sbill 		d |= BITS7|PENABLE;
29613Sbill 	if ((tp->t_flags&EVENP) == 0)
29713Sbill 		d |= OPAR;
29813Sbill 	if ((tp->t_ospeed) == 3)	/* 110 baud */
29913Sbill 		d |= TWOSB;
30013Sbill 	addr->dhlpr = d;
30113Sbill 	spl0();
30213Sbill }
30313Sbill 
30413Sbill /*
30513Sbill  * DH11 transmitter interrupt.
30613Sbill  * Restart each line which used to be active but has
30713Sbill  * terminated transmission since the last interrupt.
30813Sbill  */
30913Sbill dhxint(dev)
31013Sbill {
31113Sbill 	register struct tty *tp;
31213Sbill 	register struct device *addr;
31313Sbill 	register d;
31413Sbill 	short ttybit, bar, *sbar;
31513Sbill 
31613Sbill 	d = minor(dev) & 0177;
31713Sbill 	addr = DHADDR + d;
31813Sbill 	addr->un.dhcsr &= (short)~XINT;
319105Sbill 	if (addr->un.dhcsr & NXM) {
320105Sbill 		addr->un.dhcsr |= CLRNXM;
321105Sbill 		printf("dh clr NXM\n");
322105Sbill 	}
32313Sbill 	sbar = &dhsar[d];
32413Sbill 	bar = *sbar & ~addr->dhbar;
32513Sbill 	d <<= 4; ttybit = 1;
32613Sbill 
32713Sbill 	for(; bar; d++, ttybit <<= 1) {
32813Sbill 		if(bar&ttybit) {
32913Sbill 			*sbar &= ~ttybit;
33013Sbill 			bar &= ~ttybit;
33113Sbill 			tp = &dh11[d];
332*113Sbill 			tp->t_state &= ~BUSY;
333*113Sbill 			if (tp->t_state&FLUSH)
334*113Sbill 				tp->t_state &= ~FLUSH;
335*113Sbill 			else {
336*113Sbill 				addr->un.dhcsrl = (d&017)|IENAB;
337*113Sbill 				ndflush(&tp->t_outq, addr->dhcar-UBACVT(tp->t_outq.c_cf));
338*113Sbill 			}
339*113Sbill 			if (tp->t_line)
34013Sbill 				(*linesw[tp->t_line].l_start)(tp);
341*113Sbill 			else
34213Sbill 				dhstart(tp);
34313Sbill 		}
34413Sbill 	}
34513Sbill }
34613Sbill 
34713Sbill /*
34813Sbill  * Start (restart) transmission on the given DH11 line.
34913Sbill  */
35013Sbill dhstart(tp)
35113Sbill register struct tty *tp;
35213Sbill {
35313Sbill 	register struct device *addr;
35413Sbill 	register short nch;
35513Sbill 	int s, d;
35613Sbill 
35713Sbill 	/*
35813Sbill 	 * If it's currently active, or delaying,
35913Sbill 	 * no need to do anything.
36013Sbill 	 */
36113Sbill 	s = spl5();
36213Sbill 	d = tp-dh11;
36313Sbill 	addr = (struct device *)tp->t_addr;
36413Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
36513Sbill 		goto out;
36613Sbill 
36713Sbill 	/*
36813Sbill 	 * If the writer was sleeping on output overflow,
36913Sbill 	 * wake him when low tide is reached.
37013Sbill 	 */
37113Sbill 	if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) {
37213Sbill 		tp->t_state &= ~ASLEEP;
37313Sbill 		if (tp->t_chan)
37413Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq); else
37513Sbill 			wakeup((caddr_t)&tp->t_outq);
37613Sbill 	}
37713Sbill 
37813Sbill 	if (tp->t_outq.c_cc == 0)
37913Sbill 		goto out;
38013Sbill 
38113Sbill 	/*
38213Sbill 	 * Find number of characters to transfer.
38313Sbill 	 */
38413Sbill 	if (tp->t_flags & RAW) {
38513Sbill 		nch = ndqb(&tp->t_outq, 0);
38613Sbill 	} else {
38713Sbill 		nch = ndqb(&tp->t_outq, 0200);
38813Sbill 		if (nch == 0) {
38913Sbill 			nch = getc(&tp->t_outq);
39013Sbill 			timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
39113Sbill 			tp->t_state |= TIMEOUT;
39213Sbill 			goto out;
39313Sbill 		}
39413Sbill 	}
39513Sbill 	/*
39613Sbill 	 * If any characters were set up, start transmission;
39713Sbill 	 */
39813Sbill 	if (nch) {
39913Sbill 		addr->un.dhcsrl = (d&017)|IENAB;
40013Sbill 		addr->dhcar = UBACVT(tp->t_outq.c_cf);
40113Sbill 		addr->dhbcr = -nch;
40213Sbill 		nch = 1<<(d&017);
40313Sbill 		addr->dhbar |= nch;
40413Sbill 		dhsar[d>>4] |= nch;
40513Sbill 		tp->t_state |= BUSY;
40613Sbill 	}
40713Sbill     out:
40813Sbill 	splx(s);
40913Sbill }
41013Sbill 
41113Sbill 
41213Sbill /*
41313Sbill  * Stop output on a line.
41413Sbill  * Assume call is made at spl6.
41513Sbill  */
41613Sbill /*ARGSUSED*/
41713Sbill dhstop(tp, flag)
41813Sbill register struct tty *tp;
41913Sbill {
420*113Sbill 	register struct device *addr;
421*113Sbill 	register d, s;
42213Sbill 
423*113Sbill 	addr = (struct device *)tp->t_addr;
42413Sbill 	s = spl6();
425*113Sbill 	if (tp->t_state & BUSY) {
426*113Sbill 		d = minor(tp->t_dev);
427*113Sbill 		addr->un.dhcsrl = (d&017) | IENAB;
42813Sbill 		if ((tp->t_state&TTSTOP)==0)
42913Sbill 			tp->t_state |= FLUSH;
430*113Sbill 		addr->dhbcr = -1;
431*113Sbill 	}
43213Sbill 	splx(s);
43313Sbill }
43413Sbill 
435*113Sbill int	minsilo = 16;
43613Sbill /*ARGSUSED*/
43713Sbill dhtimer(dev)
43813Sbill {
43913Sbill register d,cc;
44013Sbill register struct device *addr;
44113Sbill 	addr = DHADDR; d = 0;
44213Sbill 	do {
44313Sbill 		cc = dhchars[d];
44413Sbill 		dhchars[d] = 0;
44513Sbill 		if (cc > 8*DHTIME)
44613Sbill 			cc = 32; else
44713Sbill 			if (cc > 3*DHTIME)
44813Sbill 				cc = 16; else
449*113Sbill 				cc = minsilo;
45013Sbill 		addr->dhsilo = cc;
45113Sbill 		addr++;
45213Sbill 		dhrint(d++);
45313Sbill 	} while (d < (NDH11+15)/16);
45413Sbill 	timeout(dhtimer, (caddr_t)0, DHTIME);
45513Sbill }
456