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