xref: /original-bsd/sys/vax/uba/dmx.c (revision 53e63aa2)
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.2 (Berkeley) 04/12/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 			break;
138 	}
139 	splx(s);
140 	if (error)
141 		return (error);
142 	return ((*linesw[tp->t_line].l_open)(tp->t_dev, tp));
143 }
144 
145 dmxclose(tp)
146 	register struct tty *tp;
147 {
148 
149 	(*linesw[tp->t_line].l_close)(tp);
150 	(void) dmxmctl(tp, DMF_BRK, DMBIC);
151 	if (tp->t_cflag & HUPCL || (tp->t_state & TS_ISOPEN) == 0)
152 		(void) dmxmctl(tp, DMF_OFF, DMSET);
153 	return (ttyclose(tp));
154 }
155 
156 dmxrint(sc)
157 	register struct dmx_softc *sc;
158 {
159 	register c, cc;
160 	register struct tty *tp;
161 	register struct dmx_octet *addr;
162 	int unit;
163 	int overrun = 0;
164 
165 	addr = (struct dmx_octet *)sc->dmx_octet;
166 	/*
167 	 * Loop fetching characters from the silo for this
168 	 * octet until there are no more in the silo.
169 	 */
170 	while ((c = addr->rbuf) < 0) {
171 		cc = c&0xff;
172 		unit = (c >> 8) & 07;
173 		tp = sc->dmx_tty + unit;
174 		if (c & DMF_DSC) {
175 			addr->csr = DMF_IE | DMFIR_RMSTSC | unit;
176 			if (addr->rmstsc & DMF_CAR)
177 				(void)(*linesw[tp->t_line].l_modem)(tp, 1);
178 			else if ((sc->dmx_softCAR & (1 << unit)) == 0 &&
179 			    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
180 				addr->csr = DMF_IE | DMFIR_LCR | unit;
181 				addr->lctms = DMF_ENA;
182 			}
183 			continue;
184 		}
185 		if ((tp->t_state&TS_ISOPEN) == 0) {
186 			wakeup((caddr_t)&tp->t_rawq);
187 #ifdef PORTSELECTOR
188 			if ((tp->t_state & TS_WOPEN) == 0)
189 #endif
190 				continue;
191 		}
192 		if (c & (DMF_PE|DMF_DO|DMF_FE)) {
193 			if (c & DMF_PE)
194 				cc |= TTY_PE;
195 			if ((c & DMF_DO) && overrun == 0) {
196 				log(LOG_WARNING,
197 				    "dm%c%d: silo overflow, line %d\n",
198 				    sc->dmx_type, sc->dmx_unit,
199 				    sc->dmx_unit0 + unit);
200 				overrun = 1;
201 			}
202 			if (c & DMF_FE)
203 				cc |= TTY_FE;
204 		}
205 		(*linesw[tp->t_line].l_rint)(cc, tp);
206 	}
207 }
208 
209 dmxioctl(tp, cmd, data, flag)
210 	register struct tty *tp;
211 	caddr_t data;
212 {
213 	int error;
214 
215 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
216 	if (error >= 0)
217 		return (error);
218 	error = ttioctl(tp, cmd, data, flag);
219 	if (error >= 0)
220 		return (error);
221 
222 	switch (cmd) {
223 
224 	case TIOCSBRK:
225 		(void) dmxmctl(tp, DMF_BRK, DMBIS);
226 		break;
227 
228 	case TIOCCBRK:
229 		(void) dmxmctl(tp, DMF_BRK, DMBIC);
230 		break;
231 
232 	case TIOCSDTR:
233 		(void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIS);
234 		break;
235 
236 	case TIOCCDTR:
237 		(void) dmxmctl(tp, DMF_DTR|DMF_RTS, DMBIC);
238 		break;
239 
240 	case TIOCMSET:
241 		(void) dmxmctl(tp, dmtodmx(*(int *)data), DMSET);
242 		break;
243 
244 	case TIOCMBIS:
245 		(void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIS);
246 		break;
247 
248 	case TIOCMBIC:
249 		(void) dmxmctl(tp, dmtodmx(*(int *)data), DMBIC);
250 		break;
251 
252 	case TIOCMGET:
253 		*(int *)data = dmxmctl(tp, 0, DMGET);
254 		break;
255 
256 	default:
257 		return (ENOTTY);
258 	}
259 	return (0);
260 }
261 
262 /*
263  * modem control
264  * "bits" are dmf/dmz lcr format;
265  * return of DMGET is DM11 format.
266  */
267 dmxmctl(tp, bits, how)
268 	struct tty *tp;
269 	int bits, how;
270 {
271 	register struct dmx_octet *addr;
272 	register int unit, mbits, lcr;
273 	int s;
274 
275 	unit = minor(tp->t_dev) & 07;
276 	addr = (struct dmx_octet *)(tp->t_addr);
277 
278 	s = spltty();
279 	addr->csr = DMF_IE | DMFIR_RMSTSC | unit;
280 	mbits = addr->rmstsc & 0xff00;
281 	addr->csr = DMF_IE | DMFIR_LCR | unit;
282 	lcr = addr->lctms;
283 
284 	switch (how) {
285 	case DMSET:
286 		lcr = bits;
287 		break;
288 
289 	case DMBIS:
290 		lcr |= bits;
291 		break;
292 
293 	case DMBIC:
294 		lcr &= ~bits;
295 		break;
296 
297 	case DMGET:
298 		splx(s);
299 		return (dmxtodm(mbits, lcr));
300 	}
301 	addr->lctms = lcr;
302 	(void) splx(s);
303 	return (mbits);
304 }
305 
306 /*
307  * Routine to convert modem status from dm to dmf/dmz lctmr format.
308  */
309 dmtodmx(bits)
310 	register int bits;
311 {
312 	register int lcr = DMF_ENA;
313 
314 	if (bits & DML_DTR)
315 		lcr |= DMF_DTR;
316 	if (bits & DML_RTS)
317 		lcr |= DMF_RTS;
318 	if (bits & DML_ST)
319 		lcr |= DMF_SRTS;
320 	if (bits & DML_USR)
321 		lcr |= DMF_USRW;
322 	return (lcr);
323 }
324 
325 /*
326  * Routine to convert modem status from dmf/dmz receive modem status
327  * and line control register to dm format.
328  * If dmf/dmz user modem read bit set, set DML_USR.
329  */
330 dmxtodm(mstat, lcr)
331 	register int mstat, lcr;
332 {
333 
334 	mstat = ((mstat & (DMF_DSR|DMF_RNG|DMF_CAR|DMF_CTS|DMF_SR)) >> 7) |
335 		((mstat & DMF_USRR) >> 1) | DML_LE;
336 	if (lcr & DMF_DTR)
337 		mstat |= DML_DTR;
338 	if (lcr & DMF_SRTS)
339 		mstat |= DML_ST;
340 	if (lcr & DMF_RTS)
341 		mstat |= DML_RTS;
342 	return (mstat);
343 }
344 
345 
346 /*
347  * Set parameters from open or ioctl into the hardware registers.
348  */
349 dmxparam(tp, t)
350 	register struct tty *tp;
351 	register struct termios *t;
352 {
353 	register struct dmx_octet *addr;
354 	register int lpar, lcr;
355 	register int cflag = t->c_cflag;
356 	int s, unit;
357 	int ispeed = ttspeedtab(t->c_ispeed, dmxspeedtab);
358         int ospeed = ttspeedtab(t->c_ospeed, dmxspeedtab);
359 
360         /* check requested parameters */
361         if (ospeed < 0 || ispeed < 0 || (cflag&CSIZE) == CS5)
362                 return(EINVAL);
363         if (ispeed == 0)
364                 ispeed = ospeed;
365         /* and copy to tty */
366         tp->t_ispeed = t->c_ispeed;
367         tp->t_ospeed = t->c_ospeed;
368         tp->t_cflag = cflag;
369 
370 	addr = (struct dmx_octet *)tp->t_addr;
371 	unit = minor(tp->t_dev) & 07;
372 	/*
373 	 * Block interrupts so parameters will be set
374 	 * before the line interrupts.
375 	 */
376 	s = spltty();
377 	addr->csr = unit | DMFIR_LCR | DMF_IE;
378 	if (ospeed == 0) {
379 		tp->t_cflag |= HUPCL;
380 		(void) dmxmctl(tp, DMF_OFF, DMSET);
381 		splx(s);
382 		return;
383 	}
384 	lpar = (ospeed<<12) | (ispeed<<8);
385 	lcr = DMF_ENA;
386 	switch (cflag&CSIZE) {
387         case CS6:       lpar |= BITS6; break;
388         case CS7:       lpar |= BITS7; break;
389         case CS8:       lpar |= BITS8; break;
390         }
391         if (cflag&PARENB)
392                 lpar |= PENABLE;
393         if (!(cflag&PARODD))
394                 lpar |= EPAR;
395         if (cflag&CSTOPB)
396                 lpar |= TWOSB;
397 
398 	lpar |= (unit&07);
399 	addr->lpr = lpar;
400 	addr->lctms = (addr->lctms &~ 0xff) | lcr;
401 	splx(s);
402 	return 0;
403 }
404 
405 /*
406  * Process a transmit interrupt on an octet.
407  */
408 dmxxint(sc)
409 	register struct dmx_softc *sc;
410 {
411 	register struct tty *tp;
412 	register struct dmx_octet *addr;
413 	register int t;
414 
415 	addr = (struct dmx_octet *)sc->dmx_octet;
416 	while ((t = addr->csr) & DMF_TI) {
417 		if (t & DMF_NXM)
418 			/* SHOULD RESTART OR SOMETHING... */
419 			printf("dm%c%d: NXM line %d\n", sc->dmx_type,
420 			    sc->dmx_unit, sc->dmx_unit0 + (t >> 8 & 7));
421 		t = t >> 8 & 7;
422 		tp = sc->dmx_tty + t;
423 		tp->t_state &= ~TS_BUSY;
424 		if (tp->t_state & TS_FLUSH)
425 			tp->t_state &= ~TS_FLUSH;
426 #define new
427 #ifndef new
428 		else if (sc->dmx_dmacount[t]) {
429 			short cntr;
430 
431 			/*
432 			 * Do arithmetic in a short to make up
433 			 * for lost 16&17 bits.
434 			 */
435 			addr->csr = DMFIR_TBA | DMF_IE | t;
436 			cntr = addr->tba -
437 			    UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum);
438 			ndflush(&tp->t_outq, (int)cntr);
439 		}
440 #else
441 		else if (sc->dmx_dmacount[t])
442 			ndflush(&tp->t_outq, sc->dmx_dmacount[t]);
443 		sc->dmx_dmacount[t] = 0;
444 #endif
445 		(*linesw[tp->t_line].l_start)(tp);
446 	}
447 }
448 
449 dmxstart(tp, sc)
450 	register struct tty *tp;
451 	struct dmx_softc *sc;
452 {
453 	register struct dmx_octet *addr;
454 	register int unit, nch;
455 	int s;
456 
457 	unit = minor(tp->t_dev) & 07;
458 	addr = (struct dmx_octet *)tp->t_addr;
459 
460 	/*
461 	 * Must hold interrupts in following code to prevent
462 	 * state of the tp from changing.
463 	 */
464 	s = spltty();
465 	/*
466 	 * If it's currently active, or delaying, no need to do anything.
467 	 */
468 	if (tp->t_state&(TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
469 		goto out;
470 	/*
471 	 * If there are still characters to dma or in the silo,
472 	 * just reenable the transmitter.
473 	 */
474 	addr->csr = DMF_IE | DMFIR_TBUF | unit;
475 #ifdef new
476 	if (addr->tsc || sc->dmx_dmacount[unit]) {
477 #else
478 	if (addr->tsc) {
479 #endif
480 		addr->csr = DMF_IE | DMFIR_LCR | unit;
481 		addr->lctms = addr->lctms | DMF_TE;
482 		tp->t_state |= TS_BUSY;
483 		goto out;
484 	}
485 	/*
486 	 * If there are sleepers, and output has drained below low
487 	 * water mark, wake up the sleepers.
488 	 */
489 	if (tp->t_outq.c_cc <= tp->t_lowat) {
490 		if (tp->t_state & TS_ASLEEP) {
491 			tp->t_state &= ~TS_ASLEEP;
492 			wakeup((caddr_t)&tp->t_outq);
493 		}
494 		if (tp->t_wsel) {
495 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
496 			tp->t_wsel = 0;
497 			tp->t_state &= ~TS_WCOLL;
498 		}
499 	}
500 	/*
501 	 * Now restart transmission unless the output queue is
502 	 * empty.
503 	 */
504 	if (tp->t_outq.c_cc == 0)
505 		goto out;
506 	if (1 || !(tp->t_oflag&OPOST))	/*XXX*/
507 		nch = ndqb(&tp->t_outq, 0);
508 	else {
509 		if ((nch = ndqb(&tp->t_outq, 0200)) == 0) {
510 			/*
511 		 	* If first thing on queue is a delay process it.
512 		 	*/
513 			nch = getc(&tp->t_outq);
514 			timeout(ttrstrt, (caddr_t)tp, (nch&0x7f)+6);
515 			tp->t_state |= TS_TIMEOUT;
516 			goto out;
517 		}
518 	}
519 	/*
520 	 * If characters to transmit, restart transmission.
521 	 */
522 	if (nch >= dmx_mindma) {
523 		register car;
524 
525 		sc->dmx_dmacount[unit] = nch;
526 		addr->csr = DMF_IE | DMFIR_LCR | unit;
527 		addr->lctms = addr->lctms | DMF_TE;
528 		car = UBACVT(tp->t_outq.c_cf, sc->dmx_ubanum);
529 		addr->csr = DMF_IE | DMFIR_TBA | unit;
530 		addr->tba = car;
531 		addr->tcc = ((car >> 2) & 0xc000) | nch;
532 		tp->t_state |= TS_BUSY;
533 	} else if (nch) {
534 		register char *cp = tp->t_outq.c_cf;
535 		register int i;
536 
537 #ifndef new
538 		sc->dmx_dmacount[unit] = 0;
539 #endif
540 		nch = MIN(nch, DMF_SILOCNT);
541 		addr->csr = DMF_IE | DMFIR_LCR | unit;
542 		addr->lctms = addr->lctms | DMF_TE;
543 		addr->csr = DMF_IE | DMFIR_TBUF | unit;
544 		for (i = 0; i < nch; i++)
545 			addr->tbuf = *cp++;
546 		ndflush(&tp->t_outq, nch);
547 		tp->t_state |= TS_BUSY;
548 	}
549 out:
550 	splx(s);
551 }
552 
553 dmxstop(tp, sc, flag)
554 	register struct tty *tp;
555 	struct dmx_softc *sc;
556 {
557 	register struct dmx_octet *addr;
558 	register unit = minor(tp->t_dev) & 7;
559 	int s;
560 
561 	addr = (struct dmx_octet *)tp->t_addr;
562 	/*
563 	 * Block input/output interrupts while messing with state.
564 	 */
565 	s = spltty();
566 	if (flag) {
567 		addr->csr = DMF_IE | DMFIR_TBUF | unit;
568 		if (addr->tsc) {
569 			/*
570 			 * Flush regardless of whether we're transmitting
571 			 * (TS_BUSY), if the silo contains untransmitted
572 			 * characters.
573 			 */
574 			addr->csr = DMFIR_LCR | unit | DMF_IE;
575 			addr->lctms = addr->lctms | DMF_TE | DMF_FLUSH;
576 			/* this will interrupt so let dmxxint handle the rest */
577 			tp->t_state |= TS_FLUSH|TS_BUSY;
578 		}
579 /*#ifdef new*/
580 		sc->dmx_dmacount[unit] = 0;
581 /*#endif*/
582 	} else {
583 		/*
584 		 * Stop transmission by disabling
585 		 * the transmitter.  We'll pick up where we
586 		 * left off by reenabling in dmxstart.
587 		 */
588 		addr->csr = DMFIR_LCR | unit | DMF_IE;
589 		addr->lctms = addr->lctms &~ DMF_TE;
590 		/* no interrupt here */
591 		tp->t_state &= ~TS_BUSY;
592 	}
593 	splx(s);
594 }
595 #endif NDMF + NDMZ
596