xref: /csrg-svn/sys/vax/uba/dh.c (revision 280)
1*280Sbill /*	dh.c	3.12	06/22/80	*/
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 
21144Sbill /*
22144Sbill  * When running dz's using only SAE (silo alarm) on input
23144Sbill  * it is necessary to call dzrint() at clock interrupt time.
24144Sbill  * This is unsafe unless spl5()s in tty code are changed to
25144Sbill  * spl6()s to block clock interrupts.  Note that the dh driver
26144Sbill  * currently in use works the same way as the dz, even though
27144Sbill  * we could try to more intelligently manage its silo.
28144Sbill  * Thus don't take this out if you have no dz's unless you
29144Sbill  * change clock.c and dhtimer().
30144Sbill  */
31144Sbill #define	spl5	spl6
32144Sbill 
3313Sbill #define	DHADDR	((struct device *)(UBA0_DEV + 0160020))
34*280Sbill #define	NDH11	32	/* number of lines */
3513Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree))
3613Sbill 
3713Sbill struct cblock {
3813Sbill 	struct cblock *c_next;
3913Sbill 	char	c_info[CBSIZE];
4013Sbill };
4113Sbill 
4213Sbill struct	tty dh11[NDH11];
43117Sbill int	dhact;
44*280Sbill int	dhisilo;
4513Sbill int	ndh11	= NDH11;
4613Sbill int	dhstart();
4713Sbill int	ttrstrt();
48*280Sbill int	dh_ubinfo;
49*280Sbill int	cbase;
50*280Sbill int	getcbase;
51*280Sbill int	dhinit;
5213Sbill extern struct cblock cfree[];
5313Sbill 
5413Sbill /*
5513Sbill  * Hardware control bits
5613Sbill  */
5713Sbill #define	BITS6	01
5813Sbill #define	BITS7	02
5913Sbill #define	BITS8	03
6013Sbill #define	TWOSB	04
6113Sbill #define	PENABLE	020
6213Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */
6313Sbill #define	OPAR	040
6413Sbill #define	HDUPLX	040000
6513Sbill 
6613Sbill #define	IENAB	030100
67105Sbill #define	NXM	02000
68105Sbill #define	CLRNXM	0400
6913Sbill #define	PERROR	010000
7013Sbill #define	FRERROR	020000
7113Sbill #define	OVERRUN	040000
7213Sbill #define	XINT	0100000
7313Sbill #define	SSPEED	7	/* standard speed: 300 baud */
7413Sbill 
7513Sbill /*
7613Sbill  * DM control bits
7713Sbill  */
7813Sbill #define	TURNON	03	/* CD lead + line enable */
7913Sbill #define	TURNOFF	01	/* line enable */
80168Sbill #define	DTR	02	/* data terminal ready */
8113Sbill #define	RQS	04	/* request to send */
8213Sbill 
8313Sbill /*
8413Sbill  * Software copy of last dhbar
8513Sbill  */
8613Sbill short	dhsar[(NDH11+15)/16];
8713Sbill 
8813Sbill struct device
8913Sbill {
9013Sbill 	union {
9113Sbill 		short	dhcsr;
9213Sbill 		char	dhcsrl;
9313Sbill 	} un;
9413Sbill 	short	dhnxch;
9513Sbill 	short	dhlpr;
9613Sbill 	unsigned short	dhcar;
9713Sbill 	short	dhbcr;
9813Sbill 	unsigned short	dhbar;
9913Sbill 	short	dhbreak;
10013Sbill 	short	dhsilo;
10113Sbill };
10213Sbill 
10313Sbill /*
10413Sbill  * Open a DH11 line.
10513Sbill  */
10613Sbill /*ARGSUSED*/
10713Sbill dhopen(dev, flag)
10813Sbill {
10913Sbill 	register struct tty *tp;
11013Sbill 	register d;
11113Sbill 	register struct device *addr;
11213Sbill 	int s;
11313Sbill 
11413Sbill 	d = minor(dev) & 0177;
11513Sbill 	if (d >= NDH11) {
11613Sbill 		u.u_error = ENXIO;
11713Sbill 		return;
11813Sbill 	}
11913Sbill 	tp = &dh11[d];
12013Sbill 	addr = DHADDR;
12113Sbill 	addr += d>>4;
12213Sbill 	tp->t_addr = (caddr_t)addr;
12313Sbill 	tp->t_oproc = dhstart;
12413Sbill 	tp->t_iproc = NULL;
12513Sbill 	tp->t_state |= WOPEN;
12613Sbill 	s = spl6();
127117Sbill 	if (!getcbase) {
128117Sbill 		getcbase++;
129*280Sbill 		dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0);
130*280Sbill 		cbase = (short)dh_ubinfo;
13113Sbill 	}
13213Sbill 	splx(s);
13313Sbill 	addr->un.dhcsr |= IENAB;
134117Sbill 	dhact |= (1<<(d>>4));
13513Sbill 	if ((tp->t_state&ISOPEN) == 0) {
13613Sbill 		ttychars(tp);
137168Sbill 		if (tp->t_ispeed == 0) {
138168Sbill 			tp->t_ispeed = SSPEED;
139168Sbill 			tp->t_ospeed = SSPEED;
140168Sbill 			tp->t_flags = ODDP|EVENP|ECHO;
141168Sbill 		}
14213Sbill 		dhparam(d);
14313Sbill 	}
14413Sbill 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
14513Sbill 		u.u_error = EBUSY;
14613Sbill 		return;
14713Sbill 	}
14813Sbill 	dmopen(dev);
14913Sbill 	(*linesw[tp->t_line].l_open)(dev,tp);
15013Sbill }
15113Sbill 
15213Sbill /*
15313Sbill  * Close a DH11 line.
15413Sbill  */
15513Sbill /*ARGSUSED*/
15613Sbill dhclose(dev, flag)
15713Sbill dev_t dev;
15813Sbill int  flag;
15913Sbill {
16013Sbill 	register struct tty *tp;
16113Sbill 	register d;
16213Sbill 
16313Sbill 	d = minor(dev) & 0177;
16413Sbill 	tp = &dh11[d];
16513Sbill 	(*linesw[tp->t_line].l_close)(tp);
16613Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
167168Sbill 		dmctl(d, TURNOFF, DMSET);
16813Sbill 	ttyclose(tp);
16913Sbill }
17013Sbill 
17113Sbill /*
17213Sbill  * Read from a DH11 line.
17313Sbill  */
17413Sbill dhread(dev)
17513Sbill {
17613Sbill register struct tty *tp;
17713Sbill 
17813Sbill 	tp = &dh11[minor(dev) & 0177];
17913Sbill 	(*linesw[tp->t_line].l_read)(tp);
18013Sbill }
18113Sbill 
18213Sbill /*
18313Sbill  * write on a DH11 line
18413Sbill  */
18513Sbill dhwrite(dev)
18613Sbill {
18713Sbill register struct tty *tp;
18813Sbill 
18913Sbill 	tp = &dh11[minor(dev) & 0177];
19013Sbill 	(*linesw[tp->t_line].l_write)(tp);
19113Sbill }
19213Sbill 
19313Sbill /*
19413Sbill  * DH11 receiver interrupt.
19513Sbill  */
19613Sbill dhrint(dev)
19713Sbill {
19813Sbill 	register struct tty *tp;
19913Sbill 	register short c;
20013Sbill 	register struct device *addr;
201117Sbill 	register struct tty *tp0;
202139Sbill 	int s;
20313Sbill 
204139Sbill 	s = spl6();	/* see comment in clock.c */
20513Sbill 	addr = DHADDR;
20613Sbill 	addr += minor(dev) & 0177;
207117Sbill 	tp0 = &dh11[((minor(dev)&0177)<<4)];
20813Sbill 	while ((c = addr->dhnxch) < 0) {	/* char. present */
209117Sbill 		tp = tp0 + ((c>>8)&017);
21013Sbill 		if (tp >= &dh11[NDH11])
21113Sbill 			continue;
21213Sbill 		if((tp->t_state&ISOPEN)==0) {
21313Sbill 			wakeup((caddr_t)tp);
21413Sbill 			continue;
21513Sbill 		}
21613Sbill 		if (c&PERROR)
21713Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
21813Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
21913Sbill 				continue;
22013Sbill 		if (c&OVERRUN)
22113Sbill 			printf("O");
22213Sbill 		if (c&FRERROR)		/* break */
22313Sbill 			if (tp->t_flags&RAW)
22413Sbill 				c = 0;	/* null (for getty) */
22513Sbill 			else
226168Sbill #ifdef IIASA
227168Sbill 				continue;
228168Sbill #else
229184Sbill 				c = tun.t_intrc;
230168Sbill #endif
231139Sbill 		if (tp->t_line == NETLDISC) {
232117Sbill 			c &= 0177;
233168Sbill 			BKINPUT(c, tp);
234117Sbill 		} else
235117Sbill 			(*linesw[tp->t_line].l_rint)(c,tp);
23613Sbill 	}
237139Sbill 	splx(s);
23813Sbill }
23913Sbill 
24013Sbill /*
24113Sbill  * stty/gtty for DH11
24213Sbill  */
24313Sbill /*ARGSUSED*/
24413Sbill dhioctl(dev, cmd, addr, flag)
24513Sbill caddr_t addr;
24613Sbill {
24713Sbill 	register struct tty *tp;
24813Sbill 
24913Sbill 	tp = &dh11[minor(dev) & 0177];
250113Sbill 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
251113Sbill 	if (cmd==0)
252113Sbill 		return;
25313Sbill 	if (ttioccomm(cmd, tp, addr, dev)) {
25413Sbill 		if (cmd==TIOCSETP||cmd==TIOCSETN)
25513Sbill 			dhparam(dev);
256168Sbill 	} else switch(cmd) {
257168Sbill 	case TIOCSBRK:
258168Sbill 		((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017);
259168Sbill 		break;
260168Sbill 	case TIOCCBRK:
261168Sbill 		((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
262168Sbill 		break;
263168Sbill 	case TIOCSDTR:
264168Sbill 		dmctl(minor(dev), DTR|RQS, DMBIS);
265168Sbill 		break;
266168Sbill 	case TIOCCDTR:
267168Sbill 		dmctl(minor(dev), DTR|RQS, DMBIC);
268168Sbill 		break;
269168Sbill 	default:
27013Sbill 		u.u_error = ENOTTY;
271168Sbill 	}
27213Sbill }
27313Sbill 
27413Sbill /*
27513Sbill  * Set parameters from open or stty into the DH hardware
27613Sbill  * registers.
27713Sbill  */
27813Sbill dhparam(dev)
27913Sbill {
28013Sbill 	register struct tty *tp;
28113Sbill 	register struct device *addr;
28213Sbill 	register d;
28313Sbill 
28413Sbill 	d = minor(dev) & 0177;
28513Sbill 	tp = &dh11[d];
28613Sbill 	addr = (struct device *)tp->t_addr;
28713Sbill 	spl5();
28813Sbill 	addr->un.dhcsrl = (d&017) | IENAB;
28913Sbill 	/*
29013Sbill 	 * Hang up line?
29113Sbill 	 */
29213Sbill 	if ((tp->t_ispeed)==0) {
29313Sbill 		tp->t_state |= HUPCLS;
294168Sbill 		dmctl(d, TURNOFF, DMSET);
29513Sbill 		return;
29613Sbill 	}
29713Sbill 	d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
29813Sbill 	if ((tp->t_ispeed) == 4)		/* 134.5 baud */
29913Sbill 		d |= BITS6|PENABLE|HDUPLX;
30013Sbill 	else if (tp->t_flags&RAW)
30113Sbill 		d |= BITS8;
30213Sbill 	else
30313Sbill 		d |= BITS7|PENABLE;
30413Sbill 	if ((tp->t_flags&EVENP) == 0)
30513Sbill 		d |= OPAR;
30613Sbill 	if ((tp->t_ospeed) == 3)	/* 110 baud */
30713Sbill 		d |= TWOSB;
30813Sbill 	addr->dhlpr = d;
30913Sbill 	spl0();
31013Sbill }
31113Sbill 
31213Sbill /*
31313Sbill  * DH11 transmitter interrupt.
31413Sbill  * Restart each line which used to be active but has
31513Sbill  * terminated transmission since the last interrupt.
31613Sbill  */
31713Sbill dhxint(dev)
31813Sbill {
31913Sbill 	register struct tty *tp;
32013Sbill 	register struct device *addr;
32113Sbill 	register d;
32213Sbill 	short ttybit, bar, *sbar;
323144Sbill 	int s;
32413Sbill 
325144Sbill 	s = spl6();	/* block the clock */
32613Sbill 	d = minor(dev) & 0177;
32713Sbill 	addr = DHADDR + d;
32813Sbill 	addr->un.dhcsr &= (short)~XINT;
329105Sbill 	if (addr->un.dhcsr & NXM) {
330105Sbill 		addr->un.dhcsr |= CLRNXM;
331105Sbill 		printf("dh clr NXM\n");
332105Sbill 	}
33313Sbill 	sbar = &dhsar[d];
33413Sbill 	bar = *sbar & ~addr->dhbar;
335*280Sbill 	if (dhinit)
336*280Sbill 		bar = ~0;
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;
349*280Sbill 				if (dhinit == 0)
350219Sbill 				ndflush(&tp->t_outq,
351219Sbill 				    (int)addr->dhcar-UBACVT(tp->t_outq.c_cf));
352113Sbill 			}
353113Sbill 			if (tp->t_line)
35413Sbill 				(*linesw[tp->t_line].l_start)(tp);
355113Sbill 			else
35613Sbill 				dhstart(tp);
35713Sbill 		}
35813Sbill 	}
359144Sbill 	splx(s);
36013Sbill }
36113Sbill 
36213Sbill /*
36313Sbill  * Start (restart) transmission on the given DH11 line.
36413Sbill  */
36513Sbill dhstart(tp)
36613Sbill register struct tty *tp;
36713Sbill {
36813Sbill 	register struct device *addr;
36913Sbill 	register short nch;
37013Sbill 	int s, d;
37113Sbill 
37213Sbill 	/*
37313Sbill 	 * If it's currently active, or delaying,
37413Sbill 	 * no need to do anything.
37513Sbill 	 */
37613Sbill 	s = spl5();
37713Sbill 	d = tp-dh11;
37813Sbill 	addr = (struct device *)tp->t_addr;
37913Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
38013Sbill 		goto out;
38113Sbill 
38213Sbill 	/*
38313Sbill 	 * If the writer was sleeping on output overflow,
38413Sbill 	 * wake him when low tide is reached.
38513Sbill 	 */
38613Sbill 	if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) {
38713Sbill 		tp->t_state &= ~ASLEEP;
38813Sbill 		if (tp->t_chan)
389168Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
390168Sbill 		else
39113Sbill 			wakeup((caddr_t)&tp->t_outq);
39213Sbill 	}
39313Sbill 
39413Sbill 	if (tp->t_outq.c_cc == 0)
39513Sbill 		goto out;
39613Sbill 
39713Sbill 	/*
39813Sbill 	 * Find number of characters to transfer.
39913Sbill 	 */
40013Sbill 	if (tp->t_flags & RAW) {
40113Sbill 		nch = ndqb(&tp->t_outq, 0);
40213Sbill 	} else {
40313Sbill 		nch = ndqb(&tp->t_outq, 0200);
40413Sbill 		if (nch == 0) {
40513Sbill 			nch = getc(&tp->t_outq);
40613Sbill 			timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
40713Sbill 			tp->t_state |= TIMEOUT;
40813Sbill 			goto out;
40913Sbill 		}
41013Sbill 	}
41113Sbill 	/*
41213Sbill 	 * If any characters were set up, start transmission;
41313Sbill 	 */
41413Sbill 	if (nch) {
41513Sbill 		addr->un.dhcsrl = (d&017)|IENAB;
41613Sbill 		addr->dhcar = UBACVT(tp->t_outq.c_cf);
41713Sbill 		addr->dhbcr = -nch;
41813Sbill 		nch = 1<<(d&017);
41913Sbill 		addr->dhbar |= nch;
42013Sbill 		dhsar[d>>4] |= nch;
42113Sbill 		tp->t_state |= BUSY;
42213Sbill 	}
42313Sbill     out:
42413Sbill 	splx(s);
42513Sbill }
42613Sbill 
42713Sbill /*
42813Sbill  * Stop output on a line.
42913Sbill  * Assume call is made at spl6.
43013Sbill  */
43113Sbill /*ARGSUSED*/
43213Sbill dhstop(tp, flag)
43313Sbill register struct tty *tp;
43413Sbill {
435113Sbill 	register struct device *addr;
436113Sbill 	register d, s;
43713Sbill 
438113Sbill 	addr = (struct device *)tp->t_addr;
43913Sbill 	s = spl6();
440113Sbill 	if (tp->t_state & BUSY) {
441113Sbill 		d = minor(tp->t_dev);
442113Sbill 		addr->un.dhcsrl = (d&017) | IENAB;
44313Sbill 		if ((tp->t_state&TTSTOP)==0)
44413Sbill 			tp->t_state |= FLUSH;
445113Sbill 		addr->dhbcr = -1;
446113Sbill 	}
44713Sbill 	splx(s);
44813Sbill }
44913Sbill 
450117Sbill int	dhsilo = 16;
451168Sbill /*
452168Sbill  * Silo control is fixed strategy
453168Sbill  * here, paralleling only option available
454168Sbill  * on DZ-11.
455168Sbill  */
45613Sbill /*ARGSUSED*/
457168Sbill dhtimer()
45813Sbill {
459168Sbill 	register d;
460117Sbill 	register struct device *addr;
461117Sbill 
46213Sbill 	addr = DHADDR; d = 0;
46313Sbill 	do {
464117Sbill 		if (dhact & (1<<d)) {
465*280Sbill 			if ((dhisilo & (1<<d)) == 0) {
466*280Sbill 				addr->dhsilo = dhsilo;
467*280Sbill 				dhisilo |= 1<<d;
468*280Sbill 			}
469117Sbill 			dhrint(d);
470117Sbill 		}
471117Sbill 		d++;
47213Sbill 		addr++;
47313Sbill 	} while (d < (NDH11+15)/16);
47413Sbill }
475*280Sbill 
476*280Sbill /*
477*280Sbill  * Reset state of driver if UBA reset was necessary.
478*280Sbill  * Reset the csrl and lpr registers on open lines, and
479*280Sbill  * restart transmitters.
480*280Sbill  */
481*280Sbill dhreset()
482*280Sbill {
483*280Sbill 	int d;
484*280Sbill 	register struct tty *tp;
485*280Sbill 	register struct device *addr;
486*280Sbill 
487*280Sbill 	if (getcbase == 0)
488*280Sbill 		return;
489*280Sbill 	printf(" dh");
490*280Sbill 	dhinit = 1;
491*280Sbill 	dhisilo = 0;
492*280Sbill 	ubafree(dh_ubinfo);
493*280Sbill 	dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0);
494*280Sbill 	cbase = (short)dh_ubinfo;
495*280Sbill 	for (d = 0; d < NDH11; d++) {
496*280Sbill 		tp = &dh11[d];
497*280Sbill 		if (tp->t_state & (ISOPEN|WOPEN))
498*280Sbill 			dhparam(d);
499*280Sbill 	}
500*280Sbill 	dhtimer();
501*280Sbill 	d = 0;
502*280Sbill 	do {
503*280Sbill 		addr = DHADDR + d;
504*280Sbill 		addr->un.dhcsr |= IENAB;
505*280Sbill 		if (dhact & (1<<d))
506*280Sbill 			dhxint(d<<4);
507*280Sbill 		d++;
508*280Sbill 	} while (d < (NDH11+15)/16);
509*280Sbill 	dhinit = 0;
510*280Sbill }
511