xref: /csrg-svn/sys/vax/uba/dh.c (revision 13)
1*13Sbill /*	dh.c	3.1	10/14/12	*/
2*13Sbill 
3*13Sbill /*
4*13Sbill  *	DH-11 driver
5*13Sbill  *	This driver calls on the DHDM driver.
6*13Sbill  *	If the DH has no DM11-BB, then the latter will
7*13Sbill  *	be fake. To insure loading of the correct DM code,
8*13Sbill  *	lib2 should have dhdm.o, dh.o and dhfdm.o in that order.
9*13Sbill  */
10*13Sbill 
11*13Sbill #include "../h/param.h"
12*13Sbill #include "../h/conf.h"
13*13Sbill #include "../h/dir.h"
14*13Sbill #include "../h/user.h"
15*13Sbill #include "../h/tty.h"
16*13Sbill #include "../h/map.h"
17*13Sbill #include "../h/pte.h"
18*13Sbill #include "../h/uba.h"
19*13Sbill 
20*13Sbill #define	q3	tp->t_outq
21*13Sbill #define	DHADDR	((struct device *)(UBA0_DEV + 0160020))
22*13Sbill #define	NDH11	16	/* number of lines */
23*13Sbill #define UBACVT(x) (cbase + (short)((x)-(char *)cfree))
24*13Sbill 
25*13Sbill struct cblock {
26*13Sbill 	struct cblock *c_next;
27*13Sbill 	char	c_info[CBSIZE];
28*13Sbill };
29*13Sbill 
30*13Sbill struct	tty dh11[NDH11];
31*13Sbill short	dhcc[NDH11];
32*13Sbill int	dhchars[(NDH11+15)/16];
33*13Sbill int	ndh11	= NDH11;
34*13Sbill int	dhstart();
35*13Sbill int	ttrstrt();
36*13Sbill int cbase;
37*13Sbill extern struct cblock cfree[];
38*13Sbill 
39*13Sbill /*
40*13Sbill  * Hardware control bits
41*13Sbill  */
42*13Sbill #define	BITS6	01
43*13Sbill #define	BITS7	02
44*13Sbill #define	BITS8	03
45*13Sbill #define	TWOSB	04
46*13Sbill #define	PENABLE	020
47*13Sbill /* DEC manuals incorrectly say this bit causes generation of even parity. */
48*13Sbill #define	OPAR	040
49*13Sbill #define	HDUPLX	040000
50*13Sbill 
51*13Sbill #define	IENAB	030100
52*13Sbill #define	PERROR	010000
53*13Sbill #define	FRERROR	020000
54*13Sbill #define	OVERRUN	040000
55*13Sbill #define	XINT	0100000
56*13Sbill #define	SSPEED	7	/* standard speed: 300 baud */
57*13Sbill 
58*13Sbill #ifdef ERNIE
59*13Sbill #define	DHTIME	2		/* Since Berknet packets are only 100 chars */
60*13Sbill #else
61*13Sbill #define	DHTIME	6
62*13Sbill #endif
63*13Sbill extern int dhtimer();
64*13Sbill 
65*13Sbill /*
66*13Sbill  * DM control bits
67*13Sbill  */
68*13Sbill #define	TURNON	03	/* CD lead + line enable */
69*13Sbill #define	TURNOFF	01	/* line enable */
70*13Sbill #define	RQS	04	/* request to send */
71*13Sbill 
72*13Sbill /*
73*13Sbill  * Software copy of last dhbar
74*13Sbill  */
75*13Sbill short	dhsar[(NDH11+15)/16];
76*13Sbill 
77*13Sbill struct device
78*13Sbill {
79*13Sbill 	union {
80*13Sbill 		short	dhcsr;
81*13Sbill 		char	dhcsrl;
82*13Sbill 	} un;
83*13Sbill 	short	dhnxch;
84*13Sbill 	short	dhlpr;
85*13Sbill 	unsigned short	dhcar;
86*13Sbill 	short	dhbcr;
87*13Sbill 	unsigned short	dhbar;
88*13Sbill 	short	dhbreak;
89*13Sbill 	short	dhsilo;
90*13Sbill };
91*13Sbill 
92*13Sbill /*
93*13Sbill  * Open a DH11 line.
94*13Sbill  */
95*13Sbill /*ARGSUSED*/
96*13Sbill dhopen(dev, flag)
97*13Sbill {
98*13Sbill 	register struct tty *tp;
99*13Sbill 	register d;
100*13Sbill 	register struct device *addr;
101*13Sbill 	static	timer_on;
102*13Sbill 	int s;
103*13Sbill 
104*13Sbill 	d = minor(dev) & 0177;
105*13Sbill 	if (d >= NDH11) {
106*13Sbill 		u.u_error = ENXIO;
107*13Sbill 		return;
108*13Sbill 	}
109*13Sbill 	tp = &dh11[d];
110*13Sbill 	addr = DHADDR;
111*13Sbill 	addr += d>>4;
112*13Sbill 	tp->t_addr = (caddr_t)addr;
113*13Sbill 	tp->t_oproc = dhstart;
114*13Sbill 	tp->t_iproc = NULL;
115*13Sbill 	tp->t_state |= WOPEN;
116*13Sbill 	s = spl6();
117*13Sbill 	if (!timer_on) {
118*13Sbill 		timer_on++;
119*13Sbill 		timeout(dhtimer, (caddr_t)0, DHTIME);
120*13Sbill 		cbase = (short)uballoc((caddr_t)cfree, NCLIST*sizeof(struct cblock), 0);
121*13Sbill 	}
122*13Sbill 	splx(s);
123*13Sbill 	addr->un.dhcsr |= IENAB;
124*13Sbill 	if ((tp->t_state&ISOPEN) == 0) {
125*13Sbill 		ttychars(tp);
126*13Sbill 		tp->t_ispeed = SSPEED;
127*13Sbill 		tp->t_ospeed = SSPEED;
128*13Sbill 		tp->t_flags = ODDP|EVENP|ECHO;
129*13Sbill 		dhparam(d);
130*13Sbill 	}
131*13Sbill 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
132*13Sbill 		u.u_error = EBUSY;
133*13Sbill 		return;
134*13Sbill 	}
135*13Sbill 	dmopen(dev);
136*13Sbill 	(*linesw[tp->t_line].l_open)(dev,tp);
137*13Sbill }
138*13Sbill 
139*13Sbill /*
140*13Sbill  * Close a DH11 line.
141*13Sbill  */
142*13Sbill /*ARGSUSED*/
143*13Sbill dhclose(dev, flag)
144*13Sbill dev_t dev;
145*13Sbill int  flag;
146*13Sbill {
147*13Sbill 	register struct tty *tp;
148*13Sbill 	register d;
149*13Sbill 
150*13Sbill 	d = minor(dev) & 0177;
151*13Sbill 	tp = &dh11[d];
152*13Sbill 	(*linesw[tp->t_line].l_close)(tp);
153*13Sbill 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
154*13Sbill 		dmctl(d, TURNOFF);
155*13Sbill 	ttyclose(tp);
156*13Sbill }
157*13Sbill 
158*13Sbill /*
159*13Sbill  * Read from a DH11 line.
160*13Sbill  */
161*13Sbill dhread(dev)
162*13Sbill {
163*13Sbill register struct tty *tp;
164*13Sbill 
165*13Sbill 	tp = &dh11[minor(dev) & 0177];
166*13Sbill 	(*linesw[tp->t_line].l_read)(tp);
167*13Sbill }
168*13Sbill 
169*13Sbill /*
170*13Sbill  * write on a DH11 line
171*13Sbill  */
172*13Sbill dhwrite(dev)
173*13Sbill {
174*13Sbill register struct tty *tp;
175*13Sbill 
176*13Sbill 	tp = &dh11[minor(dev) & 0177];
177*13Sbill 	(*linesw[tp->t_line].l_write)(tp);
178*13Sbill }
179*13Sbill 
180*13Sbill /*
181*13Sbill  * DH11 receiver interrupt.
182*13Sbill  */
183*13Sbill dhrint(dev)
184*13Sbill {
185*13Sbill 	register struct tty *tp;
186*13Sbill 	register short c;
187*13Sbill 	register struct device *addr;
188*13Sbill 
189*13Sbill 	addr = DHADDR;
190*13Sbill 	addr += minor(dev) & 0177;
191*13Sbill 	while ((c = addr->dhnxch) < 0) {	/* char. present */
192*13Sbill 		tp = &dh11[((minor(dev)&0177)<<4) + ((c>>8)&017)];
193*13Sbill 		dhchars[minor(dev)&0177]++;
194*13Sbill 		if (tp >= &dh11[NDH11])
195*13Sbill 			continue;
196*13Sbill 		if((tp->t_state&ISOPEN)==0) {
197*13Sbill 			wakeup((caddr_t)tp);
198*13Sbill 			continue;
199*13Sbill 		}
200*13Sbill 		if (c&PERROR)
201*13Sbill 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
202*13Sbill 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
203*13Sbill 				continue;
204*13Sbill 		if (c&OVERRUN)
205*13Sbill 			printf("O");
206*13Sbill 		if (c&FRERROR)		/* break */
207*13Sbill 			if (tp->t_flags&RAW)
208*13Sbill 				c = 0;	/* null (for getty) */
209*13Sbill 			else
210*13Sbill 				c = 0177;	/* DEL (intr) */
211*13Sbill 		(*linesw[tp->t_line].l_rint)(c,tp);
212*13Sbill 	}
213*13Sbill }
214*13Sbill 
215*13Sbill /*
216*13Sbill  * stty/gtty for DH11
217*13Sbill  */
218*13Sbill /*ARGSUSED*/
219*13Sbill dhioctl(dev, cmd, addr, flag)
220*13Sbill caddr_t addr;
221*13Sbill {
222*13Sbill 	register struct tty *tp;
223*13Sbill 
224*13Sbill 	tp = &dh11[minor(dev) & 0177];
225*13Sbill 	if (ttioccomm(cmd, tp, addr, dev)) {
226*13Sbill 		if (cmd==TIOCSETP||cmd==TIOCSETN)
227*13Sbill 			dhparam(dev);
228*13Sbill 	} else if (cmd==TIOCSBRK) {
229*13Sbill 		/* send a break */
230*13Sbill 		register int linebit = 1 << (dev&017);
231*13Sbill 		extern dhunbrk();
232*13Sbill 
233*13Sbill 		wflushtty(tp);
234*13Sbill 		spl5();
235*13Sbill 		((struct device *)tp->t_addr)->dhbreak |= linebit;
236*13Sbill 		tp->t_state |= TIMEOUT;
237*13Sbill 		timeout(dhunbrk, (caddr_t)tp, 25);	/* 300-500 ms */
238*13Sbill 		while (((struct device *)tp->t_addr)->dhbreak & linebit)
239*13Sbill 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
240*13Sbill 		tp->t_state &= ~TIMEOUT;
241*13Sbill 		spl0();
242*13Sbill 		flushtty(tp);
243*13Sbill 		return;
244*13Sbill 	} else
245*13Sbill 		u.u_error = ENOTTY;
246*13Sbill }
247*13Sbill 
248*13Sbill dhunbrk(tp)
249*13Sbill register struct tty *tp;
250*13Sbill {
251*13Sbill 
252*13Sbill 	((struct device *)tp->t_addr)->dhbreak &= ~ (1 << (minor(tp->t_dev)&017));
253*13Sbill 	wakeup((caddr_t)&tp->t_rawq);
254*13Sbill }
255*13Sbill 
256*13Sbill /*
257*13Sbill  * Set parameters from open or stty into the DH hardware
258*13Sbill  * registers.
259*13Sbill  */
260*13Sbill dhparam(dev)
261*13Sbill {
262*13Sbill 	register struct tty *tp;
263*13Sbill 	register struct device *addr;
264*13Sbill 	register d;
265*13Sbill 
266*13Sbill 	d = minor(dev) & 0177;
267*13Sbill 	tp = &dh11[d];
268*13Sbill 	addr = (struct device *)tp->t_addr;
269*13Sbill 	spl5();
270*13Sbill 	addr->un.dhcsrl = (d&017) | IENAB;
271*13Sbill 	/*
272*13Sbill 	 * Hang up line?
273*13Sbill 	 */
274*13Sbill 	if ((tp->t_ispeed)==0) {
275*13Sbill 		tp->t_state |= HUPCLS;
276*13Sbill 		dmctl(d, TURNOFF);
277*13Sbill 		return;
278*13Sbill 	}
279*13Sbill 	d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
280*13Sbill 	if ((tp->t_ispeed) == 4)		/* 134.5 baud */
281*13Sbill 		d |= BITS6|PENABLE|HDUPLX;
282*13Sbill 	else if (tp->t_flags&RAW)
283*13Sbill 		d |= BITS8;
284*13Sbill 	else
285*13Sbill 		d |= BITS7|PENABLE;
286*13Sbill 	if ((tp->t_flags&EVENP) == 0)
287*13Sbill 		d |= OPAR;
288*13Sbill 	if ((tp->t_ospeed) == 3)	/* 110 baud */
289*13Sbill 		d |= TWOSB;
290*13Sbill 	addr->dhlpr = d;
291*13Sbill 	spl0();
292*13Sbill }
293*13Sbill 
294*13Sbill /*
295*13Sbill  * DH11 transmitter interrupt.
296*13Sbill  * Restart each line which used to be active but has
297*13Sbill  * terminated transmission since the last interrupt.
298*13Sbill  */
299*13Sbill dhxint(dev)
300*13Sbill {
301*13Sbill 	register struct tty *tp;
302*13Sbill 	register struct device *addr;
303*13Sbill 	register d;
304*13Sbill 	short ttybit, bar, *sbar;
305*13Sbill 
306*13Sbill 	d = minor(dev) & 0177;
307*13Sbill 	addr = DHADDR + d;
308*13Sbill 	addr->un.dhcsr &= (short)~XINT;
309*13Sbill 	sbar = &dhsar[d];
310*13Sbill 	bar = *sbar & ~addr->dhbar;
311*13Sbill 	d <<= 4; ttybit = 1;
312*13Sbill 
313*13Sbill 	for(; bar; d++, ttybit <<= 1) {
314*13Sbill 		if(bar&ttybit) {
315*13Sbill 			*sbar &= ~ttybit;
316*13Sbill 			bar &= ~ttybit;
317*13Sbill 			tp = &dh11[d];
318*13Sbill 			if (tp->t_line) {
319*13Sbill 				(*linesw[tp->t_line].l_start)(tp);
320*13Sbill 			} else {
321*13Sbill 				addr->un.dhcsrl = (d&017)|IENAB;
322*13Sbill 				if (tp->t_state&FLUSH)
323*13Sbill 					tp->t_state &= ~FLUSH;
324*13Sbill 				else {
325*13Sbill 					ndflush(&q3, dhcc[d]);
326*13Sbill 				}
327*13Sbill 				tp->t_state &= ~BUSY;
328*13Sbill 				dhstart(tp);
329*13Sbill 			}
330*13Sbill 		}
331*13Sbill 	}
332*13Sbill }
333*13Sbill 
334*13Sbill /*
335*13Sbill  * Start (restart) transmission on the given DH11 line.
336*13Sbill  */
337*13Sbill dhstart(tp)
338*13Sbill register struct tty *tp;
339*13Sbill {
340*13Sbill 	register struct device *addr;
341*13Sbill 	register short nch;
342*13Sbill 	int s, d;
343*13Sbill 
344*13Sbill 	/*
345*13Sbill 	 * If it's currently active, or delaying,
346*13Sbill 	 * no need to do anything.
347*13Sbill 	 */
348*13Sbill 	s = spl5();
349*13Sbill 	d = tp-dh11;
350*13Sbill 	addr = (struct device *)tp->t_addr;
351*13Sbill 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
352*13Sbill 		goto out;
353*13Sbill 
354*13Sbill 
355*13Sbill 	/*
356*13Sbill 	 * If the writer was sleeping on output overflow,
357*13Sbill 	 * wake him when low tide is reached.
358*13Sbill 	 */
359*13Sbill 	if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT) {
360*13Sbill 		tp->t_state &= ~ASLEEP;
361*13Sbill 		if (tp->t_chan)
362*13Sbill 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq); else
363*13Sbill 			wakeup((caddr_t)&tp->t_outq);
364*13Sbill 	}
365*13Sbill 
366*13Sbill 	if (tp->t_outq.c_cc == 0)
367*13Sbill 		goto out;
368*13Sbill 
369*13Sbill 
370*13Sbill 
371*13Sbill 	/*
372*13Sbill 	 * Find number of characters to transfer.
373*13Sbill 	 */
374*13Sbill 	if (tp->t_flags & RAW) {
375*13Sbill 		nch = ndqb(&tp->t_outq, 0);
376*13Sbill 	} else {
377*13Sbill 		nch = ndqb(&tp->t_outq, 0200);
378*13Sbill 		if (nch == 0) {
379*13Sbill 			nch = getc(&tp->t_outq);
380*13Sbill 			timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
381*13Sbill 			tp->t_state |= TIMEOUT;
382*13Sbill 			goto out;
383*13Sbill 		}
384*13Sbill 	}
385*13Sbill 	/*
386*13Sbill 	 * If any characters were set up, start transmission;
387*13Sbill 	 */
388*13Sbill 	if (nch) {
389*13Sbill 		addr->un.dhcsrl = (d&017)|IENAB;
390*13Sbill 		addr->dhcar = UBACVT(tp->t_outq.c_cf);
391*13Sbill 		addr->dhbcr = -nch;
392*13Sbill 		dhcc[d] = nch;
393*13Sbill 		nch = 1<<(d&017);
394*13Sbill 		addr->dhbar |= nch;
395*13Sbill 		dhsar[d>>4] |= nch;
396*13Sbill 		tp->t_state |= BUSY;
397*13Sbill 	}
398*13Sbill     out:
399*13Sbill 	splx(s);
400*13Sbill }
401*13Sbill 
402*13Sbill 
403*13Sbill /*
404*13Sbill  * Stop output on a line.
405*13Sbill  * Assume call is made at spl6.
406*13Sbill  */
407*13Sbill /*ARGSUSED*/
408*13Sbill dhstop(tp, flag)
409*13Sbill register struct tty *tp;
410*13Sbill {
411*13Sbill 	register s;
412*13Sbill 
413*13Sbill 	s = spl6();
414*13Sbill 	if (tp->t_state & BUSY)
415*13Sbill 		if ((tp->t_state&TTSTOP)==0)
416*13Sbill 			tp->t_state |= FLUSH;
417*13Sbill 	splx(s);
418*13Sbill }
419*13Sbill 
420*13Sbill /*ARGSUSED*/
421*13Sbill dhtimer(dev)
422*13Sbill {
423*13Sbill register d,cc;
424*13Sbill register struct device *addr;
425*13Sbill 	addr = DHADDR; d = 0;
426*13Sbill 	do {
427*13Sbill 		cc = dhchars[d];
428*13Sbill 		dhchars[d] = 0;
429*13Sbill 		if (cc > 8*DHTIME)
430*13Sbill 			cc = 32; else
431*13Sbill 			if (cc > 3*DHTIME)
432*13Sbill 				cc = 16; else
433*13Sbill 				cc = 0;
434*13Sbill 		addr->dhsilo = cc;
435*13Sbill 		addr++;
436*13Sbill 		dhrint(d++);
437*13Sbill 	} while (d < (NDH11+15)/16);
438*13Sbill 	timeout(dhtimer, (caddr_t)0, DHTIME);
439*13Sbill }
440