xref: /openbsd/sys/dev/ic/z8530tty.c (revision cca36db2)
1 /*	$OpenBSD: z8530tty.c,v 1.23 2010/07/02 17:27:01 nicm Exp $ */
2 /*	$NetBSD: z8530tty.c,v 1.13 1996/10/16 20:42:14 gwr Exp $	*/
3 
4 /*
5  * Copyright (c) 1994 Gordon W. Ross
6  * Copyright (c) 1992, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This software was developed by the Computer Systems Engineering group
10  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
11  * contributed to Berkeley.
12  *
13  * All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Lawrence Berkeley Laboratory.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  * 3. Neither the name of the University nor the names of its contributors
27  *    may be used to endorse or promote products derived from this software
28  *    without specific prior written permission.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  *	@(#)zs.c	8.1 (Berkeley) 7/19/93
43  */
44 
45 /*
46  * Zilog Z8530 Dual UART driver (tty interface)
47  *
48  * This is the "slave" driver that will be attached to
49  * the "zsc" driver for plain "tty" async. serial lines.
50  *
51  * Credits, history:
52  *
53  * The original version of this code was the sparc/dev/zs.c driver
54  * as distributed with the Berkeley 4.4 Lite release.  Since then,
55  * Gordon Ross reorganized the code into the current parent/child
56  * driver scheme, separating the Sun keyboard and mouse support
57  * into independent child drivers.
58  *
59  * RTS/CTS flow-control support was a collaboration of:
60  *	Gordon Ross <gwr@netbsd.org>,
61  *	Bill Studenmund <wrstuden@loki.stanford.edu>
62  *	Ian Dall <Ian.Dall@dsto.defence.gov.au>
63  */
64 
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/proc.h>
68 #include <sys/device.h>
69 #include <sys/conf.h>
70 #include <sys/file.h>
71 #include <sys/ioctl.h>
72 #include <sys/malloc.h>
73 #include <sys/tty.h>
74 #include <sys/time.h>
75 #include <sys/kernel.h>
76 #include <sys/syslog.h>
77 
78 #include <dev/ic/z8530reg.h>
79 #include <machine/z8530var.h>
80 
81 #ifdef KGDB
82 extern int zs_check_kgdb();
83 #endif
84 
85 /*
86  * Allow the MD var.h to override the default CFLAG so that
87  * console messages during boot come out with correct parity.
88  */
89 #ifndef	ZSTTY_DEF_CFLAG
90 #define	ZSTTY_DEF_CFLAG	TTYDEF_CFLAG
91 #endif
92 
93 /*
94  * How many input characters we can buffer.
95  * The port-specific var.h may override this.
96  * Note: must be a power of two!
97  */
98 #ifndef	ZSTTY_RING_SIZE
99 #define	ZSTTY_RING_SIZE	2048
100 #endif
101 
102 /*
103  * Make this an option variable one can patch.
104  * But be warned:  this must be a power of 2!
105  */
106 int zstty_rbuf_size = ZSTTY_RING_SIZE;
107 
108 /* This should usually be 3/4 of ZSTTY_RING_SIZE */
109 int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE - (ZSTTY_RING_SIZE >> 2));
110 
111 struct zstty_softc {
112 	struct	device zst_dev;		/* required first: base device */
113 	struct  tty *zst_tty;
114 	struct	zs_chanstate *zst_cs;
115 
116 	int zst_hwflags;	/* see z8530var.h */
117 	int zst_swflags;	/* TIOCFLAG_SOFTCAR, ... <ttycom.h> */
118 
119 	/*
120 	 * Printing an overrun error message often takes long enough to
121 	 * cause another overrun, so we only print one per second.
122 	 */
123 	long	zst_rotime;		/* time of last ring overrun */
124 	long	zst_fotime;		/* time of last fifo overrun */
125 
126 	/*
127 	 * The receive ring buffer.
128 	 */
129 	int	zst_rbget;	/* ring buffer `get' index */
130 	volatile int	zst_rbput;	/* ring buffer `put' index */
131 	int	zst_ringmask;
132 	int	zst_rbhiwat;
133 
134 	u_short	*zst_rbuf; /* rr1, data pairs */
135 
136 	/*
137 	 * The transmit byte count and address are used for pseudo-DMA
138 	 * output in the hardware interrupt code.  PDMA can be suspended
139 	 * to get pending changes done; heldtbc is used for this.  It can
140 	 * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state.
141 	 */
142 	int 	zst_tbc;			/* transmit byte count */
143 	caddr_t	zst_tba;			/* transmit buffer address */
144 	int 	zst_heldtbc;		/* held tbc while xmission stopped */
145 
146 	/* Flags to communicate with zstty_softint() */
147 	volatile char zst_rx_blocked;	/* input block at ring */
148 	volatile char zst_rx_overrun;	/* ring overrun */
149 	volatile char zst_tx_busy;	/* working on an output chunk */
150 	volatile char zst_tx_done;	/* done with one output chunk */
151 	volatile char zst_tx_stopped;	/* H/W level stop (lost CTS) */
152 	volatile char zst_st_check;	/* got a status interrupt */
153 	char pad[2];
154 };
155 
156 
157 /* Definition of the driver for autoconfig. */
158 static int	zstty_match(struct device *, void *, void *);
159 static void	zstty_attach(struct device *, struct device *, void *);
160 
161 struct cfattach zstty_ca = {
162 	sizeof(struct zstty_softc), zstty_match, zstty_attach
163 };
164 
165 struct cfdriver zstty_cd = {
166 	NULL, "zstty", DV_TTY
167 };
168 
169 struct zsops zsops_tty;
170 
171 /* Routines called from other code. */
172 cdev_decl(zs);	/* open, close, read, write, ioctl, stop, ... */
173 
174 static void	zsstart(struct tty *);
175 static int	zsparam(struct tty *, struct termios *);
176 static void	zs_modem(struct zstty_softc *zst, int onoff);
177 static int	zshwiflow(struct tty *, int);
178 static void	zs_hwiflow(struct zstty_softc *, int);
179 static void	zstty_rxint(register struct zs_chanstate *);
180 static void	zstty_txint(register struct zs_chanstate *);
181 static void	zstty_stint(register struct zs_chanstate *);
182 static void	zstty_softint(struct zs_chanstate *);
183 static void	zsoverrun(struct zstty_softc *, long *, char *);
184 /*
185  * zstty_match: how is this zs channel configured?
186  */
187 int
188 zstty_match(parent, match, aux)
189 	struct device *parent;
190 	void   *match, *aux;
191 {
192 	struct cfdata *cf = match;
193 	struct zsc_attach_args *args = aux;
194 
195 	/* Exact match is better than wildcard. */
196 	if (cf->cf_loc[0] == args->channel)
197 		return 2;
198 
199 	/* This driver accepts wildcard. */
200 	if (cf->cf_loc[0] == -1)
201 		return 1;
202 
203 	return 0;
204 }
205 
206 void
207 zstty_attach(parent, self, aux)
208 	struct device *parent, *self;
209 	void   *aux;
210 
211 {
212 	struct zsc_softc *zsc = (void *) parent;
213 	struct zstty_softc *zst = (void *) self;
214 	struct zsc_attach_args *args = aux;
215 	struct zs_chanstate *cs;
216 	struct cfdata *cf;
217 	struct tty *tp;
218 	int channel, tty_unit;
219 	dev_t dev;
220 
221 	cf = zst->zst_dev.dv_cfdata;
222 	tty_unit = zst->zst_dev.dv_unit;
223 	channel = args->channel;
224 	cs = &zsc->zsc_cs[channel];
225 	cs->cs_private = zst;
226 	cs->cs_ops = &zsops_tty;
227 
228 	zst->zst_cs = cs;
229 	zst->zst_swflags = cf->cf_flags;	/* softcar, etc. */
230 	zst->zst_hwflags = args->hwflags;
231 	dev = makedev(ZSTTY_MAJOR, tty_unit);
232 
233 	if (zst->zst_swflags)
234 		printf(" flags 0x%x", zst->zst_swflags);
235 
236 	if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)
237 		printf(": console");
238 	else {
239 #ifdef KGDB
240 		/*
241 		 * Allow kgdb to "take over" this port.  If this port is
242 		 * NOT the kgdb port, zs_check_kgdb() will return zero.
243 		 * If it IS the kgdb port, it will print "kgdb,...\n"
244 		 * and then return non-zero.
245 		 */
246 		if (zs_check_kgdb(cs, dev)) {
247 			/*
248 			 * This is the kgdb port (exclusive use)
249 			 * so skip the normal attach code.
250 			 */
251 			return;
252 		}
253 #endif
254 	}
255 	printf("\n");
256 
257 	tp = ttymalloc(0);
258 	tp->t_dev = dev;
259 	tp->t_oproc = zsstart;
260 	tp->t_param = zsparam;
261 	tp->t_hwiflow = zshwiflow;
262 
263 	zst->zst_tty = tp;
264 	zst->zst_rbhiwat =  zstty_rbuf_size;	/* impossible value */
265 	zst->zst_ringmask = zstty_rbuf_size - 1;
266 	zst->zst_rbuf = malloc(zstty_rbuf_size * sizeof(zst->zst_rbuf[0]),
267 			      M_DEVBUF, M_WAITOK);
268 
269 	/*
270 	 * Hardware init
271 	 */
272 	if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE) {
273 		/* This unit is the console. */
274 		zst->zst_swflags |= TIOCFLAG_SOFTCAR;
275 		/* Call _param so interrupts get enabled. */
276 		cs->cs_defspeed = zs_getspeed(cs);
277 		tp->t_ispeed = cs->cs_defspeed;
278 		tp->t_ospeed = cs->cs_defspeed;
279 		tp->t_cflag = ZSTTY_DEF_CFLAG;
280 		(void) zsparam(tp, &tp->t_termios);
281 	} else {
282 		/* Not the console; may need reset. */
283 		int reset, s;
284 		reset = (channel == 0) ?
285 			ZSWR9_A_RESET : ZSWR9_B_RESET;
286 		s = splzs();
287 		zs_write_reg(cs, 9, reset);
288 		splx(s);
289 	}
290 
291 	/*
292 	 * Initialize state of modem control lines (DTR).
293 	 * If softcar is set, turn on DTR now and leave it.
294 	 * otherwise, turn off DTR now, and raise in open.
295 	 * (Keeps modem from answering too early.)
296 	 */
297 	zs_modem(zst, (zst->zst_swflags & TIOCFLAG_SOFTCAR) ? 1 : 0);
298 }
299 
300 
301 /*
302  * Return pointer to our tty.
303  */
304 struct tty *
305 zstty(dev)
306 	dev_t dev;
307 {
308 	struct zstty_softc *zst;
309 	int unit = minor(dev);
310 
311 #ifdef	DIAGNOSTIC
312 	if (unit >= zstty_cd.cd_ndevs)
313 		panic("zstty");
314 #endif
315 	zst = zstty_cd.cd_devs[unit];
316 	return (zst->zst_tty);
317 }
318 
319 
320 /*
321  * Open a zs serial (tty) port.
322  */
323 int
324 zsopen(dev, flags, mode, p)
325 	dev_t dev;
326 	int flags;
327 	int mode;
328 	struct proc *p;
329 {
330 	register struct tty *tp;
331 	register struct zs_chanstate *cs;
332 	struct zstty_softc *zst;
333 	int error, s, unit;
334 
335 	unit = minor(dev);
336 	if (unit >= zstty_cd.cd_ndevs)
337 		return (ENXIO);
338 	zst = zstty_cd.cd_devs[unit];
339 	if (zst == NULL)
340 		return (ENXIO);
341 	tp = zst->zst_tty;
342 	cs = zst->zst_cs;
343 
344 	/* If KGDB took the line, then tp==NULL */
345 	if (tp == NULL)
346 		return (EBUSY);
347 
348 	/* It's simpler to do this up here. */
349 	if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE))
350 	     ==             (TS_ISOPEN | TS_XCLUDE))
351 	    && (suser(p, 0) != 0) )
352 	{
353 		return (EBUSY);
354 	}
355 
356 	s = spltty();
357 
358 	if ((tp->t_state & TS_ISOPEN) == 0) {
359 		/* First open. */
360 		ttychars(tp);
361 		tp->t_iflag = TTYDEF_IFLAG;
362 		tp->t_oflag = TTYDEF_OFLAG;
363 		tp->t_cflag = ZSTTY_DEF_CFLAG;
364 		if (zst->zst_swflags & TIOCFLAG_CLOCAL)
365 			tp->t_cflag |= CLOCAL;
366 		if (zst->zst_swflags & TIOCFLAG_CRTSCTS)
367 			tp->t_cflag |= CRTSCTS;
368 		if (zst->zst_swflags & TIOCFLAG_MDMBUF)
369 			tp->t_cflag |= MDMBUF;
370 		tp->t_lflag = TTYDEF_LFLAG;
371 		tp->t_ispeed = tp->t_ospeed = cs->cs_defspeed;
372 		(void) zsparam(tp, &tp->t_termios);
373 		ttsetwater(tp);
374 		/* Flush any pending input. */
375 		zst->zst_rbget = zst->zst_rbput;
376 		zs_iflush(cs);	/* XXX */
377 		/* Turn on DTR */
378 		zs_modem(zst, 1);
379 		if (zst->zst_swflags & TIOCFLAG_SOFTCAR) {
380 			tp->t_state |= TS_CARR_ON;
381 		}
382 	}
383 	error = 0;
384 
385 	/* Wait for carrier. */
386 	for (;;) {
387 
388 		/* Might never get status intr if carrier already on. */
389 		cs->cs_rr0 = zs_read_csr(cs);
390 		if (cs->cs_rr0 & ZSRR0_DCD) {
391 			tp->t_state |= TS_CARR_ON;
392 			break;
393 		}
394 
395 		if ((tp->t_state & TS_CARR_ON) ||
396 		    (tp->t_cflag & CLOCAL) ||
397 		    (flags & O_NONBLOCK) )
398 		{
399 			break;
400 		}
401 
402 		tp->t_state |= TS_WOPEN;
403 		error = ttysleep(tp, (caddr_t)&tp->t_rawq,
404 			TTIPRI | PCATCH, ttopen, 0);
405 		if (error) {
406 			if ((tp->t_state & TS_ISOPEN) == 0) {
407 				/* Never get here with softcar */
408 				zs_modem(zst, 0);
409 				tp->t_state &= ~TS_WOPEN;
410 				ttwakeup(tp);
411 			}
412 			break;
413 		}
414 	}
415 
416 	splx(s);
417 
418 	if (error == 0)
419 		error = linesw[tp->t_line].l_open(dev, tp, p);
420 
421 	return (error);
422 }
423 
424 /*
425  * Close a zs serial port.
426  */
427 int
428 zsclose(dev, flags, mode, p)
429 	dev_t dev;
430 	int flags;
431 	int mode;
432 	struct proc *p;
433 {
434 	struct zstty_softc *zst;
435 	register struct zs_chanstate *cs;
436 	register struct tty *tp;
437 	int hup;
438 
439 	zst = zstty_cd.cd_devs[minor(dev)];
440 	cs = zst->zst_cs;
441 	tp = zst->zst_tty;
442 
443 	/* XXX This is for cons.c. */
444 	if ((tp->t_state & TS_ISOPEN) == 0)
445 		return 0;
446 
447 	(*linesw[tp->t_line].l_close)(tp, flags, p);
448 	hup = tp->t_cflag & HUPCL;
449 	if (zst->zst_swflags & TIOCFLAG_SOFTCAR)
450 		hup = 0;
451 	if (hup) {
452 		zs_modem(zst, 0);
453 		/* hold low for 1 second */
454 		(void) tsleep((caddr_t)cs, TTIPRI, ttclos, hz);
455 	}
456 	if (cs->cs_creg[5] & ZSWR5_BREAK) {
457 		zs_break(cs, 0);
458 	}
459 	/* XXX - turn off interrupts? */
460 
461 	ttyclose(tp);
462 	return (0);
463 }
464 
465 /*
466  * Read/write zs serial port.
467  */
468 int
469 zsread(dev, uio, flags)
470 	dev_t dev;
471 	struct uio *uio;
472 	int flags;
473 {
474 	register struct zstty_softc *zst;
475 	register struct tty *tp;
476 
477 	zst = zstty_cd.cd_devs[minor(dev)];
478 	tp = zst->zst_tty;
479 	return (linesw[tp->t_line].l_read(tp, uio, flags));
480 }
481 
482 int
483 zswrite(dev, uio, flags)
484 	dev_t dev;
485 	struct uio *uio;
486 	int flags;
487 {
488 	register struct zstty_softc *zst;
489 	register struct tty *tp;
490 
491 	zst = zstty_cd.cd_devs[minor(dev)];
492 	tp = zst->zst_tty;
493 	return (linesw[tp->t_line].l_write(tp, uio, flags));
494 }
495 
496 #define TIOCFLAG_ALL (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | \
497                       TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF )
498 
499 int
500 zsioctl(dev, cmd, data, flag, p)
501 	dev_t dev;
502 	u_long cmd;
503 	caddr_t data;
504 	int flag;
505 	struct proc *p;
506 {
507 	register struct zstty_softc *zst;
508 	register struct zs_chanstate *cs;
509 	register struct tty *tp;
510 	register int error, tmp;
511 
512 	zst = zstty_cd.cd_devs[minor(dev)];
513 	cs = zst->zst_cs;
514 	tp = zst->zst_tty;
515 
516 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
517 	if (error >= 0)
518 		return (error);
519 	error = ttioctl(tp, cmd, data, flag, p);
520 	if (error >= 0)
521 		return (error);
522 
523 	switch (cmd) {
524 
525 	case TIOCSBRK:
526 		zs_break(cs, 1);
527 		break;
528 
529 	case TIOCCBRK:
530 		zs_break(cs, 0);
531 		break;
532 
533 	case TIOCGFLAGS:
534 		*(int *)data = zst->zst_swflags;
535 		break;
536 
537 	case TIOCSFLAGS:
538 		error = suser(p, 0);
539 		if (error != 0)
540 			return (EPERM);
541 		tmp = *(int *)data;
542 		/* Check for random bits... */
543 		if (tmp & ~TIOCFLAG_ALL)
544 			return(EINVAL);
545 		/* Silently enforce softcar on the console. */
546 		if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)
547 			tmp |= TIOCFLAG_SOFTCAR;
548 		/* These flags take effect during open. */
549 		zst->zst_swflags = tmp;
550 		break;
551 
552 	case TIOCSDTR:
553 		zs_modem(zst, 1);
554 		break;
555 
556 	case TIOCCDTR:
557 		zs_modem(zst, 0);
558 		break;
559 
560 	case TIOCMSET:
561 	case TIOCMBIS:
562 	case TIOCMBIC:
563 	case TIOCMGET:
564 	default:
565 		return (ENOTTY);
566 	}
567 	return (0);
568 }
569 
570 /*
571  * Start or restart transmission.
572  */
573 static void
574 zsstart(tp)
575 	register struct tty *tp;
576 {
577 	register struct zstty_softc *zst;
578 	register struct zs_chanstate *cs;
579 	register int s, nch;
580 
581 	zst = zstty_cd.cd_devs[minor(tp->t_dev)];
582 	cs = zst->zst_cs;
583 
584 	s = spltty();
585 
586 	/*
587 	 * If currently active or delaying, no need to do anything.
588 	 */
589 	if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
590 		goto out;
591 
592 	/*
593 	 * If under CRTSCTS hfc and halted, do nothing
594 	 */
595 	if (tp->t_cflag & CRTSCTS)
596 		if (zst->zst_tx_stopped)
597 			goto out;
598 
599 	/*
600 	 * If there are sleepers, and output has drained below low
601 	 * water mark, awaken.
602 	 */
603 	ttwakeupwr(tp);
604 
605 	nch = ndqb(&tp->t_outq, 0);	/* XXX */
606 	(void) splzs();
607 
608 	if (nch) {
609 		register char *p = tp->t_outq.c_cf;
610 
611 		/* mark busy, enable tx done interrupts, & send first byte */
612 		tp->t_state |= TS_BUSY;
613 		zst->zst_tx_busy = 1;
614 		cs->cs_preg[1] |= ZSWR1_TIE;
615 		cs->cs_creg[1] = cs->cs_preg[1];
616 		zs_write_reg(cs, 1, cs->cs_creg[1]);
617 		zs_write_data(cs, *p);
618 		zst->zst_tba = p + 1;
619 		zst->zst_tbc = nch - 1;
620 	} else {
621 		/*
622 		 * Nothing to send, turn off transmit done interrupts.
623 		 * This is useful if something is doing polled output.
624 		 */
625 		cs->cs_preg[1] &= ~ZSWR1_TIE;
626 		cs->cs_creg[1] = cs->cs_preg[1];
627 		zs_write_reg(cs, 1, cs->cs_creg[1]);
628 	}
629 out:
630 	splx(s);
631 }
632 
633 /*
634  * Stop output, e.g., for ^S or output flush.
635  */
636 int
637 zsstop(tp, flag)
638 	struct tty *tp;
639 	int flag;
640 {
641 	register struct zstty_softc *zst;
642 	register struct zs_chanstate *cs;
643 	register int s;
644 
645 	zst = zstty_cd.cd_devs[minor(tp->t_dev)];
646 	cs = zst->zst_cs;
647 
648 	s = splzs();
649 	if (tp->t_state & TS_BUSY) {
650 		/*
651 		 * Device is transmitting; must stop it.
652 		 * Also clear _heldtbc to prevent any
653 		 * flow-control event from resuming.
654 		 */
655 		zst->zst_tbc = 0;
656 		zst->zst_heldtbc = 0;
657 		if ((tp->t_state & TS_TTSTOP) == 0)
658 			tp->t_state |= TS_FLUSH;
659 	}
660 	splx(s);
661 	return (0);
662 }
663 
664 /*
665  * Set ZS tty parameters from termios.
666  * XXX - Should just copy the whole termios after
667  * making sure all the changes could be done.
668  * XXX - Only whack the UART when params change...
669  */
670 static int
671 zsparam(tp, t)
672 	register struct tty *tp;
673 	register struct termios *t;
674 {
675 	register struct zstty_softc *zst;
676 	register struct zs_chanstate *cs;
677 	register int s, bps, cflag, tconst;
678 	u_char tmp3, tmp4, tmp5;
679 
680 	zst = zstty_cd.cd_devs[minor(tp->t_dev)];
681 	cs = zst->zst_cs;
682 
683 	/* XXX: Need to use an MD function for this. */
684 	bps = t->c_ospeed;
685 	if (bps < 0 || (t->c_ispeed && t->c_ispeed != bps))
686 		return (EINVAL);
687 	if (bps == 0) {
688 		/* stty 0 => drop DTR and RTS */
689 		zs_modem(zst, 0);
690 		return (0);
691 	}
692 	tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
693 	if (tconst < 0)
694 		return (EINVAL);
695 
696 	/* Convert back to make sure we can do it. */
697 	bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
698 	if (bps != t->c_ospeed)
699 		return (EINVAL);
700 	tp->t_ispeed = tp->t_ospeed = bps;
701 
702 	cflag = t->c_cflag;
703 	tp->t_cflag = cflag;
704 
705 	/*
706 	 * Block interrupts so that state will not
707 	 * be altered until we are done setting it up.
708 	 */
709 	s = splzs();
710 
711 	/*
712 	 * Initial values in cs_preg are set before
713 	 * our attach routine is called.  The master
714 	 * interrupt enable is handled by zsc.c
715 	 */
716 
717 	cs->cs_preg[12] = tconst;
718 	cs->cs_preg[13] = tconst >> 8;
719 
720 	switch (cflag & CSIZE) {
721 	case CS5:
722 		tmp3 = ZSWR3_RX_5;
723 		tmp5 = ZSWR5_TX_5;
724 		break;
725 	case CS6:
726 		tmp3 = ZSWR3_RX_6;
727 		tmp5 = ZSWR5_TX_6;
728 		break;
729 	case CS7:
730 		tmp3 = ZSWR3_RX_7;
731 		tmp5 = ZSWR5_TX_7;
732 		break;
733 	case CS8:
734 	default:
735 		tmp3 = ZSWR3_RX_8;
736 		tmp5 = ZSWR5_TX_8;
737 		break;
738 	}
739 
740 	cs->cs_preg[3] = tmp3 | ZSWR3_RX_ENABLE;
741 	cs->cs_preg[5] = tmp5 | ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS;
742 
743 	tmp4 = ZSWR4_CLK_X16 | (cflag & CSTOPB ? ZSWR4_TWOSB : ZSWR4_ONESB);
744 	if ((cflag & PARODD) == 0)
745 		tmp4 |= ZSWR4_EVENP;
746 	if (cflag & PARENB)
747 		tmp4 |= ZSWR4_PARENB;
748 	cs->cs_preg[4] = tmp4;
749 
750 	/*
751 	 * Output hardware flow control on the chip is horrendous:
752 	 * if carrier detect drops, the receiver is disabled.
753 	 * Therefore, NEVER set the HFC bit, and instead use
754 	 * the status interrupts to detect CTS changes.
755 	 */
756 	if (cflag & CRTSCTS) {
757 		zst->zst_rbhiwat = zstty_rbuf_hiwat;
758 		cs->cs_preg[15] |= ZSWR15_CTS_IE;
759 	} else {
760 		zst->zst_rbhiwat = zstty_rbuf_size; /* impossible value */
761 		cs->cs_preg[15] &= ~ZSWR15_CTS_IE;
762 	}
763 
764 	/*
765 	 * If nothing is being transmitted, set up new current values,
766 	 * else mark them as pending.
767 	 */
768 	if (cs->cs_heldchange == 0) {
769 		if (zst->zst_tx_busy) {
770 			zst->zst_heldtbc = zst->zst_tbc;
771 			zst->zst_tbc = 0;
772 			cs->cs_heldchange = 0xFF; /* XXX */
773 		} else {
774 			zs_loadchannelregs(cs);
775 		}
776 	}
777 	splx(s);
778 	return (0);
779 }
780 
781 /*
782  * Raise or lower modem control (DTR/RTS) signals.  If a character is
783  * in transmission, the change is deferred.
784  */
785 static void
786 zs_modem(zst, onoff)
787 	struct zstty_softc *zst;
788 	int onoff;
789 {
790 	struct zs_chanstate *cs;
791 	struct tty *tp;
792 	int s, bis, and;
793 
794 	cs = zst->zst_cs;
795 	tp = zst->zst_tty;
796 
797 	if (onoff) {
798 		bis = ZSWR5_DTR | ZSWR5_RTS;
799 		and = ~0;
800 	} else {
801 		bis = 0;
802 		and = ~(ZSWR5_DTR | ZSWR5_RTS);
803 	}
804 	s = splzs();
805 	cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and;
806 	if (cs->cs_heldchange == 0) {
807 		if (zst->zst_tx_busy) {
808 			zst->zst_heldtbc = zst->zst_tbc;
809 			zst->zst_tbc = 0;
810 			cs->cs_heldchange = (1<<5);
811 		} else {
812 			cs->cs_creg[5] = cs->cs_preg[5];
813 			zs_write_reg(cs, 5, cs->cs_creg[5]);
814 		}
815 	}
816 	splx(s);
817 }
818 
819 /*
820  * Try to block or unblock input using hardware flow-control.
821  * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
822  * if this function returns non-zero, the TS_TBLOCK flag will
823  * be set or cleared according to the "stop" arg passed.
824  */
825 int
826 zshwiflow(tp, stop)
827 	struct tty *tp;
828 	int stop;
829 {
830 	register struct zstty_softc *zst;
831 	int s;
832 
833 	zst = zstty_cd.cd_devs[minor(tp->t_dev)];
834 
835 	s = splzs();
836 	if (stop) {
837 		/*
838 		 * The tty layer is asking us to block input.
839 		 * If we already did it, just return TRUE.
840 		 */
841 		if (zst->zst_rx_blocked)
842 			goto out;
843 		zst->zst_rx_blocked = 1;
844 	} else {
845 		/*
846 		 * The tty layer is asking us to resume input.
847 		 * The input ring is always empty by now.
848 		 */
849 		zst->zst_rx_blocked = 0;
850 	}
851 	zs_hwiflow(zst, stop);
852  out:
853 	splx(s);
854 	return 1;
855 }
856 
857 /*
858  * Internal version of zshwiflow
859  * called at splzs
860  */
861 static void
862 zs_hwiflow(zst, stop)
863 	register struct zstty_softc *zst;
864 	int stop;
865 {
866 	register struct zs_chanstate *cs;
867 	register struct tty *tp;
868 	register int bis, and;
869 
870 	cs = zst->zst_cs;
871 	tp = zst->zst_tty;
872 
873 	if (stop) {
874 		/* Block input (Lower RTS) */
875 		bis = 0;
876 		and = ~ZSWR5_RTS;
877 	} else {
878 		/* Unblock input (Raise RTS) */
879 		bis = ZSWR5_RTS;
880 		and = ~0;
881 	}
882 
883 	cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and;
884 	if (cs->cs_heldchange == 0) {
885 		if (zst->zst_tx_busy) {
886 			zst->zst_heldtbc = zst->zst_tbc;
887 			zst->zst_tbc = 0;
888 			cs->cs_heldchange = (1<<5);
889 		} else {
890 			cs->cs_creg[5] = cs->cs_preg[5];
891 			zs_write_reg(cs, 5, cs->cs_creg[5]);
892 		}
893 	}
894 }
895 
896 
897 /****************************************************************
898  * Interface to the lower layer (zscc)
899  ****************************************************************/
900 
901 
902 /*
903  * receiver ready interrupt.
904  * called at splzs
905  */
906 static void
907 zstty_rxint(cs)
908 	register struct zs_chanstate *cs;
909 {
910 	register struct zstty_softc *zst;
911 	register int cc, put, put_next, ringmask;
912 	register u_char c, rr0, rr1;
913 	register u_short ch_rr1;
914 
915 	zst = cs->cs_private;
916 	put = zst->zst_rbput;
917 	ringmask = zst->zst_ringmask;
918 
919 nextchar:
920 
921 	/*
922 	 * First read the status, because reading the received char
923 	 * destroys the status of this char.
924 	 */
925 	rr1 = zs_read_reg(cs, 1);
926 	c = zs_read_data(cs);
927 	ch_rr1 = (c << 8) | rr1;
928 
929 	if (ch_rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
930 		/* Clear the receive error. */
931 		zs_write_csr(cs, ZSWR0_RESET_ERRORS);
932 	}
933 
934 	/* XXX: Check for the stop character? */
935 
936 	zst->zst_rbuf[put] = ch_rr1;
937 	put_next = (put + 1) & ringmask;
938 
939 	/* Would overrun if increment makes (put==get). */
940 	if (put_next == zst->zst_rbget) {
941 		zst->zst_rx_overrun = 1;
942 	} else {
943 		/* OK, really increment. */
944 		put = put_next;
945 	}
946 
947 	/* Keep reading until the FIFO is empty. */
948 	rr0 = zs_read_csr(cs);
949 	if (rr0 & ZSRR0_RX_READY)
950 		goto nextchar;
951 
952 	/* Done reading. */
953 	zst->zst_rbput = put;
954 
955 	/*
956 	 * If ring is getting too full, try to block input.
957 	 */
958 	cc = put - zst->zst_rbget;
959 	if (cc < 0)
960 		cc += zstty_rbuf_size;
961 	if ((cc > zst->zst_rbhiwat) && (zst->zst_rx_blocked == 0)) {
962 		zst->zst_rx_blocked = 1;
963 		zs_hwiflow(zst, 1);
964 	}
965 
966 	/* Ask for softint() call. */
967 	cs->cs_softreq = 1;
968 }
969 
970 /*
971  * transmitter ready interrupt.  (splzs)
972  */
973 static void
974 zstty_txint(cs)
975 	register struct zs_chanstate *cs;
976 {
977 	register struct zstty_softc *zst;
978 	register int count;
979 
980 	zst = cs->cs_private;
981 
982 	/*
983 	 * If we suspended output for a "held" change,
984 	 * then handle that now and resume.
985 	 * Do flow-control changes ASAP.
986 	 * When the only change is for flow control,
987 	 * avoid hitting other registers, because that
988 	 * often makes the stupid zs drop input...
989 	 */
990 	if (cs->cs_heldchange) {
991 		if (cs->cs_heldchange == (1<<5)) {
992 			/* Avoid whacking the chip... */
993 			cs->cs_creg[5] = cs->cs_preg[5];
994 			zs_write_reg(cs, 5, cs->cs_creg[5]);
995 		} else
996 			zs_loadchannelregs(cs);
997 		cs->cs_heldchange = 0;
998 		count = zst->zst_heldtbc;
999 	} else
1000 		count = zst->zst_tbc;
1001 
1002 	/*
1003 	 * If our transmit buffer still has data,
1004 	 * just send the next character.
1005 	 */
1006 	if (count > 0) {
1007 		/* Send the next char. */
1008 		zst->zst_tbc = --count;
1009 		zs_write_data(cs, *zst->zst_tba);
1010 		zst->zst_tba++;
1011 		return;
1012 	}
1013 
1014 	zs_write_csr(cs, ZSWR0_RESET_TXINT);
1015 
1016 	/* Ask the softint routine for more output. */
1017 	zst->zst_tx_busy = 0;
1018 	zst->zst_tx_done = 1;
1019 	cs->cs_softreq = 1;
1020 }
1021 
1022 /*
1023  * status change interrupt.  (splzs)
1024  */
1025 static void
1026 zstty_stint(cs)
1027 	register struct zs_chanstate *cs;
1028 {
1029 	register struct zstty_softc *zst;
1030 	register struct tty *tp;
1031 	register u_char rr0;
1032 
1033 	zst = cs->cs_private;
1034 	tp  = zst->zst_tty;
1035 
1036 	rr0 = zs_read_csr(cs);
1037 	zs_write_csr(cs, ZSWR0_RESET_STATUS);
1038 
1039 	/*
1040 	 * Check here for console break, so that we can abort
1041 	 * even when interrupts are locking up the machine.
1042 	 */
1043 	if ((rr0 & ZSRR0_BREAK) &&
1044 		(zst->zst_hwflags & ZS_HWFLAG_CONSOLE))
1045 	{
1046 		zs_abort();
1047 		return;
1048 	}
1049 
1050 	/*
1051 	 * Need to handle CTS output flow control here.
1052 	 * Output remains stopped as long as either the
1053 	 * zst_tx_stopped or TS_TTSTOP flag is set.
1054 	 * Never restart here; the softint routine will
1055 	 * do that after things are ready to move.
1056 	 */
1057 	if (((rr0 & ZSRR0_CTS) == 0) && (tp->t_cflag & CRTSCTS)) {
1058 		zst->zst_tbc = 0;
1059 		zst->zst_heldtbc = 0;
1060 		zst->zst_tx_stopped = 1;
1061 	}
1062 
1063 	/*
1064 	 * We have to accumulate status line changes here.
1065 	 * Otherwise, if we get multiple status interrupts
1066 	 * before the softint runs, we could fail to notice
1067 	 * some status line changes in the softint routine.
1068 	 * Fix from Bill Studenmund, October 1996.
1069 	 */
1070 	cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0);
1071 
1072 	ttytstamp(tp, cs->cs_rr0 & ZSRR0_CTS, rr0 & ZSRR0_CTS,
1073 	    cs->cs_rr0 & ZSRR0_DCD, rr0 & ZSRR0_DCD);
1074 
1075 	cs->cs_rr0 = rr0;
1076 	zst->zst_st_check = 1;
1077 
1078 	/* Ask for softint() call. */
1079 	cs->cs_softreq = 1;
1080 }
1081 
1082 /*
1083  * Print out a ring or fifo overrun error message.
1084  */
1085 static void
1086 zsoverrun(zst, ptime, what)
1087 	struct zstty_softc *zst;
1088 	long *ptime;
1089 	char *what;
1090 {
1091 
1092 	if (*ptime != time_second) {
1093 		*ptime = time_second;
1094 		log(LOG_WARNING, "%s: %s overrun\n",
1095 			zst->zst_dev.dv_xname, what);
1096 	}
1097 }
1098 
1099 /*
1100  * Software interrupt.  Called at zssoft
1101  *
1102  * The main job to be done here is to empty the input ring
1103  * by passing its contents up to the tty layer.  The ring is
1104  * always emptied during this operation, therefore the ring
1105  * must not be larger than the space after "high water" in
1106  * the tty layer, or the tty layer might drop our input.
1107  *
1108  * Note: an "input blockage" condition is assumed to exist if
1109  * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
1110  */
1111 static void
1112 zstty_softint(cs)
1113 	struct zs_chanstate *cs;
1114 {
1115 	register struct zstty_softc *zst;
1116 	register struct linesw *line;
1117 	register struct tty *tp;
1118 	register int get, c, s;
1119 	int ringmask, overrun;
1120 	register u_short ring_data;
1121 	register u_char rr0, delta;
1122 
1123 	zst  = cs->cs_private;
1124 	tp   = zst->zst_tty;
1125 	line = &linesw[tp->t_line];
1126 	ringmask = zst->zst_ringmask;
1127 	overrun = 0;
1128 
1129 	/*
1130 	 * Raise to tty priority while servicing the ring.
1131 	 */
1132 	s = spltty();
1133 
1134 	if (zst->zst_rx_overrun) {
1135 		zst->zst_rx_overrun = 0;
1136 		zsoverrun(zst, &zst->zst_rotime, "ring");
1137 	}
1138 
1139 	/*
1140 	 * Copy data from the receive ring into the tty layer.
1141 	 */
1142 	get = zst->zst_rbget;
1143 	while (get != zst->zst_rbput) {
1144 		ring_data = zst->zst_rbuf[get];
1145 		get = (get + 1) & ringmask;
1146 
1147 		if (ring_data & ZSRR1_DO)
1148 			overrun++;
1149 		/* low byte of ring_data is rr1 */
1150 		c = (ring_data >> 8) & 0xff;
1151 		if (ring_data & ZSRR1_FE)
1152 			c |= TTY_FE;
1153 		if (ring_data & ZSRR1_PE)
1154 			c |= TTY_PE;
1155 
1156 		line->l_rint(c, tp);
1157 	}
1158 	zst->zst_rbget = get;
1159 
1160 	/*
1161 	 * If the overrun flag is set now, it was set while
1162 	 * copying char/status pairs from the ring, which
1163 	 * means this was a hardware (fifo) overrun.
1164 	 */
1165 	if (overrun) {
1166 		zsoverrun(zst, &zst->zst_fotime, "fifo");
1167 	}
1168 
1169 	/*
1170 	 * We have emptied the input ring.  Maybe unblock input.
1171 	 * Note: an "input blockage" condition is assumed to exist
1172 	 * when EITHER zst_rx_blocked or the TS_TBLOCK flag is set,
1173 	 * so unblock here ONLY if TS_TBLOCK has not been set.
1174 	 */
1175 	if (zst->zst_rx_blocked && ((tp->t_state & TS_TBLOCK) == 0)) {
1176 		(void) splzs();
1177 		zst->zst_rx_blocked = 0;
1178 		zs_hwiflow(zst, 0);	/* unblock input */
1179 		(void) spltty();
1180 	}
1181 
1182 	/*
1183 	 * Do any deferred work for status interrupts.
1184 	 * The rr0 was saved in the h/w interrupt to
1185 	 * avoid another splzs in here.
1186 	 */
1187 	if (zst->zst_st_check) {
1188 		zst->zst_st_check = 0;
1189 
1190 		rr0 = cs->cs_rr0;
1191 		delta = cs->cs_rr0_delta;
1192 		cs->cs_rr0_delta = 0;
1193 		if (delta & ZSRR0_DCD) {
1194 			c = ((rr0 & ZSRR0_DCD) != 0);
1195 			if (line->l_modem(tp, c) == 0)
1196 				zs_modem(zst, c);
1197 		}
1198 		if ((delta & ZSRR0_CTS) && (tp->t_cflag & CRTSCTS)) {
1199 			/*
1200 			 * Only do restart here.  Stop is handled
1201 			 * at the h/w interrupt level.
1202 			 */
1203 			if (rr0 & ZSRR0_CTS) {
1204 				zst->zst_tx_stopped = 0;
1205 				tp->t_state &= ~TS_TTSTOP;
1206 				(*line->l_start)(tp);
1207 			}
1208 		}
1209 	}
1210 
1211 	if (zst->zst_tx_done) {
1212 		zst->zst_tx_done = 0;
1213 		tp->t_state &= ~TS_BUSY;
1214 		if (tp->t_state & TS_FLUSH)
1215 			tp->t_state &= ~TS_FLUSH;
1216 		else
1217 			ndflush(&tp->t_outq, zst->zst_tba -
1218 				(caddr_t) tp->t_outq.c_cf);
1219 		line->l_start(tp);
1220 	}
1221 
1222 	splx(s);
1223 }
1224 
1225 struct zsops zsops_tty = {
1226 	zstty_rxint,	/* receive char available */
1227 	zstty_stint,	/* external/status */
1228 	zstty_txint,	/* xmit buffer empty */
1229 	zstty_softint,	/* process software interrupt */
1230 };
1231 
1232