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