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