xref: /csrg-svn/sys/vax/uba/dh.c (revision 117)
1*117Sbill /*	dh.c	3.4	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"
19113Sbill #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];
31*117Sbill int	dhact;
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 /*
6013Sbill  * DM control bits
6113Sbill  */
6213Sbill #define	TURNON	03	/* CD lead + line enable */
6313Sbill #define	TURNOFF	01	/* line enable */
6413Sbill #define	RQS	04	/* request to send */
6513Sbill 
6613Sbill /*
6713Sbill  * Software copy of last dhbar
6813Sbill  */
6913Sbill short	dhsar[(NDH11+15)/16];
7013Sbill 
7113Sbill struct device
7213Sbill {
7313Sbill 	union {
7413Sbill 		short	dhcsr;
7513Sbill 		char	dhcsrl;
7613Sbill 	} un;
7713Sbill 	short	dhnxch;
7813Sbill 	short	dhlpr;
7913Sbill 	unsigned short	dhcar;
8013Sbill 	short	dhbcr;
8113Sbill 	unsigned short	dhbar;
8213Sbill 	short	dhbreak;
8313Sbill 	short	dhsilo;
8413Sbill };
8513Sbill 
8613Sbill /*
8713Sbill  * Open a DH11 line.
8813Sbill  */
8913Sbill /*ARGSUSED*/
9013Sbill dhopen(dev, flag)
9113Sbill {
9213Sbill 	register struct tty *tp;
9313Sbill 	register d;
9413Sbill 	register struct device *addr;
95*117Sbill 	static getcbase;
9613Sbill 	int s;
9713Sbill 
9813Sbill 	d = minor(dev) & 0177;
9913Sbill 	if (d >= NDH11) {
10013Sbill 		u.u_error = ENXIO;
10113Sbill 		return;
10213Sbill 	}
10313Sbill 	tp = &dh11[d];
10413Sbill 	addr = DHADDR;
10513Sbill 	addr += d>>4;
10613Sbill 	tp->t_addr = (caddr_t)addr;
10713Sbill 	tp->t_oproc = dhstart;
10813Sbill 	tp->t_iproc = NULL;
10913Sbill 	tp->t_state |= WOPEN;
11013Sbill 	s = spl6();
111*117Sbill 	if (!getcbase) {
112*117Sbill 		getcbase++;
11313Sbill 		cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0);
11413Sbill 	}
11513Sbill 	splx(s);
11613Sbill 	addr->un.dhcsr |= IENAB;
117*117Sbill 	dhact |= (1<<(d>>4));
11813Sbill 	if ((tp->t_state&ISOPEN) == 0) {
11913Sbill 		ttychars(tp);
12013Sbill 		tp->t_ispeed = SSPEED;
12113Sbill 		tp->t_ospeed = SSPEED;
12213Sbill 		tp->t_flags = ODDP|EVENP|ECHO;
12313Sbill 		dhparam(d);
12413Sbill 	}
12513Sbill 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
12613Sbill 		u.u_error = EBUSY;
12713Sbill 		return;
12813Sbill 	}
12913Sbill 	dmopen(dev);
13013Sbill 	(*linesw[tp->t_line].l_open)(dev,tp);
13113Sbill }
13213Sbill 
13313Sbill /*
13413Sbill  * Close a DH11 line.
13513Sbill  */
13613Sbill /*ARGSUSED*/
13713Sbill dhclose(dev, flag)
13813Sbill dev_t dev;
13913Sbill int  flag;
14013Sbill {
14113Sbill 	register struct tty *tp;
14213Sbill 	register d;
14313Sbill 
14413Sbill 	d = minor(dev) & 0177;
14513Sbill 	tp = &dh11[d];
14613Sbill 	(*linesw[tp->t_line].l_close)(tp);
14713Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
14813Sbill 		dmctl(d, TURNOFF);
14913Sbill 	ttyclose(tp);
15013Sbill }
15113Sbill 
15213Sbill /*
15313Sbill  * Read from a DH11 line.
15413Sbill  */
15513Sbill dhread(dev)
15613Sbill {
15713Sbill register struct tty *tp;
15813Sbill 
15913Sbill 	tp = &dh11[minor(dev) & 0177];
16013Sbill 	(*linesw[tp->t_line].l_read)(tp);
16113Sbill }
16213Sbill 
16313Sbill /*
16413Sbill  * write on a DH11 line
16513Sbill  */
16613Sbill dhwrite(dev)
16713Sbill {
16813Sbill register struct tty *tp;
16913Sbill 
17013Sbill 	tp = &dh11[minor(dev) & 0177];
17113Sbill 	(*linesw[tp->t_line].l_write)(tp);
17213Sbill }
17313Sbill 
17413Sbill /*
17513Sbill  * DH11 receiver interrupt.
17613Sbill  */
17713Sbill dhrint(dev)
17813Sbill {
17913Sbill 	register struct tty *tp;
18013Sbill 	register short c;
18113Sbill 	register struct device *addr;
182*117Sbill 	register struct tty *tp0;
18313Sbill 
18413Sbill 	addr = DHADDR;
18513Sbill 	addr += minor(dev) & 0177;
186*117Sbill 	tp0 = &dh11[((minor(dev)&0177)<<4)];
18713Sbill 	while ((c = addr->dhnxch) < 0) {	/* char. present */
188*117Sbill 		tp = tp0 + ((c>>8)&017);
18913Sbill 		if (tp >= &dh11[NDH11])
19013Sbill 			continue;
19113Sbill 		if((tp->t_state&ISOPEN)==0) {
19213Sbill 			wakeup((caddr_t)tp);
19313Sbill 			continue;
19413Sbill 		}
19513Sbill 		if (c&PERROR)
19613Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
19713Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
19813Sbill 				continue;
19913Sbill 		if (c&OVERRUN)
20013Sbill 			printf("O");
20113Sbill 		if (c&FRERROR)		/* break */
20213Sbill 			if (tp->t_flags&RAW)
20313Sbill 				c = 0;	/* null (for getty) */
20413Sbill 			else
20513Sbill 				c = 0177;	/* DEL (intr) */
206113Sbill #ifdef BERKNET
207*117Sbill 		if (tp->t_line == BNETLDIS) {
208*117Sbill 			c &= 0177;
209*117Sbill 			NETINPUT(c, tp);
210*117Sbill 		} else
211113Sbill #endif
212*117Sbill 			(*linesw[tp->t_line].l_rint)(c,tp);
21313Sbill 	}
21413Sbill }
21513Sbill 
21613Sbill /*
21713Sbill  * stty/gtty for DH11
21813Sbill  */
21913Sbill /*ARGSUSED*/
22013Sbill dhioctl(dev, cmd, addr, flag)
22113Sbill caddr_t addr;
22213Sbill {
22313Sbill 	register struct tty *tp;
22413Sbill 
22513Sbill 	tp = &dh11[minor(dev) & 0177];
226113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
227113Sbill 	if (cmd==0)
228113Sbill 		return;
22913Sbill 	if (ttioccomm(cmd, tp, addr, dev)) {
23013Sbill 		if (cmd==TIOCSETP||cmd==TIOCSETN)
23113Sbill 			dhparam(dev);
23213Sbill 	} else if (cmd==TIOCSBRK) {
23313Sbill 		/* send a break */
23413Sbill 		register int linebit = 1 << (dev&017);
23513Sbill 		extern dhunbrk();
23613Sbill 
23713Sbill 		wflushtty(tp);
23813Sbill 		spl5();
23913Sbill 		((struct device *)tp->t_addr)->dhbreak |= linebit;
24013Sbill 		tp->t_state |= TIMEOUT;
24113Sbill 		timeout(dhunbrk, (caddr_t)tp, 25);	/* 300-500 ms */
24213Sbill 		while (((struct device *)tp->t_addr)->dhbreak & linebit)
24313Sbill 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
24413Sbill 		tp->t_state &= ~TIMEOUT;
24513Sbill 		spl0();
24613Sbill 		flushtty(tp);
24713Sbill 		return;
24813Sbill 	} else
24913Sbill 		u.u_error = ENOTTY;
25013Sbill }
25113Sbill 
25213Sbill dhunbrk(tp)
25313Sbill register struct tty *tp;
25413Sbill {
25513Sbill 
25613Sbill 	((struct device *)tp->t_addr)->dhbreak &= ~ (1 << (minor(tp->t_dev)&017));
25713Sbill 	wakeup((caddr_t)&tp->t_rawq);
25813Sbill }
25913Sbill 
26013Sbill /*
26113Sbill  * Set parameters from open or stty into the DH hardware
26213Sbill  * registers.
26313Sbill  */
26413Sbill dhparam(dev)
26513Sbill {
26613Sbill 	register struct tty *tp;
26713Sbill 	register struct device *addr;
26813Sbill 	register d;
26913Sbill 
27013Sbill 	d = minor(dev) & 0177;
27113Sbill 	tp = &dh11[d];
27213Sbill 	addr = (struct device *)tp->t_addr;
27313Sbill 	spl5();
27413Sbill 	addr->un.dhcsrl = (d&017) | IENAB;
27513Sbill 	/*
27613Sbill 	 * Hang up line?
27713Sbill 	 */
27813Sbill 	if ((tp->t_ispeed)==0) {
27913Sbill 		tp->t_state |= HUPCLS;
28013Sbill 		dmctl(d, TURNOFF);
28113Sbill 		return;
28213Sbill 	}
28313Sbill 	d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
28413Sbill 	if ((tp->t_ispeed) == 4)		/* 134.5 baud */
28513Sbill 		d |= BITS6|PENABLE|HDUPLX;
28613Sbill 	else if (tp->t_flags&RAW)
28713Sbill 		d |= BITS8;
28813Sbill 	else
28913Sbill 		d |= BITS7|PENABLE;
29013Sbill 	if ((tp->t_flags&EVENP) == 0)
29113Sbill 		d |= OPAR;
29213Sbill 	if ((tp->t_ospeed) == 3)	/* 110 baud */
29313Sbill 		d |= TWOSB;
29413Sbill 	addr->dhlpr = d;
29513Sbill 	spl0();
29613Sbill }
29713Sbill 
29813Sbill /*
29913Sbill  * DH11 transmitter interrupt.
30013Sbill  * Restart each line which used to be active but has
30113Sbill  * terminated transmission since the last interrupt.
30213Sbill  */
30313Sbill dhxint(dev)
30413Sbill {
30513Sbill 	register struct tty *tp;
30613Sbill 	register struct device *addr;
30713Sbill 	register d;
30813Sbill 	short ttybit, bar, *sbar;
30913Sbill 
31013Sbill 	d = minor(dev) & 0177;
31113Sbill 	addr = DHADDR + d;
31213Sbill 	addr->un.dhcsr &= (short)~XINT;
313105Sbill 	if (addr->un.dhcsr & NXM) {
314105Sbill 		addr->un.dhcsr |= CLRNXM;
315105Sbill 		printf("dh clr NXM\n");
316105Sbill 	}
31713Sbill 	sbar = &dhsar[d];
31813Sbill 	bar = *sbar & ~addr->dhbar;
31913Sbill 	d <<= 4; ttybit = 1;
32013Sbill 
32113Sbill 	for(; bar; d++, ttybit <<= 1) {
32213Sbill 		if(bar&ttybit) {
32313Sbill 			*sbar &= ~ttybit;
32413Sbill 			bar &= ~ttybit;
32513Sbill 			tp = &dh11[d];
326113Sbill 			tp->t_state &= ~BUSY;
327113Sbill 			if (tp->t_state&FLUSH)
328113Sbill 				tp->t_state &= ~FLUSH;
329113Sbill 			else {
330113Sbill 				addr->un.dhcsrl = (d&017)|IENAB;
331113Sbill 				ndflush(&tp->t_outq, addr->dhcar-UBACVT(tp->t_outq.c_cf));
332113Sbill 			}
333113Sbill 			if (tp->t_line)
33413Sbill 				(*linesw[tp->t_line].l_start)(tp);
335113Sbill 			else
33613Sbill 				dhstart(tp);
33713Sbill 		}
33813Sbill 	}
33913Sbill }
34013Sbill 
34113Sbill /*
34213Sbill  * Start (restart) transmission on the given DH11 line.
34313Sbill  */
34413Sbill dhstart(tp)
34513Sbill register struct tty *tp;
34613Sbill {
34713Sbill 	register struct device *addr;
34813Sbill 	register short nch;
34913Sbill 	int s, d;
35013Sbill 
35113Sbill 	/*
35213Sbill 	 * If it's currently active, or delaying,
35313Sbill 	 * no need to do anything.
35413Sbill 	 */
35513Sbill 	s = spl5();
35613Sbill 	d = tp-dh11;
35713Sbill 	addr = (struct device *)tp->t_addr;
35813Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
35913Sbill 		goto out;
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 	 * Find number of characters to transfer.
37713Sbill 	 */
37813Sbill 	if (tp->t_flags & RAW) {
37913Sbill 		nch = ndqb(&tp->t_outq, 0);
38013Sbill 	} else {
38113Sbill 		nch = ndqb(&tp->t_outq, 0200);
38213Sbill 		if (nch == 0) {
38313Sbill 			nch = getc(&tp->t_outq);
38413Sbill 			timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
38513Sbill 			tp->t_state |= TIMEOUT;
38613Sbill 			goto out;
38713Sbill 		}
38813Sbill 	}
38913Sbill 	/*
39013Sbill 	 * If any characters were set up, start transmission;
39113Sbill 	 */
39213Sbill 	if (nch) {
39313Sbill 		addr->un.dhcsrl = (d&017)|IENAB;
39413Sbill 		addr->dhcar = UBACVT(tp->t_outq.c_cf);
39513Sbill 		addr->dhbcr = -nch;
39613Sbill 		nch = 1<<(d&017);
39713Sbill 		addr->dhbar |= nch;
39813Sbill 		dhsar[d>>4] |= nch;
39913Sbill 		tp->t_state |= BUSY;
40013Sbill 	}
40113Sbill     out:
40213Sbill 	splx(s);
40313Sbill }
40413Sbill 
40513Sbill 
40613Sbill /*
40713Sbill  * Stop output on a line.
40813Sbill  * Assume call is made at spl6.
40913Sbill  */
41013Sbill /*ARGSUSED*/
41113Sbill dhstop(tp, flag)
41213Sbill register struct tty *tp;
41313Sbill {
414113Sbill 	register struct device *addr;
415113Sbill 	register d, s;
41613Sbill 
417113Sbill 	addr = (struct device *)tp->t_addr;
41813Sbill 	s = spl6();
419113Sbill 	if (tp->t_state & BUSY) {
420113Sbill 		d = minor(tp->t_dev);
421113Sbill 		addr->un.dhcsrl = (d&017) | IENAB;
42213Sbill 		if ((tp->t_state&TTSTOP)==0)
42313Sbill 			tp->t_state |= FLUSH;
424113Sbill 		addr->dhbcr = -1;
425113Sbill 	}
42613Sbill 	splx(s);
42713Sbill }
42813Sbill 
429*117Sbill int	dhsilo = 16;
43013Sbill /*ARGSUSED*/
43113Sbill dhtimer(dev)
43213Sbill {
433*117Sbill 	register d,cc;
434*117Sbill 	register struct device *addr;
435*117Sbill 
43613Sbill 	addr = DHADDR; d = 0;
43713Sbill 	do {
438*117Sbill 		if (dhact & (1<<d)) {
439*117Sbill 			addr->dhsilo = dhsilo;
440*117Sbill 			dhrint(d);
441*117Sbill 		}
442*117Sbill 		d++;
44313Sbill 		addr++;
44413Sbill 	} while (d < (NDH11+15)/16);
44513Sbill }
446