xref: /original-bsd/sys/vax/uba/dh.c (revision d25e1985)
1 /*	dh.c	3.16	09/27/80	*/
2 
3 /*
4  *	DH-11 driver
5  *	This driver calls on the DHDM driver.
6  *	If the DH has no DM11-BB, then the latter will
7  *	be fake. To insure loading of the correct DM code,
8  *	lib2 should have dhdm.o, dh.o and dhfdm.o in that order.
9  */
10 
11 #include "../h/param.h"
12 #include "../h/conf.h"
13 #include "../h/dir.h"
14 #include "../h/user.h"
15 #include "../h/tty.h"
16 #include "../h/map.h"
17 #include "../h/pte.h"
18 #include "../h/uba.h"
19 #include "../h/bk.h"
20 
21 /*
22  * When running dz's using only SAE (silo alarm) on input
23  * it is necessary to call dzrint() at clock interrupt time.
24  * This is unsafe unless spl5()s in tty code are changed to
25  * spl6()s to block clock interrupts.  Note that the dh driver
26  * currently in use works the same way as the dz, even though
27  * we could try to more intelligently manage its silo.
28  * Thus don't take this out if you have no dz's unless you
29  * change clock.c and dhtimer().
30  */
31 #define	spl5	spl6
32 
33 #define	DHADDR	((struct device *)(UBA0_DEV + 0160020))
34 #define	NDH11	32	/* number of lines */
35 #define UBACVT(x) (cbase + (short)((x)-(char *)cfree))
36 
37 struct cblock {
38 	struct cblock *c_next;
39 	char	c_info[CBSIZE];
40 };
41 
42 struct	tty dh11[NDH11];
43 int	dhact;
44 int	dhisilo;
45 int	ndh11	= NDH11;
46 int	dhstart();
47 int	ttrstrt();
48 int	dh_ubinfo;
49 int	cbase;
50 int	getcbase;
51 extern struct cblock cfree[];
52 
53 /*
54  * Hardware control bits
55  */
56 #define	BITS6	01
57 #define	BITS7	02
58 #define	BITS8	03
59 #define	TWOSB	04
60 #define	PENABLE	020
61 /* DEC manuals incorrectly say this bit causes generation of even parity. */
62 #define	OPAR	040
63 #define	HDUPLX	040000
64 
65 #define	IENAB	030100
66 #define	NXM	02000
67 #define	CLRNXM	0400
68 #define	PERROR	010000
69 #define	FRERROR	020000
70 #define	OVERRUN	040000
71 #define	XINT	0100000
72 #define	SSPEED	7	/* standard speed: 300 baud */
73 
74 /*
75  * DM control bits
76  */
77 #define	TURNON	03	/* CD lead + line enable */
78 #define	TURNOFF	01	/* line enable */
79 #define	DTR	02	/* data terminal ready */
80 #define	RQS	04	/* request to send */
81 
82 /*
83  * Software copy of last dhbar
84  */
85 short	dhsar[(NDH11+15)/16];
86 
87 struct device
88 {
89 	union {
90 		short	dhcsr;
91 		char	dhcsrl;
92 	} un;
93 	short	dhnxch;
94 	short	dhlpr;
95 	unsigned short	dhcar;
96 	short	dhbcr;
97 	unsigned short	dhbar;
98 	short	dhbreak;
99 	short	dhsilo;
100 };
101 
102 /*
103  * Open a DH11 line.
104  */
105 /*ARGSUSED*/
106 dhopen(dev, flag)
107 {
108 	register struct tty *tp;
109 	register d;
110 	register struct device *addr;
111 	int s;
112 
113 	d = minor(dev) & 0177;
114 	if (d >= NDH11) {
115 		u.u_error = ENXIO;
116 		return;
117 	}
118 	tp = &dh11[d];
119 	addr = DHADDR;
120 	addr += d>>4;
121 	tp->t_addr = (caddr_t)addr;
122 	tp->t_oproc = dhstart;
123 	tp->t_iproc = NULL;
124 	tp->t_state |= WOPEN;
125 	s = spl6();
126 	if (!getcbase) {
127 		getcbase++;
128 		/* 512+ is a kludge to try to get around a hardware problem */
129 		dh_ubinfo = uballoc((caddr_t)cfree, 512+NCLIST*sizeof(struct cblock), 0);
130 		cbase = (short)dh_ubinfo;
131 	}
132 	splx(s);
133 	addr->un.dhcsr |= IENAB;
134 	dhact |= (1<<(d>>4));
135 	if ((tp->t_state&ISOPEN) == 0) {
136 		ttychars(tp);
137 		if (tp->t_ispeed == 0) {
138 			tp->t_ispeed = SSPEED;
139 			tp->t_ospeed = SSPEED;
140 			tp->t_flags = ODDP|EVENP|ECHO;
141 		}
142 		dhparam(d);
143 	}
144 	if (tp->t_state&XCLUDE && u.u_uid!=0) {
145 		u.u_error = EBUSY;
146 		return;
147 	}
148 	dmopen(dev);
149 	(*linesw[tp->t_line].l_open)(dev,tp);
150 }
151 
152 /*
153  * Close a DH11 line.
154  */
155 /*ARGSUSED*/
156 dhclose(dev, flag)
157 dev_t dev;
158 int  flag;
159 {
160 	register struct tty *tp;
161 	register d;
162 
163 	d = minor(dev) & 0177;
164 	tp = &dh11[d];
165 	(*linesw[tp->t_line].l_close)(tp);
166 	if (tp->t_state&HUPCLS || (tp->t_state&ISOPEN)==0)
167 		dmctl(d, TURNOFF, DMSET);
168 	ttyclose(tp);
169 }
170 
171 /*
172  * Read from a DH11 line.
173  */
174 dhread(dev)
175 {
176 register struct tty *tp;
177 
178 	tp = &dh11[minor(dev) & 0177];
179 	(*linesw[tp->t_line].l_read)(tp);
180 }
181 
182 /*
183  * write on a DH11 line
184  */
185 dhwrite(dev)
186 {
187 register struct tty *tp;
188 
189 	tp = &dh11[minor(dev) & 0177];
190 	(*linesw[tp->t_line].l_write)(tp);
191 }
192 
193 /*
194  * DH11 receiver interrupt.
195  */
196 dhrint(dev)
197 {
198 	register struct tty *tp;
199 	register short c;
200 	register struct device *addr;
201 	register struct tty *tp0;
202 	int s;
203 
204 	s = spl6();	/* see comment in clock.c */
205 	addr = DHADDR;
206 	addr += minor(dev) & 0177;
207 	tp0 = &dh11[((minor(dev)&0177)<<4)];
208 	while ((c = addr->dhnxch) < 0) {	/* char. present */
209 		tp = tp0 + ((c>>8)&017);
210 		if (tp >= &dh11[NDH11])
211 			continue;
212 		if((tp->t_state&ISOPEN)==0) {
213 			wakeup((caddr_t)tp);
214 			continue;
215 		}
216 		if (c&PERROR)
217 			if ((tp->t_flags&(EVENP|ODDP))==EVENP
218 			 || (tp->t_flags&(EVENP|ODDP))==ODDP )
219 				continue;
220 		if (c&OVERRUN)
221 			printf("O");
222 		if (c&FRERROR)		/* break */
223 			if (tp->t_flags&RAW)
224 				c = 0;	/* null (for getty) */
225 			else
226 #ifdef IIASA
227 				continue;
228 #else
229 				c = tun.t_intrc;
230 #endif
231 		if (tp->t_line == NETLDISC) {
232 			c &= 0177;
233 			BKINPUT(c, tp);
234 		} else
235 			(*linesw[tp->t_line].l_rint)(c,tp);
236 	}
237 	splx(s);
238 }
239 
240 /*
241  * stty/gtty for DH11
242  */
243 /*ARGSUSED*/
244 dhioctl(dev, cmd, addr, flag)
245 caddr_t addr;
246 {
247 	register struct tty *tp;
248 
249 	tp = &dh11[minor(dev) & 0177];
250 	cmd = (*linesw[tp->t_line].l_ioctl)(tp, cmd, addr);
251 	if (cmd==0)
252 		return;
253 	if (ttioctl(cmd, tp, addr, dev, flag)) {
254 		if (cmd==TIOCSETP||cmd==TIOCSETN)
255 			dhparam(dev);
256 	} else switch(cmd) {
257 	case TIOCSBRK:
258 		((struct device *)(tp->t_addr))->dhbreak |= 1<<(minor(dev)&017);
259 		break;
260 	case TIOCCBRK:
261 		((struct device *)(tp->t_addr))->dhbreak &= ~(1<<(minor(dev)&017));
262 		break;
263 	case TIOCSDTR:
264 		dmctl(minor(dev), DTR|RQS, DMBIS);
265 		break;
266 	case TIOCCDTR:
267 		dmctl(minor(dev), DTR|RQS, DMBIC);
268 		break;
269 	default:
270 		u.u_error = ENOTTY;
271 	}
272 }
273 
274 /*
275  * Set parameters from open or stty into the DH hardware
276  * registers.
277  */
278 dhparam(dev)
279 {
280 	register struct tty *tp;
281 	register struct device *addr;
282 	register d;
283 	int s;
284 
285 	d = minor(dev) & 0177;
286 	tp = &dh11[d];
287 	addr = (struct device *)tp->t_addr;
288 	s = spl5();
289 	addr->un.dhcsrl = (d&017) | IENAB;
290 	/*
291 	 * Hang up line?
292 	 */
293 	if ((tp->t_ispeed)==0) {
294 		tp->t_state |= HUPCLS;
295 		dmctl(d, TURNOFF, DMSET);
296 		return;
297 	}
298 	d = ((tp->t_ospeed)<<10) | ((tp->t_ispeed)<<6);
299 	if ((tp->t_ispeed) == 4)		/* 134.5 baud */
300 		d |= BITS6|PENABLE|HDUPLX;
301 	else if (tp->t_flags&RAW)
302 		d |= BITS8;
303 	else
304 		d |= BITS7|PENABLE;
305 	if ((tp->t_flags&EVENP) == 0)
306 		d |= OPAR;
307 	if ((tp->t_ospeed) == 3)	/* 110 baud */
308 		d |= TWOSB;
309 	addr->dhlpr = d;
310 	splx(s);
311 }
312 
313 /*
314  * DH11 transmitter interrupt.
315  * Restart each line which used to be active but has
316  * terminated transmission since the last interrupt.
317  */
318 dhxint(dev)
319 {
320 	register struct tty *tp;
321 	register struct device *addr;
322 	register d;
323 	short ttybit, bar, *sbar;
324 	int s;
325 
326 	s = spl6();	/* block the clock */
327 	d = minor(dev) & 0177;
328 	addr = DHADDR + d;
329 	addr->un.dhcsr &= (short)~XINT;
330 	if (addr->un.dhcsr & NXM) {
331 		addr->un.dhcsr |= CLRNXM;
332 		printf("dh clr NXM\n");
333 	}
334 	sbar = &dhsar[d];
335 	bar = *sbar & ~addr->dhbar;
336 	d <<= 4; ttybit = 1;
337 
338 	for(; bar; d++, ttybit <<= 1) {
339 		if(bar&ttybit) {
340 			*sbar &= ~ttybit;
341 			bar &= ~ttybit;
342 			tp = &dh11[d];
343 			tp->t_state &= ~BUSY;
344 			if (tp->t_state&FLUSH)
345 				tp->t_state &= ~FLUSH;
346 			else {
347 				addr->un.dhcsrl = (d&017)|IENAB;
348 				ndflush(&tp->t_outq,
349 				    (int)addr->dhcar-UBACVT(tp->t_outq.c_cf));
350 			}
351 			if (tp->t_line)
352 				(*linesw[tp->t_line].l_start)(tp);
353 			else
354 				dhstart(tp);
355 		}
356 	}
357 	splx(s);
358 }
359 
360 /*
361  * Start (restart) transmission on the given DH11 line.
362  */
363 dhstart(tp)
364 register struct tty *tp;
365 {
366 	register struct device *addr;
367 	register short nch;
368 	int s, d;
369 
370 	/*
371 	 * If it's currently active, or delaying,
372 	 * no need to do anything.
373 	 */
374 	s = spl5();
375 	d = tp-dh11;
376 	addr = (struct device *)tp->t_addr;
377 	if (tp->t_state&(TIMEOUT|BUSY|TTSTOP))
378 		goto out;
379 
380 	/*
381 	 * If the writer was sleeping on output overflow,
382 	 * wake him when low tide is reached.
383 	 */
384 	if (tp->t_state&ASLEEP && tp->t_outq.c_cc<=TTLOWAT(tp)) {
385 		tp->t_state &= ~ASLEEP;
386 		if (tp->t_chan)
387 			mcstart(tp->t_chan, (caddr_t)&tp->t_outq);
388 		else
389 			wakeup((caddr_t)&tp->t_outq);
390 	}
391 
392 	if (tp->t_outq.c_cc == 0)
393 		goto out;
394 
395 	/*
396 	 * Find number of characters to transfer.
397 	 */
398 	if (tp->t_flags & RAW) {
399 		nch = ndqb(&tp->t_outq, 0);
400 	} else {
401 		nch = ndqb(&tp->t_outq, 0200);
402 		if (nch == 0) {
403 			nch = getc(&tp->t_outq);
404 			timeout(ttrstrt, (caddr_t)tp, (nch&0177)+6);
405 			tp->t_state |= TIMEOUT;
406 			goto out;
407 		}
408 	}
409 	/*
410 	 * If any characters were set up, start transmission;
411 	 */
412 	if (nch) {
413 		addr->un.dhcsrl = (d&017)|IENAB;
414 		addr->dhcar = UBACVT(tp->t_outq.c_cf);
415 		addr->dhbcr = -nch;
416 		nch = 1<<(d&017);
417 		addr->dhbar |= nch;
418 		dhsar[d>>4] |= nch;
419 		tp->t_state |= BUSY;
420 	}
421     out:
422 	splx(s);
423 }
424 
425 /*
426  * Stop output on a line.
427  * Assume call is made at spl6.
428  */
429 /*ARGSUSED*/
430 dhstop(tp, flag)
431 register struct tty *tp;
432 {
433 	register struct device *addr;
434 	register d, s;
435 
436 	addr = (struct device *)tp->t_addr;
437 	s = spl6();
438 	if (tp->t_state & BUSY) {
439 		d = minor(tp->t_dev);
440 		addr->un.dhcsrl = (d&017) | IENAB;
441 		if ((tp->t_state&TTSTOP)==0)
442 			tp->t_state |= FLUSH;
443 		addr->dhbcr = -1;
444 	}
445 	splx(s);
446 }
447 
448 int	dhsilo = 16;
449 /*
450  * Silo control is fixed strategy
451  * here, paralleling only option available
452  * on DZ-11.
453  */
454 /*ARGSUSED*/
455 dhtimer()
456 {
457 	register d;
458 	register struct device *addr;
459 
460 	addr = DHADDR; d = 0;
461 	do {
462 		if (dhact & (1<<d)) {
463 			if ((dhisilo & (1<<d)) == 0) {
464 				addr->dhsilo = dhsilo;
465 				dhisilo |= 1<<d;
466 			}
467 			dhrint(d);
468 		}
469 		d++;
470 		addr++;
471 	} while (d < (NDH11+15)/16);
472 }
473 
474 /*
475  * Reset state of driver if UBA reset was necessary.
476  * Reset the csrl and lpr registers on open lines, and
477  * restart transmitters.
478  */
479 dhreset()
480 {
481 	int d;
482 	register struct tty *tp;
483 	register struct device *addr;
484 
485 	if (getcbase == 0)
486 		return;
487 	printf(" dh");
488 	dhisilo = 0;
489 	ubafree(dh_ubinfo);
490 	dh_ubinfo = uballoc((caddr_t)cfree, NCLIST*sizeof (struct cblock), 0);
491 	cbase = (short)dh_ubinfo;
492 	d = 0;
493 	do {
494 		addr = DHADDR + d;
495 		if (dhact & (1<<d))
496 			addr->un.dhcsr |= IENAB;
497 		d++;
498 	} while (d < (NDH11+15)/16);
499 	for (d = 0; d < NDH11; d++) {
500 		tp = &dh11[d];
501 		if (tp->t_state & (ISOPEN|WOPEN)) {
502 			dhparam(d);
503 			dmctl(d, TURNON, DMSET);
504 			tp->t_state &= ~BUSY;
505 			dhstart(tp);
506 		}
507 	}
508 	dhtimer();
509 }
510