Annotation of sys/dev/ic/z8530tty.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: z8530tty.c,v 1.16 2006/04/27 19:31:44 deraadt 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();
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: && (p->p_ucred->cr_uid != 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);
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);
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: if (tp->t_outq.c_cc <= tp->t_lowat) {
604: if (tp->t_state & TS_ASLEEP) {
605: tp->t_state &= ~TS_ASLEEP;
606: wakeup((caddr_t)&tp->t_outq);
607: }
608: selwakeup(&tp->t_wsel);
609: }
610:
611: nch = ndqb(&tp->t_outq, 0); /* XXX */
612: (void) splzs();
613:
614: if (nch) {
615: register char *p = tp->t_outq.c_cf;
616:
617: /* mark busy, enable tx done interrupts, & send first byte */
618: tp->t_state |= TS_BUSY;
619: zst->zst_tx_busy = 1;
620: cs->cs_preg[1] |= ZSWR1_TIE;
621: cs->cs_creg[1] = cs->cs_preg[1];
622: zs_write_reg(cs, 1, cs->cs_creg[1]);
623: zs_write_data(cs, *p);
624: zst->zst_tba = p + 1;
625: zst->zst_tbc = nch - 1;
626: } else {
627: /*
628: * Nothing to send, turn off transmit done interrupts.
629: * This is useful if something is doing polled output.
630: */
631: cs->cs_preg[1] &= ~ZSWR1_TIE;
632: cs->cs_creg[1] = cs->cs_preg[1];
633: zs_write_reg(cs, 1, cs->cs_creg[1]);
634: }
635: out:
636: splx(s);
637: }
638:
639: /*
640: * Stop output, e.g., for ^S or output flush.
641: */
642: int
643: zsstop(tp, flag)
644: struct tty *tp;
645: int flag;
646: {
647: register struct zstty_softc *zst;
648: register struct zs_chanstate *cs;
649: register int s;
650:
651: zst = zstty_cd.cd_devs[minor(tp->t_dev)];
652: cs = zst->zst_cs;
653:
654: s = splzs();
655: if (tp->t_state & TS_BUSY) {
656: /*
657: * Device is transmitting; must stop it.
658: * Also clear _heldtbc to prevent any
659: * flow-control event from resuming.
660: */
661: zst->zst_tbc = 0;
662: zst->zst_heldtbc = 0;
663: if ((tp->t_state & TS_TTSTOP) == 0)
664: tp->t_state |= TS_FLUSH;
665: }
666: splx(s);
667: return (0);
668: }
669:
670: /*
671: * Set ZS tty parameters from termios.
672: * XXX - Should just copy the whole termios after
673: * making sure all the changes could be done.
674: * XXX - Only whack the UART when params change...
675: */
676: static int
677: zsparam(tp, t)
678: register struct tty *tp;
679: register struct termios *t;
680: {
681: register struct zstty_softc *zst;
682: register struct zs_chanstate *cs;
683: register int s, bps, cflag, tconst;
684: u_char tmp3, tmp4, tmp5;
685:
686: zst = zstty_cd.cd_devs[minor(tp->t_dev)];
687: cs = zst->zst_cs;
688:
689: /* XXX: Need to use an MD function for this. */
690: bps = t->c_ospeed;
691: if (bps < 0 || (t->c_ispeed && t->c_ispeed != bps))
692: return (EINVAL);
693: if (bps == 0) {
694: /* stty 0 => drop DTR and RTS */
695: zs_modem(zst, 0);
696: return (0);
697: }
698: tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps);
699: if (tconst < 0)
700: return (EINVAL);
701:
702: /* Convert back to make sure we can do it. */
703: bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst);
704: if (bps != t->c_ospeed)
705: return (EINVAL);
706: tp->t_ispeed = tp->t_ospeed = bps;
707:
708: cflag = t->c_cflag;
709: tp->t_cflag = cflag;
710:
711: /*
712: * Block interrupts so that state will not
713: * be altered until we are done setting it up.
714: */
715: s = splzs();
716:
717: /*
718: * Initial values in cs_preg are set before
719: * our attach routine is called. The master
720: * interrupt enable is handled by zsc.c
721: */
722:
723: cs->cs_preg[12] = tconst;
724: cs->cs_preg[13] = tconst >> 8;
725:
726: switch (cflag & CSIZE) {
727: case CS5:
728: tmp3 = ZSWR3_RX_5;
729: tmp5 = ZSWR5_TX_5;
730: break;
731: case CS6:
732: tmp3 = ZSWR3_RX_6;
733: tmp5 = ZSWR5_TX_6;
734: break;
735: case CS7:
736: tmp3 = ZSWR3_RX_7;
737: tmp5 = ZSWR5_TX_7;
738: break;
739: case CS8:
740: default:
741: tmp3 = ZSWR3_RX_8;
742: tmp5 = ZSWR5_TX_8;
743: break;
744: }
745:
746: cs->cs_preg[3] = tmp3 | ZSWR3_RX_ENABLE;
747: cs->cs_preg[5] = tmp5 | ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS;
748:
749: tmp4 = ZSWR4_CLK_X16 | (cflag & CSTOPB ? ZSWR4_TWOSB : ZSWR4_ONESB);
750: if ((cflag & PARODD) == 0)
751: tmp4 |= ZSWR4_EVENP;
752: if (cflag & PARENB)
753: tmp4 |= ZSWR4_PARENB;
754: cs->cs_preg[4] = tmp4;
755:
756: /*
757: * Output hardware flow control on the chip is horrendous:
758: * if carrier detect drops, the receiver is disabled.
759: * Therefore, NEVER set the HFC bit, and instead use
760: * the status interrupts to detect CTS changes.
761: */
762: if (cflag & CRTSCTS) {
763: zst->zst_rbhiwat = zstty_rbuf_hiwat;
764: cs->cs_preg[15] |= ZSWR15_CTS_IE;
765: } else {
766: zst->zst_rbhiwat = zstty_rbuf_size; /* impossible value */
767: cs->cs_preg[15] &= ~ZSWR15_CTS_IE;
768: }
769:
770: /*
771: * If nothing is being transmitted, set up new current values,
772: * else mark them as pending.
773: */
774: if (cs->cs_heldchange == 0) {
775: if (zst->zst_tx_busy) {
776: zst->zst_heldtbc = zst->zst_tbc;
777: zst->zst_tbc = 0;
778: cs->cs_heldchange = 0xFF; /* XXX */
779: } else {
780: zs_loadchannelregs(cs);
781: }
782: }
783: splx(s);
784: return (0);
785: }
786:
787: /*
788: * Raise or lower modem control (DTR/RTS) signals. If a character is
789: * in transmission, the change is deferred.
790: */
791: static void
792: zs_modem(zst, onoff)
793: struct zstty_softc *zst;
794: int onoff;
795: {
796: struct zs_chanstate *cs;
797: struct tty *tp;
798: int s, bis, and;
799:
800: cs = zst->zst_cs;
801: tp = zst->zst_tty;
802:
803: if (onoff) {
804: bis = ZSWR5_DTR | ZSWR5_RTS;
805: and = ~0;
806: } else {
807: bis = 0;
808: and = ~(ZSWR5_DTR | ZSWR5_RTS);
809: }
810: s = splzs();
811: cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and;
812: if (cs->cs_heldchange == 0) {
813: if (zst->zst_tx_busy) {
814: zst->zst_heldtbc = zst->zst_tbc;
815: zst->zst_tbc = 0;
816: cs->cs_heldchange = (1<<5);
817: } else {
818: cs->cs_creg[5] = cs->cs_preg[5];
819: zs_write_reg(cs, 5, cs->cs_creg[5]);
820: }
821: }
822: splx(s);
823: }
824:
825: /*
826: * Try to block or unblock input using hardware flow-control.
827: * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
828: * if this function returns non-zero, the TS_TBLOCK flag will
829: * be set or cleared according to the "stop" arg passed.
830: */
831: int
832: zshwiflow(tp, stop)
833: struct tty *tp;
834: int stop;
835: {
836: register struct zstty_softc *zst;
837: int s;
838:
839: zst = zstty_cd.cd_devs[minor(tp->t_dev)];
840:
841: s = splzs();
842: if (stop) {
843: /*
844: * The tty layer is asking us to block input.
845: * If we already did it, just return TRUE.
846: */
847: if (zst->zst_rx_blocked)
848: goto out;
849: zst->zst_rx_blocked = 1;
850: } else {
851: /*
852: * The tty layer is asking us to resume input.
853: * The input ring is always empty by now.
854: */
855: zst->zst_rx_blocked = 0;
856: }
857: zs_hwiflow(zst, stop);
858: out:
859: splx(s);
860: return 1;
861: }
862:
863: /*
864: * Internal version of zshwiflow
865: * called at splzs
866: */
867: static void
868: zs_hwiflow(zst, stop)
869: register struct zstty_softc *zst;
870: int stop;
871: {
872: register struct zs_chanstate *cs;
873: register struct tty *tp;
874: register int bis, and;
875:
876: cs = zst->zst_cs;
877: tp = zst->zst_tty;
878:
879: if (stop) {
880: /* Block input (Lower RTS) */
881: bis = 0;
882: and = ~ZSWR5_RTS;
883: } else {
884: /* Unblock input (Raise RTS) */
885: bis = ZSWR5_RTS;
886: and = ~0;
887: }
888:
889: cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and;
890: if (cs->cs_heldchange == 0) {
891: if (zst->zst_tx_busy) {
892: zst->zst_heldtbc = zst->zst_tbc;
893: zst->zst_tbc = 0;
894: cs->cs_heldchange = (1<<5);
895: } else {
896: cs->cs_creg[5] = cs->cs_preg[5];
897: zs_write_reg(cs, 5, cs->cs_creg[5]);
898: }
899: }
900: }
901:
902:
903: /****************************************************************
904: * Interface to the lower layer (zscc)
905: ****************************************************************/
906:
907:
908: /*
909: * receiver ready interrupt.
910: * called at splzs
911: */
912: static void
913: zstty_rxint(cs)
914: register struct zs_chanstate *cs;
915: {
916: register struct zstty_softc *zst;
917: register int cc, put, put_next, ringmask;
918: register u_char c, rr0, rr1;
919: register u_short ch_rr1;
920:
921: zst = cs->cs_private;
922: put = zst->zst_rbput;
923: ringmask = zst->zst_ringmask;
924:
925: nextchar:
926:
927: /*
928: * First read the status, because reading the received char
929: * destroys the status of this char.
930: */
931: rr1 = zs_read_reg(cs, 1);
932: c = zs_read_data(cs);
933: ch_rr1 = (c << 8) | rr1;
934:
935: if (ch_rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
936: /* Clear the receive error. */
937: zs_write_csr(cs, ZSWR0_RESET_ERRORS);
938: }
939:
940: /* XXX: Check for the stop character? */
941:
942: zst->zst_rbuf[put] = ch_rr1;
943: put_next = (put + 1) & ringmask;
944:
945: /* Would overrun if increment makes (put==get). */
946: if (put_next == zst->zst_rbget) {
947: zst->zst_rx_overrun = 1;
948: } else {
949: /* OK, really increment. */
950: put = put_next;
951: }
952:
953: /* Keep reading until the FIFO is empty. */
954: rr0 = zs_read_csr(cs);
955: if (rr0 & ZSRR0_RX_READY)
956: goto nextchar;
957:
958: /* Done reading. */
959: zst->zst_rbput = put;
960:
961: /*
962: * If ring is getting too full, try to block input.
963: */
964: cc = put - zst->zst_rbget;
965: if (cc < 0)
966: cc += zstty_rbuf_size;
967: if ((cc > zst->zst_rbhiwat) && (zst->zst_rx_blocked == 0)) {
968: zst->zst_rx_blocked = 1;
969: zs_hwiflow(zst, 1);
970: }
971:
972: /* Ask for softint() call. */
973: cs->cs_softreq = 1;
974: }
975:
976: /*
977: * transmitter ready interrupt. (splzs)
978: */
979: static void
980: zstty_txint(cs)
981: register struct zs_chanstate *cs;
982: {
983: register struct zstty_softc *zst;
984: register int count;
985:
986: zst = cs->cs_private;
987:
988: /*
989: * If we suspended output for a "held" change,
990: * then handle that now and resume.
991: * Do flow-control changes ASAP.
992: * When the only change is for flow control,
993: * avoid hitting other registers, because that
994: * often makes the stupid zs drop input...
995: */
996: if (cs->cs_heldchange) {
997: if (cs->cs_heldchange == (1<<5)) {
998: /* Avoid whacking the chip... */
999: cs->cs_creg[5] = cs->cs_preg[5];
1000: zs_write_reg(cs, 5, cs->cs_creg[5]);
1001: } else
1002: zs_loadchannelregs(cs);
1003: cs->cs_heldchange = 0;
1004: count = zst->zst_heldtbc;
1005: } else
1006: count = zst->zst_tbc;
1007:
1008: /*
1009: * If our transmit buffer still has data,
1010: * just send the next character.
1011: */
1012: if (count > 0) {
1013: /* Send the next char. */
1014: zst->zst_tbc = --count;
1015: zs_write_data(cs, *zst->zst_tba);
1016: zst->zst_tba++;
1017: return;
1018: }
1019:
1020: zs_write_csr(cs, ZSWR0_RESET_TXINT);
1021:
1022: /* Ask the softint routine for more output. */
1023: zst->zst_tx_busy = 0;
1024: zst->zst_tx_done = 1;
1025: cs->cs_softreq = 1;
1026: }
1027:
1028: /*
1029: * status change interrupt. (splzs)
1030: */
1031: static void
1032: zstty_stint(cs)
1033: register struct zs_chanstate *cs;
1034: {
1035: register struct zstty_softc *zst;
1036: register struct tty *tp;
1037: register u_char rr0;
1038:
1039: zst = cs->cs_private;
1040: tp = zst->zst_tty;
1041:
1042: rr0 = zs_read_csr(cs);
1043: zs_write_csr(cs, ZSWR0_RESET_STATUS);
1044:
1045: /*
1046: * Check here for console break, so that we can abort
1047: * even when interrupts are locking up the machine.
1048: */
1049: if ((rr0 & ZSRR0_BREAK) &&
1050: (zst->zst_hwflags & ZS_HWFLAG_CONSOLE))
1051: {
1052: zs_abort();
1053: return;
1054: }
1055:
1056: /*
1057: * Need to handle CTS output flow control here.
1058: * Output remains stopped as long as either the
1059: * zst_tx_stopped or TS_TTSTOP flag is set.
1060: * Never restart here; the softint routine will
1061: * do that after things are ready to move.
1062: */
1063: if (((rr0 & ZSRR0_CTS) == 0) && (tp->t_cflag & CRTSCTS)) {
1064: zst->zst_tbc = 0;
1065: zst->zst_heldtbc = 0;
1066: zst->zst_tx_stopped = 1;
1067: }
1068:
1069: /*
1070: * We have to accumulate status line changes here.
1071: * Otherwise, if we get multiple status interrupts
1072: * before the softint runs, we could fail to notice
1073: * some status line changes in the softint routine.
1074: * Fix from Bill Studenmund, October 1996.
1075: */
1076: cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0);
1077:
1078: ttytstamp(tp, cs->cs_rr0 & ZSRR0_CTS, rr0 & ZSRR0_CTS,
1079: cs->cs_rr0 & ZSRR0_DCD, rr0 & ZSRR0_DCD);
1080:
1081: cs->cs_rr0 = rr0;
1082: zst->zst_st_check = 1;
1083:
1084: /* Ask for softint() call. */
1085: cs->cs_softreq = 1;
1086: }
1087:
1088: /*
1089: * Print out a ring or fifo overrun error message.
1090: */
1091: static void
1092: zsoverrun(zst, ptime, what)
1093: struct zstty_softc *zst;
1094: long *ptime;
1095: char *what;
1096: {
1097:
1098: if (*ptime != time_second) {
1099: *ptime = time_second;
1100: log(LOG_WARNING, "%s: %s overrun\n",
1101: zst->zst_dev.dv_xname, what);
1102: }
1103: }
1104:
1105: /*
1106: * Software interrupt. Called at zssoft
1107: *
1108: * The main job to be done here is to empty the input ring
1109: * by passing its contents up to the tty layer. The ring is
1110: * always emptied during this operation, therefore the ring
1111: * must not be larger than the space after "high water" in
1112: * the tty layer, or the tty layer might drop our input.
1113: *
1114: * Note: an "input blockage" condition is assumed to exist if
1115: * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
1116: */
1117: static void
1118: zstty_softint(cs)
1119: struct zs_chanstate *cs;
1120: {
1121: register struct zstty_softc *zst;
1122: register struct linesw *line;
1123: register struct tty *tp;
1124: register int get, c, s;
1125: int ringmask, overrun;
1126: register u_short ring_data;
1127: register u_char rr0, delta;
1128:
1129: zst = cs->cs_private;
1130: tp = zst->zst_tty;
1131: line = &linesw[tp->t_line];
1132: ringmask = zst->zst_ringmask;
1133: overrun = 0;
1134:
1135: /*
1136: * Raise to tty priority while servicing the ring.
1137: */
1138: s = spltty();
1139:
1140: if (zst->zst_rx_overrun) {
1141: zst->zst_rx_overrun = 0;
1142: zsoverrun(zst, &zst->zst_rotime, "ring");
1143: }
1144:
1145: /*
1146: * Copy data from the receive ring into the tty layer.
1147: */
1148: get = zst->zst_rbget;
1149: while (get != zst->zst_rbput) {
1150: ring_data = zst->zst_rbuf[get];
1151: get = (get + 1) & ringmask;
1152:
1153: if (ring_data & ZSRR1_DO)
1154: overrun++;
1155: /* low byte of ring_data is rr1 */
1156: c = (ring_data >> 8) & 0xff;
1157: if (ring_data & ZSRR1_FE)
1158: c |= TTY_FE;
1159: if (ring_data & ZSRR1_PE)
1160: c |= TTY_PE;
1161:
1162: line->l_rint(c, tp);
1163: }
1164: zst->zst_rbget = get;
1165:
1166: /*
1167: * If the overrun flag is set now, it was set while
1168: * copying char/status pairs from the ring, which
1169: * means this was a hardware (fifo) overrun.
1170: */
1171: if (overrun) {
1172: zsoverrun(zst, &zst->zst_fotime, "fifo");
1173: }
1174:
1175: /*
1176: * We have emptied the input ring. Maybe unblock input.
1177: * Note: an "input blockage" condition is assumed to exist
1178: * when EITHER zst_rx_blocked or the TS_TBLOCK flag is set,
1179: * so unblock here ONLY if TS_TBLOCK has not been set.
1180: */
1181: if (zst->zst_rx_blocked && ((tp->t_state & TS_TBLOCK) == 0)) {
1182: (void) splzs();
1183: zst->zst_rx_blocked = 0;
1184: zs_hwiflow(zst, 0); /* unblock input */
1185: (void) spltty();
1186: }
1187:
1188: /*
1189: * Do any deferred work for status interrupts.
1190: * The rr0 was saved in the h/w interrupt to
1191: * avoid another splzs in here.
1192: */
1193: if (zst->zst_st_check) {
1194: zst->zst_st_check = 0;
1195:
1196: rr0 = cs->cs_rr0;
1197: delta = cs->cs_rr0_delta;
1198: cs->cs_rr0_delta = 0;
1199: if (delta & ZSRR0_DCD) {
1200: c = ((rr0 & ZSRR0_DCD) != 0);
1201: if (line->l_modem(tp, c) == 0)
1202: zs_modem(zst, c);
1203: }
1204: if ((delta & ZSRR0_CTS) && (tp->t_cflag & CRTSCTS)) {
1205: /*
1206: * Only do restart here. Stop is handled
1207: * at the h/w interrupt level.
1208: */
1209: if (rr0 & ZSRR0_CTS) {
1210: zst->zst_tx_stopped = 0;
1211: tp->t_state &= ~TS_TTSTOP;
1212: (*line->l_start)(tp);
1213: }
1214: }
1215: }
1216:
1217: if (zst->zst_tx_done) {
1218: zst->zst_tx_done = 0;
1219: tp->t_state &= ~TS_BUSY;
1220: if (tp->t_state & TS_FLUSH)
1221: tp->t_state &= ~TS_FLUSH;
1222: else
1223: ndflush(&tp->t_outq, zst->zst_tba -
1224: (caddr_t) tp->t_outq.c_cf);
1225: line->l_start(tp);
1226: }
1227:
1228: splx(s);
1229: }
1230:
1231: struct zsops zsops_tty = {
1232: zstty_rxint, /* receive char available */
1233: zstty_stint, /* external/status */
1234: zstty_txint, /* xmit buffer empty */
1235: zstty_softint, /* process software interrupt */
1236: };
1237:
CVSweb