xref: /original-bsd/sys/vax/uba/dmx.c (revision 91abda3c)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)dmx.c	7.3 (Berkeley) 06/06/90
7  */
8 
9 /*
10  * Common code for DMF32 and DMZ32 drivers
11  */
12 #include "dmf.h"
13 #include "dmz.h"
14 #if NDMF + NDMZ > 0
15 
16 #include "machine/pte.h"
17 
18 #include "uba.h"
19 #include "param.h"
20 #include "conf.h"
21 #include "user.h"
22 #include "proc.h"
23 #include "ioctl.h"
24 #include "tty.h"
25 #include "map.h"
26 #include "buf.h"
27 #include "vm.h"
28 #include "bkmac.h"
29 #include "clist.h"
30 #include "file.h"
31 #include "uio.h"
32 #include "kernel.h"
33 #include "syslog.h"
34 
35 #include "dmx.h"
36 #include "ubareg.h"
37 #include "ubavar.h"
38 #include "dmxreg.h"
39 #include "dmreg.h"
40 
41 #ifndef	PORTSELECTOR
42 #define	ISPEED	TTYDEF_SPEED
43 #define	LFLAG	TTYDEF_LFLAG
44 #else
45 #define	ISPEED	B4800
46 #define	IFLAGS	(TTYDEF_LFLAG&~ECHO)
47 #endif
48 
49 #ifndef DMX_TIMEOUT
50 #define DMX_TIMEOUT	10
51 #endif
52 int	dmx_timeout = DMX_TIMEOUT;		/* silo timeout, in ms */
53 int	dmx_mindma = 4;			/* don't dma below this point */
54 
55 struct speedtab dmxspeedtab[] = {
56 	0,	0,
57 	75,	1,
58 	110,	2,
59 	134,	3,
60 	150,	4,
61 	300,	5,
62 	600,	6,
63 	1200,	7,
64 	1800,	010,
65 	2400,	012,
66 	4800,	014,
67 	9600,	016,
68 	19200,	017,
69 	EXTA,	017,
70 	-1,	-1
71 };
72 /*
73  * The clist space is mapped by the drivers onto each UNIBUS.
74  * The UBACVT macro converts a clist space address for unibus uban
75  * into an I/O space address for the DMA routine.
76  */
77 int	cbase[NUBA];			/* base address in unibus map */
78 #define	UBACVT(x, uban)		(cbase[uban] + ((x)-(char *)cfree))
79 
80 int	ttrstrt();
81 
82 /*
83  * DMF/DMZ open common code
84  */
85 dmxopen(tp, sc, flag)
86 	register struct tty *tp;
87 	register struct dmx_softc *sc;
88 {
89 	int s, unit, error = 0;
90 	int dmxparam();
91 
92 	s = spltty();
93 	if ((sc->dmx_flags & DMX_ACTIVE) == 0) {
94 		sc->dmx_octet->csr |= DMF_IE;
95 		sc->dmx_flags |= DMX_ACTIVE;
96 		sc->dmx_octet->rsp = dmx_timeout;
97 	}
98 	splx(s);
99 	if (tp->t_state & TS_XCLUDE && u.u_uid != 0)
100 		return (EBUSY);
101 	/*
102 	 * If this is first open, initialize tty state to default.
103 	 */
104 	if ((tp->t_state&TS_ISOPEN) == 0) {
105 		ttychars(tp);
106 #ifndef PORTSELECTOR
107 		if (tp->t_ispeed == 0) {
108 #endif
109 			tp->t_iflag = TTYDEF_IFLAG;
110                         tp->t_oflag = TTYDEF_OFLAG;
111                         tp->t_cflag = TTYDEF_CFLAG;
112                         tp->t_lflag = LFLAG;
113                         tp->t_ispeed = tp->t_ospeed = ISPEED;
114 #ifdef PORTSELECTOR
115 			tp->t_cflag |= HUPCL;
116 #else
117 		}
118 #endif
119 	}
120 	dmxparam(tp, &tp->t_termios);
121 
122 	unit = minor(tp->t_dev) & 07;
123 	/*
124 	 * Wait for carrier, then process line discipline specific open.
125 	 */
126 	s = spltty();
127 	for (;;) {
128 		if ((dmxmctl(tp, DMF_ON, DMSET) & DMF_CAR) ||
129 		    (sc->dmx_softCAR & (1 << unit)))
130 			tp->t_state |= TS_CARR_ON;
131 		if (tp->t_state&TS_CARR_ON || flag&O_NONBLOCK ||
132 		    tp->t_cflag&CLOCAL)
133 			break;
134 		tp->t_state |= TS_WOPEN;
135 		if ((error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
136 				    ttopen, 0)) ||
137 		    (error = ttclosed(tp)))
138 			break;
139 	}
140 	splx(s);
141 	if (error)
142 		return (error);
143 	return ((*linesw[tp->t_line].l_open)(tp->t_dev, tp));
144 }
145 
146 dmxclose(tp)
147 	register struct tty *tp;
148 {
149 
150 	(*linesw[tp->t_line].l_close)(tp);
151 	(void) dmxmctl(tp, DMF_BRK, DMBIC);
152 	if (tp->t_cflag & HUPCL || (tp->t_state & TS_ISOPEN) == 0)
153 		(void) dmxmctl(tp, DMF_OFF, DMSET);
154 	return (ttyclose(tp));
155 }
156 
157 dmxrint(sc)
158 	register struct dmx_softc *sc;
159 {
160 	register c, cc;
161 	register struct tty *tp;
162 	register struct dmx_octet *addr;
163 	int unit;
164 	int overrun = 0;
165 
166 	addr = (struct dmx_octet *)sc->dmx_octet;
167 	/*
168 	 * Loop fetching characters from the silo for this
169 	 * octet until there are no more in the silo.
170 	 */
171 	while ((c = addr->rbuf) < 0) {
172 		cc = c&0xff;
173 		unit = (c >> 8) & 07;
174 		tp = sc->dmx_tty + unit;
175 		if (c & DMF_DSC) {
176 			addr->csr = DMF_IE | DMFIR_RMSTSC | unit;
177 			if (addr->rmstsc & DMF_CAR)
178 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
179 			else if ((sc->dmx_softCAR & (1 << unit)) == 0 &&
180 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
181 				addr->csr = DMF_IE | DMFIR_LCR | unit;
182 				addr->lctms = DMF_ENA;
183 			}
184 			continue;
185 		}
186 		if ((tp->t_state&TS_ISOPEN) == 0) {
187 			wakeup((caddr_t)&tp->t_rawq);
188 #ifdef PORTSELECTOR
189 			if ((tp->t_state & TS_WOPEN) == 0)
190 #endif
191 				continue;
192 		}
193 		if (c & (DMF_PE|DMF_DO|DMF_FE)) {
194 			if (c & DMF_PE)
195 				cc |= TTY_PE;
196 			if ((c & DMF_DO) && overrun == 0) {
197 				log(LOG_WARNING,
198 				    "dm%c%d: silo overflow, line %d\n",
199 				    sc->dmx_type, sc->dmx_unit,
200 				    sc->dmx_unit0 + unit);
201 				overrun = 1;
202 			}
203 			if (c & DMF_FE)
204 				cc |= TTY_FE;
205 		}
206 		(*linesw[tp->t_line].l_rint)(cc, tp);
207 	}
208 }
209 
210 dmxioctl(tp, cmd, data, flag)
211 	register struct tty *tp;
212 	caddr_t data;
213 {
214 	int error;
215 
216 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
217 	if (error >= 0)
218 		return (error);
219 	error = ttioctl(tp, cmd, data, flag);
220 	if (error >= 0)
221 		return (error);
222 
223 	switch (cmd) {
224 
225 	case TIOCSBRK:
226 		(void) dmxmctl(tp, DMF_BRK, DMBIS);
227 		break;
228 
229 	case TIOCCBRK:
230 		(void) dmxmctl(tp, DMF_BRK, DMBIC);
231 		break;
232 
233 	case TIOCSDTR:
234 		(void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIS);
235 		break;
236 
237 	case TIOCCDTR:
238 		(void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIC);
239 		break;
240 
241 	case TIOCMSET:
242 		(void) dmxmctl(tp, dmtodmx(*(int *)data), DMSET);
243 		break;
244 
245 	case TIOCMBIS:
246 		(void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIS);
247 		break;
248 
249 	case TIOCMBIC:
250 		(void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIC);
251 		break;
252 
253 	case TIOCMGET:
254 		*(int *)data = dmxmctl(tp, 0, DMGET);
255 		break;
256 
257 	default:
258 		return (ENOTTY);
259 	}
260 	return (0);
261 }
262 
263 /*
264  * modem control
265  * "bits" are dmf/dmz lcr format;
266  * return of DMGET is DM11 format.
267  */
268 dmxmctl(tp, bits, how)
269 	struct tty *tp;
270 	int bits, how;
271 {
272 	register struct dmx_octet *addr;
273 	register int unit, mbits, lcr;
274 	int s;
275 
276 	unit = minor(tp->t_dev) & 07;
277 	addr = (struct dmx_octet *)(tp->t_addr);
278 
279 	s = spltty();
280 	addr->csr = DMF_IE | DMFIR_RMSTSC | unit;
281 	mbits = addr->rmstsc & 0xff00;
282 	addr->csr = DMF_IE | DMFIR_LCR | unit;
283 	lcr = addr->lctms;
284 
285 	switch (how) {
286 	case DMSET:
287 		lcr = bits;
288 		break;
289 
290 	case DMBIS:
291 		lcr |= bits;
292 		break;
293 
294 	case DMBIC:
295 		lcr &= ~bits;
296 		break;
297 
298 	case DMGET:
299 		splx(s);
300 		return (dmxtodm(mbits, lcr));
301 	}
302 	addr->lctms = lcr;
303 	(void) splx(s);
304 	return (mbits);
305 }
306 
307 /*
308  * Routine to convert modem status from dm to dmf/dmz lctmr format.
309  */
310 dmtodmx(bits)
311 	register int bits;
312 {
313 	register int lcr = DMF_ENA;
314 
315 	if (bits & DML_DTR)
316 		lcr |= DMF_DTR;
317 	if (bits & DML_RTS)
318 		lcr |= DMF_RTS;
319 	if (bits & DML_ST)
320 		lcr |= DMF_SRTS;
321 	if (bits & DML_USR)
322 		lcr |= DMF_USRW;
323 	return (lcr);
324 }
325 
326 /*
327  * Routine to convert modem status from dmf/dmz receive modem status
328  * and line control register to dm format.
329  * If dmf/dmz user modem read bit set, set DML_USR.
330  */
331 dmxtodm(mstat, lcr)
332 	register int mstat, lcr;
333 {
334 
335 	mstat = ((mstat & (DMF_DSR|DMF_RNG|DMF_CAR|DMF_CTS|DMF_SR)) >> 7) |
336 		((mstat & DMF_USRR) >> 1) | DML_LE;
337 	if (lcr & DMF_DTR)
338 		mstat |= DML_DTR;
339 	if (lcr & DMF_SRTS)
340 		mstat |= DML_ST;
341 	if (lcr & DMF_RTS)
342 		mstat |= DML_RTS;
343 	return (mstat);
344 }
345 
346 
347 /*
348  * Set parameters from open or ioctl into the hardware registers.
349  */
350 dmxparam(tp, t)
351 	register struct tty *tp;
352 	register struct termios *t;
353 {
354 	register struct dmx_octet *addr;
355 	register int lpar, lcr;
356 	register int cflag = t->c_cflag;
357 	int s, unit;
358 	int ispeed = ttspeedtab(t->c_ispeed, dmxspeedtab);
359         int ospeed = ttspeedtab(t->c_ospeed, dmxspeedtab);
360 
361         /* check requested parameters */
362         if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5)
363                 return(EINVAL);
364         if (ispeed == 0)
365                 ispeed = ospeed;
366         /* and copy to tty */
367         tp->t_ispeed = t->c_ispeed;
368         tp->t_ospeed = t->c_ospeed;
369         tp->t_cflag = cflag;
370 
371 	addr = (struct dmx_octet *)tp->t_addr;
372 	unit = minor(tp->t_dev) & 07;
373 	/*
374 	 * Block interrupts so parameters will be set
375 	 * before the line interrupts.
376 	 */
377 	s = spltty();
378 	addr->csr = unit | DMFIR_LCR | DMF_IE;
379 	if (ospeed == 0) {
380 		tp->t_cflag |= HUPCL;
381 		(void) dmxmctl(tp, DMF_OFF, DMSET);
382 		splx(s);
383 		return;
384 	}
385 	lpar = (ospeed<<12) | (ispeed<<8);
386 	lcr = DMF_ENA;
387 	switch (cflag&CSIZE) {
388         case CS6:       lpar |= BITS6; break;
389         case CS7:       lpar |= BITS7; break;
390         case CS8:       lpar |= BITS8; break;
391         }
392         if (cflag&PARENB)
393                 lpar |= PENABLE;
394         if (!(cflag&PARODD))
395                 lpar |= EPAR;
396         if (cflag&CSTOPB)
397                 lpar |= TWOSB;
398 
399 	lpar |= (unit&07);
400 	addr->lpr = lpar;
401 	addr->lctms = (addr->lctms &~ 0xff) | lcr;
402 	splx(s);
403 	return 0;
404 }
405 
406 /*
407  * Process a transmit interrupt on an octet.
408  */
409 dmxxint(sc)
410 	register struct dmx_softc *sc;
411 {
412 	register struct tty *tp;
413 	register struct dmx_octet *addr;
414 	register int t;
415 
416 	addr = (struct dmx_octet *)sc->dmx_octet;
417 	while ((t = addr->csr) & DMF_TI) {
418 		if (t & DMF_NXM)
419 			/* SHOULD RESTART OR SOMETHING... */
420 			printf("dm%c%d: NXM line %d\n", sc->dmx_type,
421 			    sc->dmx_unit, sc->dmx_unit0 + (t >> 8 & 7));
422 		t = t >> 8 & 7;
423 		tp = sc->dmx_tty + t;
424 		tp->t_state &= ~TS_BUSY;
425 		if (tp->t_state & TS_FLUSH)
426 			tp->t_state &= ~TS_FLUSH;
427 #define new
428 #ifndef new
429 		else if (sc->dmx_dmacount[t]) {
430 			short cntr;
431 
432 			/*
433 			 * Do arithmetic in a short to make up
434 			 * for lost 16&17 bits.
435 			 */
436 			addr->csr = DMFIR_TBA | DMF_IE | t;
437 			cntr = addr->tba -
438 			    UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum);
439 			ndflush(&tp->t_outq, (int)cntr);
440 		}
441 #else
442 		else if (sc->dmx_dmacount[t])
443 			ndflush(&tp->t_outq, sc->dmx_dmacount[t]);
444 		sc->dmx_dmacount[t] = 0;
445 #endif
446 		(*linesw[tp->t_line].l_start)(tp);
447 	}
448 }
449 
450 dmxstart(tp, sc)
451 	register struct tty *tp;
452 	struct dmx_softc *sc;
453 {
454 	register struct dmx_octet *addr;
455 	register int unit, nch;
456 	int s;
457 
458 	unit = minor(tp->t_dev) & 07;
459 	addr = (struct dmx_octet *)tp->t_addr;
460 
461 	/*
462 	 * Must hold interrupts in following code to prevent
463 	 * state of the tp from changing.
464 	 */
465 	s = spltty();
466 	/*
467 	 * If it's currently active, or delaying, no need to do anything.
468 	 */
469 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
470 		goto out;
471 	/*
472 	 * If there are still characters to dma or in the silo,
473 	 * just reenable the transmitter.
474 	 */
475 	addr->csr = DMF_IE | DMFIR_TBUF | unit;
476 #ifdef new
477 	if (addr->tsc || sc->dmx_dmacount[unit]) {
478 #else
479 	if (addr->tsc) {
480 #endif
481 		addr->csr = DMF_IE | DMFIR_LCR | unit;
482 		addr->lctms = addr->lctms | DMF_TE;
483 		tp->t_state |= TS_BUSY;
484 		goto out;
485 	}
486 	/*
487 	 * If there are sleepers, and output has drained below low
488 	 * water mark, wake up the sleepers.
489 	 */
490 	if (tp->t_outq.c_cc <= tp->t_lowat) {
491 		if (tp->t_state & TS_ASLEEP) {
492 			tp->t_state &= ~TS_ASLEEP;
493 			wakeup((caddr_t)&tp->t_outq);
494 		}
495 		if (tp->t_wsel) {
496 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
497 			tp->t_wsel = 0;
498 			tp->t_state &= ~TS_WCOLL;
499 		}
500 	}
501 	/*
502 	 * Now restart transmission unless the output queue is
503 	 * empty.
504 	 */
505 	if (tp->t_outq.c_cc == 0)
506 		goto out;
507 	if (1 || !(tp->t_oflag&OPOST))	/*XXX*/
508 		nch = ndqb(&tp->t_outq, 0);
509 	else {
510 		if ((nch = ndqb(&tp->t_outq, 0200)) == 0) {
511 			/*
512 		 	* If first thing on queue is a delay process it.
513 		 	*/
514 			nch = getc(&tp->t_outq);
515 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
516 			tp->t_state |= TS_TIMEOUT;
517 			goto out;
518 		}
519 	}
520 	/*
521 	 * If characters to transmit, restart transmission.
522 	 */
523 	if (nch >= dmx_mindma) {
524 		register car;
525 
526 		sc->dmx_dmacount[unit] = nch;
527 		addr->csr = DMF_IE | DMFIR_LCR | unit;
528 		addr->lctms = addr->lctms | DMF_TE;
529 		car = UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum);
530 		addr->csr = DMF_IE | DMFIR_TBA | unit;
531 		addr->tba = car;
532 		addr->tcc = ((car >> 2) & 0xc000) | nch;
533 		tp->t_state |= TS_BUSY;
534 	} else if (nch) {
535 		register char *cp = tp->t_outq.c_cf;
536 		register int i;
537 
538 #ifndef new
539 		sc->dmx_dmacount[unit] = 0;
540 #endif
541 		nch = MIN(nch, DMF_SILOCNT);
542 		addr->csr = DMF_IE | DMFIR_LCR | unit;
543 		addr->lctms = addr->lctms | DMF_TE;
544 		addr->csr = DMF_IE | DMFIR_TBUF | unit;
545 		for (i = 0; i < nch; i++)
546 			addr->tbuf = *cp++;
547 		ndflush(&tp->t_outq, nch);
548 		tp->t_state |= TS_BUSY;
549 	}
550 out:
551 	splx(s);
552 }
553 
554 dmxstop(tp, sc, flag)
555 	register struct tty *tp;
556 	struct dmx_softc *sc;
557 {
558 	register struct dmx_octet *addr;
559 	register unit = minor(tp->t_dev) & 7;
560 	int s;
561 
562 	addr = (struct dmx_octet *)tp->t_addr;
563 	/*
564 	 * Block input/output interrupts while messing with state.
565 	 */
566 	s = spltty();
567 	if (flag) {
568 		addr->csr = DMF_IE | DMFIR_TBUF | unit;
569 		if (addr->tsc) {
570 			/*
571 			 * Flush regardless of whether we're transmitting
572 			 * (TS_BUSY), if the silo contains untransmitted
573 			 * characters.
574 			 */
575 			addr->csr = DMFIR_LCR | unit | DMF_IE;
576 			addr->lctms = addr->lctms | DMF_TE | DMF_FLUSH;
577 			/* this will interrupt so let dmxxint handle the rest */
578 			tp->t_state |= TS_FLUSH|TS_BUSY;
579 		}
580 /*#ifdef new*/
581 		sc->dmx_dmacount[unit] = 0;
582 /*#endif*/
583 	} else {
584 		/*
585 		 * Stop transmission by disabling
586 		 * the transmitter.  We'll pick up where we
587 		 * left off by reenabling in dmxstart.
588 		 */
589 		addr->csr = DMFIR_LCR | unit | DMF_IE;
590 		addr->lctms = addr->lctms &~ DMF_TE;
591 		/* no interrupt here */
592 		tp->t_state &= ~TS_BUSY;
593 	}
594 	splx(s);
595 }
596 #endif NDMF + NDMZ
597