xref: /netbsd-src/sys/dev/dec/dz.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: dz.c,v 1.41 2014/03/16 05:20:27 dholland Exp $	*/
2 /*
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Ralph Campbell and Rick Macklem.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 /*
35  * Copyright (c) 1996  Ken C. Wellsch.  All rights reserved.
36  *
37  * This code is derived from software contributed to Berkeley by
38  * Ralph Campbell and Rick Macklem.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  *    notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  *    notice, this list of conditions and the following disclaimer in the
47  *    documentation and/or other materials provided with the distribution.
48  * 3. All advertising materials mentioning features or use of this software
49  *    must display the following acknowledgement:
50  *	This product includes software developed by the University of
51  *	California, Berkeley and its contributors.
52  * 4. Neither the name of the University nor the names of its contributors
53  *    may be used to endorse or promote products derived from this software
54  *    without specific prior written permission.
55  *
56  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
57  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
58  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
59  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
60  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
61  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
62  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
63  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
64  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
65  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
66  * SUCH DAMAGE.
67  */
68 
69 #include <sys/cdefs.h>
70 __KERNEL_RCSID(0, "$NetBSD: dz.c,v 1.41 2014/03/16 05:20:27 dholland Exp $");
71 
72 #include <sys/param.h>
73 #include <sys/systm.h>
74 #include <sys/callout.h>
75 #include <sys/ioctl.h>
76 #include <sys/tty.h>
77 #include <sys/proc.h>
78 #include <sys/buf.h>
79 #include <sys/conf.h>
80 #include <sys/file.h>
81 #include <sys/uio.h>
82 #include <sys/kernel.h>
83 #include <sys/syslog.h>
84 #include <sys/device.h>
85 #include <sys/kauth.h>
86 
87 #include <sys/bus.h>
88 
89 #include <dev/dec/dzreg.h>
90 #include <dev/dec/dzvar.h>
91 
92 #include <dev/cons.h>
93 
94 #ifdef __mips__
95 #define	DZ_DELAY(x)	DELAY(x)
96 #define control		__noinline
97 #else	/* presumably vax */
98 #define	DZ_DELAY(x)	/* nothing */
99 #define	control		inline
100 #endif
101 
102 static control uint
103 dz_read1(struct dz_softc *sc, u_int off)
104 {
105 	u_int rv;
106 
107 	rv = bus_space_read_1(sc->sc_iot, sc->sc_ioh, off);
108 	DZ_DELAY(1);
109 	return rv;
110 }
111 
112 static control u_int
113 dz_read2(struct dz_softc *sc, u_int off)
114 {
115 	u_int rv;
116 
117 	rv = bus_space_read_2(sc->sc_iot, sc->sc_ioh, off);
118 	DZ_DELAY(1);
119 	return rv;
120 }
121 
122 static control void
123 dz_write1(struct dz_softc *sc, u_int off, u_int val)
124 {
125 
126 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, off, val);
127 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_dr.dr_firstreg,
128 	    sc->sc_dr.dr_winsize, BUS_SPACE_BARRIER_WRITE |
129 	    BUS_SPACE_BARRIER_READ);
130 	DZ_DELAY(10);
131 }
132 
133 static control void
134 dz_write2(struct dz_softc *sc, u_int off, u_int val)
135 {
136 
137 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, off, val);
138 	bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_dr.dr_firstreg,
139 	    sc->sc_dr.dr_winsize, BUS_SPACE_BARRIER_WRITE |
140 	    BUS_SPACE_BARRIER_READ);
141 	DZ_DELAY(10);
142 }
143 
144 #include "ioconf.h"
145 
146 /* Flags used to monitor modem bits, make them understood outside driver */
147 
148 #define DML_DTR		TIOCM_DTR
149 #define DML_DCD		TIOCM_CD
150 #define DML_RI		TIOCM_RI
151 #define DML_BRK		0100000		/* no equivalent, we will mask */
152 
153 static const struct speedtab dzspeedtab[] =
154 {
155   {       0,	0		},
156   {      50,	DZ_LPR_B50	},
157   {      75,	DZ_LPR_B75	},
158   {     110,	DZ_LPR_B110	},
159   {     134,	DZ_LPR_B134	},
160   {     150,	DZ_LPR_B150	},
161   {     300,	DZ_LPR_B300	},
162   {     600,	DZ_LPR_B600	},
163   {    1200,	DZ_LPR_B1200	},
164   {    1800,	DZ_LPR_B1800	},
165   {    2000,	DZ_LPR_B2000	},
166   {    2400,	DZ_LPR_B2400	},
167   {    3600,	DZ_LPR_B3600	},
168   {    4800,	DZ_LPR_B4800	},
169   {    7200,	DZ_LPR_B7200	},
170   {    9600,	DZ_LPR_B9600	},
171   {   19200,	DZ_LPR_B19200	},
172   {      -1,	-1		}
173 };
174 
175 static void	dzstart(struct tty *);
176 static int	dzparam(struct tty *, struct termios *);
177 static unsigned	dzmctl(struct dz_softc *, int, int, int);
178 static void	dzscan(void *);
179 
180 static dev_type_open(dzopen);
181 static dev_type_close(dzclose);
182 static dev_type_read(dzread);
183 static dev_type_write(dzwrite);
184 static dev_type_ioctl(dzioctl);
185 static dev_type_stop(dzstop);
186 static dev_type_tty(dztty);
187 static dev_type_poll(dzpoll);
188 
189 const struct cdevsw dz_cdevsw = {
190 	.d_open = dzopen,
191 	.d_close = dzclose,
192 	.d_read = dzread,
193 	.d_write = dzwrite,
194 	.d_ioctl = dzioctl,
195 	.d_stop = dzstop,
196 	.d_tty = dztty,
197 	.d_poll = dzpoll,
198 	.d_mmap = nommap,
199 	.d_kqfilter = ttykqfilter,
200 	.d_flag = D_TTY
201 };
202 
203 /*
204  * The DZ series doesn't interrupt on carrier transitions,
205  * so we have to use a timer to watch it.
206  */
207 int	dz_timer;	/* true if timer started */
208 struct callout dzscan_ch;
209 static struct cnm_state dz_cnm_state;
210 
211 void
212 dzattach(struct dz_softc *sc, struct evcnt *parent_evcnt, int consline)
213 {
214 	int n;
215 
216 	/* Initialize our softc structure. */
217 
218 	for (n = 0; n < sc->sc_type; n++) {
219 		sc->sc_dz[n].dz_sc = sc;
220 		sc->sc_dz[n].dz_line = n;
221 		sc->sc_dz[n].dz_tty = tty_alloc();
222 	}
223 
224 	evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, parent_evcnt,
225 	    device_xname(sc->sc_dev), "rintr");
226 	evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, parent_evcnt,
227 	    device_xname(sc->sc_dev), "tintr");
228 
229 	/* Console magic keys */
230 	cn_init_magic(&dz_cnm_state);
231 	cn_set_magic("\047\001"); /* default magic is BREAK */
232 				  /* VAX will change it in MD code */
233 
234 	sc->sc_rxint = sc->sc_brk = 0;
235 	sc->sc_consline = consline;
236 
237 	sc->sc_dr.dr_tcrw = sc->sc_dr.dr_tcr;
238 	dz_write2(sc, sc->sc_dr.dr_csr, DZ_CSR_MSE | DZ_CSR_RXIE | DZ_CSR_TXIE);
239 	dz_write1(sc, sc->sc_dr.dr_dtr, 0);
240 	dz_write1(sc, sc->sc_dr.dr_break, 0);
241 	DELAY(10000);
242 
243 	/* Alas no interrupt on modem bit changes, so we manually scan */
244 	if (dz_timer == 0) {
245 		dz_timer = 1;
246 		callout_init(&dzscan_ch, 0);
247 		callout_reset(&dzscan_ch, hz, dzscan, NULL);
248 	}
249 	printf("\n");
250 }
251 
252 /* Receiver Interrupt */
253 
254 void
255 dzrint(void *arg)
256 {
257 	struct dz_softc *sc = arg;
258 	struct tty *tp;
259 	int cc, mcc, line;
260 	unsigned c;
261 	int overrun = 0;
262 
263 	sc->sc_rxint++;
264 
265 	while ((c = dz_read2(sc, sc->sc_dr.dr_rbuf)) & DZ_RBUF_DATA_VALID) {
266 		cc = c & 0xFF;
267 		line = DZ_PORT(c>>8);
268 		tp = sc->sc_dz[line].dz_tty;
269 
270 		/* Must be caught early */
271 		if (sc->sc_dz[line].dz_catch &&
272 		    (*sc->sc_dz[line].dz_catch)(sc->sc_dz[line].dz_private, cc))
273 			continue;
274 
275 		if ((c & (DZ_RBUF_FRAMING_ERR | 0xff)) == DZ_RBUF_FRAMING_ERR)
276 			mcc = CNC_BREAK;
277 		else
278 			mcc = cc;
279 
280 		cn_check_magic(tp->t_dev, mcc, dz_cnm_state);
281 
282 		if (!(tp->t_state & TS_ISOPEN)) {
283 			cv_broadcast(&tp->t_rawcv);
284 			continue;
285 		}
286 
287 		if ((c & DZ_RBUF_OVERRUN_ERR) && overrun == 0) {
288 			log(LOG_WARNING, "%s: silo overflow, line %d\n",
289 			    device_xname(sc->sc_dev), line);
290 			overrun = 1;
291 		}
292 
293 		if (c & DZ_RBUF_FRAMING_ERR)
294 			cc |= TTY_FE;
295 		if (c & DZ_RBUF_PARITY_ERR)
296 			cc |= TTY_PE;
297 
298 		(*tp->t_linesw->l_rint)(cc, tp);
299 	}
300 }
301 
302 /* Transmitter Interrupt */
303 
304 void
305 dzxint(void *arg)
306 {
307 	struct dz_softc *sc = arg;
308 	struct tty *tp;
309 	struct clist *cl;
310 	int line, ch, csr;
311 	u_char tcr;
312 
313 	/*
314 	 * Switch to POLLED mode.
315 	 *   Some simple measurements indicated that even on
316 	 *  one port, by freeing the scanner in the controller
317 	 *  by either providing a character or turning off
318 	 *  the port when output is complete, the transmitter
319 	 *  was ready to accept more output when polled again.
320 	 *   With just two ports running the game "worms,"
321 	 *  almost every interrupt serviced both transmitters!
322 	 *   Each UART is double buffered, so if the scanner
323 	 *  is quick enough and timing works out, we can even
324 	 *  feed the same port twice.
325 	 *
326 	 * Ragge 980517:
327 	 * Do not need to turn off interrupts, already at interrupt level.
328 	 * Remove the pdma stuff; no great need of it right now.
329 	 */
330 
331 	for (;;) {
332 		csr = dz_read2(sc, sc->sc_dr.dr_csr);
333 		if ((csr & DZ_CSR_TX_READY) == 0)
334 			break;
335 
336 		line = DZ_PORT(csr >> 8);
337 		tp = sc->sc_dz[line].dz_tty;
338 		cl = &tp->t_outq;
339 		tp->t_state &= ~TS_BUSY;
340 
341 		/* Just send out a char if we have one */
342 		/* As long as we can fill the chip buffer, we just loop here */
343 		if (cl->c_cc) {
344 			tp->t_state |= TS_BUSY;
345 			ch = getc(cl);
346 			dz_write1(sc, sc->sc_dr.dr_tbuf, ch);
347 			continue;
348 		}
349 
350 		/* Nothing to send; clear the scan bit */
351 		/* Clear xmit scanner bit; dzstart may set it again */
352 		tcr = dz_read2(sc, sc->sc_dr.dr_tcrw);
353 		tcr &= 255;
354 		tcr &= ~(1 << line);
355 		dz_write1(sc, sc->sc_dr.dr_tcr, tcr);
356 		if (sc->sc_dz[line].dz_catch)
357 			continue;
358 
359 		if (tp->t_state & TS_FLUSH)
360 			tp->t_state &= ~TS_FLUSH;
361 		else
362 			ndflush (&tp->t_outq, cl->c_cc);
363 
364 		(*tp->t_linesw->l_start)(tp);
365 	}
366 }
367 
368 int
369 dzopen(dev_t dev, int flag, int mode, struct lwp *l)
370 {
371 	const int line = DZ_PORT(minor(dev));
372 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
373 	struct tty *tp;
374 	int error = 0;
375 
376 	if (sc == NULL || line >= sc->sc_type)
377 		return ENXIO;
378 
379 	/* if some other device is using the line, it's busy */
380 	if (sc->sc_dz[line].dz_catch)
381 		return EBUSY;
382 
383 	tp = sc->sc_dz[line].dz_tty;
384 	if (tp == NULL)
385 		return (ENODEV);
386 	tp->t_oproc = dzstart;
387 	tp->t_param = dzparam;
388 	tp->t_dev = dev;
389 
390 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
391 		return (EBUSY);
392 
393 	if ((tp->t_state & TS_ISOPEN) == 0) {
394 		ttychars(tp);
395 		if (tp->t_ispeed == 0) {
396 			tp->t_iflag = TTYDEF_IFLAG;
397 			tp->t_oflag = TTYDEF_OFLAG;
398 			tp->t_cflag = TTYDEF_CFLAG;
399 			tp->t_lflag = TTYDEF_LFLAG;
400 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
401 		}
402 		(void) dzparam(tp, &tp->t_termios);
403 		ttsetwater(tp);
404 	}
405 
406 	/* Use DMBIS and *not* DMSET or else we clobber incoming bits */
407 	if (dzmctl(sc, line, DML_DTR, DMBIS) & DML_DCD)
408 		tp->t_state |= TS_CARR_ON;
409 	mutex_spin_enter(&tty_lock);
410 	while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
411 	       !(tp->t_state & TS_CARR_ON)) {
412 		tp->t_wopen++;
413 		error = ttysleep(tp, &tp->t_rawcv, true, 0);
414 		tp->t_wopen--;
415 		if (error)
416 			break;
417 	}
418 	mutex_spin_exit(&tty_lock);
419 	if (error)
420 		return (error);
421 	return ((*tp->t_linesw->l_open)(dev, tp));
422 }
423 
424 /*ARGSUSED*/
425 int
426 dzclose(dev_t dev, int flag, int mode, struct lwp *l)
427 {
428 	const int line = DZ_PORT(minor(dev));
429 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
430 	struct tty *tp = sc->sc_dz[line].dz_tty;
431 
432 	(*tp->t_linesw->l_close)(tp, flag);
433 
434 	/* Make sure a BREAK state is not left enabled. */
435 	(void) dzmctl(sc, line, DML_BRK, DMBIC);
436 
437 	/* Do a hangup if so required. */
438 	if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN))
439 		(void) dzmctl(sc, line, 0, DMSET);
440 
441 	return ttyclose(tp);
442 }
443 
444 int
445 dzread(dev_t dev, struct uio *uio, int flag)
446 {
447 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
448 	struct tty *tp = sc->sc_dz[DZ_PORT(minor(dev))].dz_tty;
449 
450 	return ((*tp->t_linesw->l_read)(tp, uio, flag));
451 }
452 
453 int
454 dzwrite(dev_t dev, struct uio *uio, int flag)
455 {
456 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
457 	struct tty *tp = sc->sc_dz[DZ_PORT(minor(dev))].dz_tty;
458 
459 	return ((*tp->t_linesw->l_write)(tp, uio, flag));
460 }
461 
462 int
463 dzpoll(dev_t dev, int events, struct lwp *l)
464 {
465 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
466 	struct tty *tp = sc->sc_dz[DZ_PORT(minor(dev))].dz_tty;
467 
468 	return ((*tp->t_linesw->l_poll)(tp, events, l));
469 }
470 
471 /*ARGSUSED*/
472 int
473 dzioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
474 {
475 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
476 	const int line = DZ_PORT(minor(dev));
477 	struct tty *tp = sc->sc_dz[line].dz_tty;
478 	int error;
479 
480 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
481 	if (error >= 0)
482 		return (error);
483 
484 	error = ttioctl(tp, cmd, data, flag, l);
485 	if (error >= 0)
486 		return (error);
487 
488 	switch (cmd) {
489 	case TIOCSBRK:
490 		(void) dzmctl(sc, line, DML_BRK, DMBIS);
491 		break;
492 
493 	case TIOCCBRK:
494 		(void) dzmctl(sc, line, DML_BRK, DMBIC);
495 		break;
496 
497 	case TIOCSDTR:
498 		(void) dzmctl(sc, line, DML_DTR, DMBIS);
499 		break;
500 
501 	case TIOCCDTR:
502 		(void) dzmctl(sc, line, DML_DTR, DMBIC);
503 		break;
504 
505 	case TIOCMSET:
506 		(void) dzmctl(sc, line, *(int *)data, DMSET);
507 		break;
508 
509 	case TIOCMBIS:
510 		(void) dzmctl(sc, line, *(int *)data, DMBIS);
511 		break;
512 
513 	case TIOCMBIC:
514 		(void) dzmctl(sc, line, *(int *)data, DMBIC);
515 		break;
516 
517 	case TIOCMGET:
518 		*(int *)data = (dzmctl(sc, line, 0, DMGET) & ~DML_BRK);
519 		break;
520 
521 	default:
522 		return (EPASSTHROUGH);
523 	}
524 	return (0);
525 }
526 
527 struct tty *
528 dztty(dev_t dev)
529 {
530 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(dev)));
531 
532 	return sc->sc_dz[DZ_PORT(minor(dev))].dz_tty;
533 }
534 
535 /*ARGSUSED*/
536 void
537 dzstop(struct tty *tp, int flag)
538 {
539 	if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY)
540 		tp->t_state |= TS_FLUSH;
541 }
542 
543 void
544 dzstart(struct tty *tp)
545 {
546 	struct dz_softc *sc;
547 	int line;
548 	int s;
549 	char state;
550 
551 	s = spltty();
552 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP)) {
553 		splx(s);
554 		return;
555 	}
556 	if (!ttypull(tp)) {
557 		splx(s);
558 		return;
559 	}
560 
561 	line = DZ_PORT(minor(tp->t_dev));
562 	sc = device_lookup_private(&dz_cd, DZ_I2C(minor(tp->t_dev)));
563 
564 	tp->t_state |= TS_BUSY;
565 	state = dz_read2(sc, sc->sc_dr.dr_tcrw) & 255;
566 	if ((state & (1 << line)) == 0)
567 		dz_write1(sc, sc->sc_dr.dr_tcr, state | (1 << line));
568 	dzxint(sc);
569 	splx(s);
570 }
571 
572 static int
573 dzparam(struct tty *tp, struct termios *t)
574 {
575 	struct dz_softc *sc = device_lookup_private(&dz_cd, DZ_I2C(minor(tp->t_dev)));
576 	const int line = DZ_PORT(minor(tp->t_dev));
577 	int cflag = t->c_cflag;
578 	int ispeed = ttspeedtab(t->c_ispeed, dzspeedtab);
579 	int ospeed = ttspeedtab(t->c_ospeed, dzspeedtab);
580 	unsigned lpr;
581 	int s;
582 
583 	/* check requested parameters */
584         if (ospeed < 0 || ispeed < 0 || ispeed != ospeed)
585                 return (EINVAL);
586 
587         tp->t_ispeed = t->c_ispeed;
588         tp->t_ospeed = t->c_ospeed;
589         tp->t_cflag = cflag;
590 
591 	if (ospeed == 0) {
592 		(void) dzmctl(sc, line, 0, DMSET);	/* hang up line */
593 		return (0);
594 	}
595 
596 	s = spltty();
597 
598 	/* XXX This is wrong.  Flush output or the chip gets very confused. */
599 	ttywait(tp);
600 
601 	lpr = DZ_LPR_RX_ENABLE | ((ispeed&0xF)<<8) | line;
602 
603 	switch (cflag & CSIZE)
604 	{
605 	  case CS5:
606 		lpr |= DZ_LPR_5_BIT_CHAR;
607 		break;
608 	  case CS6:
609 		lpr |= DZ_LPR_6_BIT_CHAR;
610 		break;
611 	  case CS7:
612 		lpr |= DZ_LPR_7_BIT_CHAR;
613 		break;
614 	  default:
615 		lpr |= DZ_LPR_8_BIT_CHAR;
616 		break;
617 	}
618 	if (cflag & PARENB)
619 		lpr |= DZ_LPR_PARENB;
620 	if (cflag & PARODD)
621 		lpr |= DZ_LPR_OPAR;
622 	if (cflag & CSTOPB)
623 		lpr |= DZ_LPR_2_STOP;
624 
625 	dz_write2(sc, sc->sc_dr.dr_lpr, lpr);
626 	(void) splx(s);
627 	DELAY(10000);
628 
629 	return (0);
630 }
631 
632 static unsigned
633 dzmctl(struct dz_softc *sc, int line, int bits, int how)
634 {
635 	unsigned status;
636 	unsigned mbits;
637 	unsigned bit;
638 	int s;
639 
640 	s = spltty();
641 	mbits = 0;
642 	bit = (1 << line);
643 
644 	/* external signals as seen from the port */
645 	status = dz_read1(sc, sc->sc_dr.dr_dcd) | sc->sc_dsr;
646 	if (status & bit)
647 		mbits |= DML_DCD;
648 	status = dz_read1(sc, sc->sc_dr.dr_ring);
649 	if (status & bit)
650 		mbits |= DML_RI;
651 
652 	/* internal signals/state delivered to port */
653 	status = dz_read1(sc, sc->sc_dr.dr_dtr);
654 	if (status & bit)
655 		mbits |= DML_DTR;
656 	if (sc->sc_brk & bit)
657 		mbits |= DML_BRK;
658 
659 	switch (how)
660 	{
661 	  case DMSET:
662 		mbits = bits;
663 		break;
664 
665 	  case DMBIS:
666 		mbits |= bits;
667 		break;
668 
669 	  case DMBIC:
670 		mbits &= ~bits;
671 		break;
672 
673 	  case DMGET:
674 		(void) splx(s);
675 		return (mbits);
676 	}
677 
678 	if (mbits & DML_DTR) {
679 		dz_write1(sc, sc->sc_dr.dr_dtr, dz_read1(sc, sc->sc_dr.dr_dtr) | bit);
680 	} else {
681 		dz_write1(sc, sc->sc_dr.dr_dtr, dz_read1(sc, sc->sc_dr.dr_dtr) & ~bit);
682 	}
683 
684 	if (mbits & DML_BRK) {
685 		sc->sc_brk |= bit;
686 		dz_write1(sc, sc->sc_dr.dr_break, sc->sc_brk);
687 	} else {
688 		sc->sc_brk &= ~bit;
689 		dz_write1(sc, sc->sc_dr.dr_break, sc->sc_brk);
690 	}
691 
692 	(void) splx(s);
693 
694 	return (mbits);
695 }
696 
697 /*
698  * This is called by timeout() periodically.
699  * Check to see if modem status bits have changed.
700  */
701 static void
702 dzscan(void *arg)
703 {
704 	struct dz_softc *sc;
705 	struct tty *tp;
706 	int n, bit, port;
707 	unsigned int csr;
708 	unsigned int tmp;
709 	int s;
710 
711 	s = spltty();
712 	for (n = 0; n < dz_cd.cd_ndevs; n++) {
713 		if ((sc = device_lookup_private(&dz_cd, n)) == NULL)
714 			continue;
715 
716 		for (port = 0; port < sc->sc_type; port++) {
717 			tp = sc->sc_dz[port].dz_tty;
718 			bit = (1 << port);
719 
720 			if ((dz_read1(sc, sc->sc_dr.dr_dcd) | sc->sc_dsr) & bit) {
721 				if (!(tp->t_state & TS_CARR_ON))
722 					(*tp->t_linesw->l_modem) (tp, 1);
723 			} else if ((tp->t_state & TS_CARR_ON) &&
724 			    (*tp->t_linesw->l_modem)(tp, 0) == 0) {
725 			    	tmp = dz_read2(sc, sc->sc_dr.dr_tcrw) & 255;
726 				dz_write1(sc, sc->sc_dr.dr_tcr, tmp & ~bit);
727 			}
728 	    	}
729 
730 		/*
731 		 *  If the RX interrupt rate is this high, switch
732 		 *  the controller to Silo Alarm - which means don't
733 	 	 *  interrupt until the RX silo has 16 characters in
734 	 	 *  it (the silo is 64 characters in all).
735 		 *  Avoid oscillating SA on and off by not turning
736 		 *  if off unless the rate is appropriately low.
737 		 */
738 		csr = dz_read2(sc, sc->sc_dr.dr_csr);
739 		tmp = csr;
740 		if (sc->sc_rxint > 16*10)
741 			csr |= DZ_CSR_SAE;
742 		else if (sc->sc_rxint < 10)
743 	    		csr &= ~DZ_CSR_SAE;
744 		if (csr != tmp)
745 			dz_write2(sc, sc->sc_dr.dr_csr, csr);
746 		sc->sc_rxint = 0;
747 
748 		dzxint(sc);
749 		dzrint(sc);
750 	}
751 	(void) splx(s);
752 	callout_reset(&dzscan_ch, hz, dzscan, NULL);
753 }
754 
755 /*
756  * Called after an ubareset. The DZ card is reset, but the only thing
757  * that must be done is to start the receiver and transmitter again.
758  * No DMA setup to care about.
759  */
760 void
761 dzreset(device_t dev)
762 {
763 	struct dz_softc *sc = device_private(dev);
764 	struct tty *tp;
765 	int i;
766 
767 	for (i = 0; i < sc->sc_type; i++) {
768 		tp = sc->sc_dz[i].dz_tty;
769 
770 		if (((tp->t_state & TS_ISOPEN) == 0) || (tp->t_wopen == 0))
771 			continue;
772 
773 		dzparam(tp, &tp->t_termios);
774 		dzmctl(sc, i, DML_DTR, DMSET);
775 		tp->t_state &= ~TS_BUSY;
776 		dzstart(tp);	/* Kick off transmitter again */
777 	}
778 }
779