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