Annotation of sys/arch/mac68k/dev/z8530tty.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: z8530tty.c,v 1.17 2006/04/14 09:36:49 martin Exp $ */
2: /* $NetBSD: z8530tty.c,v 1.14 1996/12/17 20:42:43 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 <mac68k/dev/z8530reg.h>
79: #include <machine/z8530var.h>
80:
81: #ifdef KGDB
82: extern int zs_check_kgdb();
83: #endif
84:
85: /*
86: * How many input characters we can buffer.
87: * The port-specific var.h may override this.
88: * Note: must be a power of two!
89: */
90: #ifndef ZSTTY_RING_SIZE
91: #define ZSTTY_RING_SIZE 2048
92: #endif
93:
94: /*
95: * Make this an option variable one can patch.
96: * But be warned: this must be a power of 2!
97: */
98: int zstty_rbuf_size = ZSTTY_RING_SIZE;
99:
100: /* This should usually be 3/4 of ZSTTY_RING_SIZE */
101: int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE - (ZSTTY_RING_SIZE >> 2));
102:
103: struct zstty_softc {
104: struct device zst_dev; /* required first: base device */
105: struct tty *zst_tty;
106: struct zs_chanstate *zst_cs;
107:
108: int zst_hwflags; /* see z8530var.h */
109: int zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */
110:
111: /*
112: * Printing an overrun error message often takes long enough to
113: * cause another overrun, so we only print one per second.
114: */
115: long zst_rotime; /* time of last ring overrun */
116: long zst_fotime; /* time of last fifo overrun */
117:
118: /*
119: * The receive ring buffer.
120: */
121: int zst_rbget; /* ring buffer `get' index */
122: volatile int zst_rbput; /* ring buffer `put' index */
123: int zst_ringmask;
124: int zst_rbhiwat;
125:
126: u_short *zst_rbuf; /* rr1, data pairs */
127:
128: /*
129: * The transmit byte count and address are used for pseudo-DMA
130: * output in the hardware interrupt code. PDMA can be suspended
131: * to get pending changes done; heldtbc is used for this. It can
132: * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state.
133: */
134: int zst_tbc; /* transmit byte count */
135: caddr_t zst_tba; /* transmit buffer address */
136: int zst_heldtbc; /* held tbc while xmission stopped */
137:
138: /* Flags to communicate with zstty_softint() */
139: volatile char zst_rx_blocked; /* input block at ring */
140: volatile char zst_rx_overrun; /* ring overrun */
141: volatile char zst_tx_busy; /* working on an output chunk */
142: volatile char zst_tx_done; /* done with one output chunk */
143: volatile char zst_tx_stopped; /* H/W level stop (lost CTS) */
144: volatile char zst_st_check; /* got a status interrupt */
145: char pad[2];
146: };
147:
148:
149: /* Definition of the driver for autoconfig. */
150: static int zstty_match(struct device *, void *, void *);
151: static void zstty_attach(struct device *, struct device *, void *);
152:
153: struct cfattach zstty_ca = {
154: sizeof(struct zstty_softc), zstty_match, zstty_attach
155: };
156:
157: struct cfdriver zstty_cd = {
158: NULL, "zstty", DV_TTY
159: };
160:
161: struct zsops zsops_tty;
162:
163: /* Routines called from other code. */
164: cdev_decl(zs); /* open, close, read, write, ioctl, stop, ... */
165:
166: static void zsstart(struct tty *);
167: static int zsparam(struct tty *, struct termios *);
168: static void zs_modem(struct zstty_softc *zst, int onoff);
169: static int zshwiflow(struct tty *, int);
170: static void zs_hwiflow(struct zstty_softc *, int);
171: static void zstty_rxint(register struct zs_chanstate *);
172: static void zstty_txint(register struct zs_chanstate *);
173: static void zstty_stint(register struct zs_chanstate *);
174: static void zstty_softint(struct zs_chanstate *);
175: static void zsoverrun(struct zstty_softc *, long *, char *);
176: /*
177: * zstty_match: how is this zs channel configured?
178: */
179: int
180: zstty_match(parent, match, aux)
181: struct device *parent;
182: void *match, *aux;
183: {
184: struct cfdata *cf = match;
185: struct zsc_attach_args *args = aux;
186:
187: /* Exact match is better than wildcard. */
188: if (cf->cf_loc[0] == args->channel)
189: return 2;
190:
191: /* This driver accepts wildcard. */
192: if (cf->cf_loc[0] == -1)
193: return 1;
194:
195: return 0;
196: }
197:
198: void
199: zstty_attach(parent, self, aux)
200: struct device *parent, *self;
201: void *aux;
202:
203: {
204: struct zsc_softc *zsc = (void *) parent;
205: struct zstty_softc *zst = (void *) self;
206: struct zsc_attach_args *args = aux;
207: struct zs_chanstate *cs;
208: struct cfdata *cf;
209: struct tty *tp;
210: int channel, tty_unit;
211: dev_t dev;
212:
213: tty_unit = zst->zst_dev.dv_unit;
214: channel = args->channel;
215: cs = zsc->zsc_cs[channel];
216: cs->cs_private = zst;
217: cs->cs_ops = &zsops_tty;
218:
219: zst->zst_cs = cs;
220: zst->zst_swflags = cf->cf_flags; /* softcar, etc. */
221: zst->zst_hwflags = args->hwflags;
222: dev = makedev(zs_major, tty_unit);
223:
224: if (zst->zst_swflags)
225: printf(" flags 0x%x", zst->zst_swflags);
226:
227: if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)
228: printf(": console");
229: else {
230: #ifdef KGDB
231: /*
232: * Allow kgdb to "take over" this port. If this port is
233: * NOT the kgdb port, zs_check_kgdb() will return zero.
234: * If it IS the kgdb port, it will print "kgdb,...\n"
235: * and then return non-zero.
236: */
237: if (zs_check_kgdb(cs, dev)) {
238: /*
239: * This is the kgdb port (exclusive use)
240: * so skip the normal attach code.
241: */
242: return;
243: }
244: #endif
245: }
246: printf("\n");
247:
248: tp = ttymalloc();
249: tp->t_dev = dev;
250: tp->t_oproc = zsstart;
251: tp->t_param = zsparam;
252: tp->t_hwiflow = zshwiflow;
253:
254: zst->zst_tty = tp;
255: zst->zst_rbhiwat = zstty_rbuf_size; /* impossible value */
256: zst->zst_ringmask = zstty_rbuf_size - 1;
257: zst->zst_rbuf = malloc(zstty_rbuf_size * sizeof(zst->zst_rbuf[0]),
258: M_DEVBUF, M_WAITOK);
259: /* XXX - Do we need an MD hook here? */
260:
261: /*
262: * Hardware init
263: */
264: if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE) {
265: /* Call zsparam similar to open. */
266: struct termios t;
267:
268: /* Make console output work while closed. */
269: zst->zst_swflags |= TIOCFLAG_SOFTCAR;
270: /* Setup the "new" parameters in t. */
271: bzero((void*)&t, sizeof(t));
272: t.c_cflag = cs->cs_defcflag;
273: t.c_ospeed = cs->cs_defspeed;
274: /* Enable interrupts. */
275: cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE;
276: /* Make sure zsparam will see changes. */
277: tp->t_ospeed = 0;
278: (void) zsparam(tp, &t);
279: } else {
280: /* Not the console; may need reset. */
281: int reset, s;
282: reset = (channel == 0) ?
283: ZSWR9_A_RESET : ZSWR9_B_RESET;
284: s = splzs();
285: zs_write_reg(cs, 9, reset);
286: splx(s);
287: }
288:
289: /*
290: * Initialize state of modem control lines (DTR).
291: * If softcar is set, turn on DTR now and leave it.
292: * otherwise, turn off DTR now, and raise in open.
293: * (Keeps modem from answering too early.)
294: */
295: zs_modem(zst, (zst->zst_swflags & TIOCFLAG_SOFTCAR) ? 1 : 0);
296: }
297:
298:
299: /*
300: * Return pointer to our tty.
301: */
302: struct tty *
303: zstty(dev)
304: dev_t dev;
305: {
306: struct zstty_softc *zst;
307: int unit = minor(dev);
308:
309: #ifdef DIAGNOSTIC
310: if (unit >= zstty_cd.cd_ndevs)
311: panic("zstty");
312: #endif
313: zst = zstty_cd.cd_devs[unit];
314: return (zst->zst_tty);
315: }
316:
317:
318: /*
319: * Open a zs serial (tty) port.
320: */
321: int
322: zsopen(dev, flags, mode, p)
323: dev_t dev;
324: int flags;
325: int mode;
326: struct proc *p;
327: {
328: register struct tty *tp;
329: register struct zs_chanstate *cs;
330: struct zstty_softc *zst;
331: int error, s, unit;
332:
333: unit = minor(dev);
334: if (unit >= zstty_cd.cd_ndevs)
335: return (ENXIO);
336: zst = zstty_cd.cd_devs[unit];
337: if (zst == NULL)
338: return (ENXIO);
339: tp = zst->zst_tty;
340: cs = zst->zst_cs;
341:
342: /* If KGDB took the line, then tp==NULL */
343: if (tp == NULL)
344: return (EBUSY);
345:
346: /* It's simpler to do this up here. */
347: if (((tp->t_state & (TS_ISOPEN | TS_XCLUDE))
348: == (TS_ISOPEN | TS_XCLUDE))
349: && (p->p_ucred->cr_uid != 0) )
350: {
351: return (EBUSY);
352: }
353:
354: s = spltty();
355:
356: if ((tp->t_state & TS_ISOPEN) == 0) {
357: /* First open. */
358: struct termios t;
359:
360: /*
361: * Setup the "new" parameters in t.
362: * Can not use tp->t because zsparam
363: * deals only with what has changed.
364: */
365: bzero((void*)&t, sizeof(t));
366: t.c_cflag = cs->cs_defcflag;
367: if (zst->zst_swflags & TIOCFLAG_CLOCAL)
368: t.c_cflag |= CLOCAL;
369: if (zst->zst_swflags & TIOCFLAG_CRTSCTS)
370: t.c_cflag |= CRTSCTS;
371: if (zst->zst_swflags & TIOCFLAG_MDMBUF)
372: t.c_cflag |= MDMBUF;
373: t.c_ospeed = cs->cs_defspeed;
374: /* Enable interrupts. */
375: cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE;
376: /* Make sure zsparam will see changes. */
377: tp->t_ospeed = 0;
378: (void) zsparam(tp, &t);
379: /*
380: * Note: zsparam has done: cflag, ispeed, ospeed
381: * so we just need to do: iflag, oflag, lflag, cc
382: * For "raw" mode, just leave all zeros.
383: */
384: if ((zst->zst_hwflags & ZS_HWFLAG_RAW) == 0) {
385: tp->t_iflag = TTYDEF_IFLAG;
386: tp->t_oflag = TTYDEF_OFLAG;
387: tp->t_lflag = TTYDEF_LFLAG;
388: ttychars(tp);
389: }
390: ttsetwater(tp);
391: /* Flush any pending input. */
392: zst->zst_rbget = zst->zst_rbput;
393: zs_iflush(cs); /* XXX */
394: /* DTR was turned on by zsparam. */
395: if (zst->zst_swflags & TIOCFLAG_SOFTCAR) {
396: tp->t_state |= TS_CARR_ON;
397: }
398: /* XXX - The MD code could just force CLOCAL instead. */
399: if (zst->zst_hwflags & ZS_HWFLAG_NO_DCD) {
400: tp->t_state |= TS_CARR_ON;
401: }
402: }
403: error = 0;
404:
405: /* In this section, we may touch the chip. */
406: (void)splzs();
407:
408: /*
409: * Get initial value of RR0. This is done after we
410: * raise DTR in case the cable loops DTR back to CTS.
411: */
412: cs->cs_rr0 = zs_read_csr(cs);
413:
414: /*
415: * Wait for DCD (if necessary). Note that we might
416: * never get status interrupt if DCD is already on.
417: */
418: for (;;) {
419: /* Check the DCD bit (if we have one). */
420: if (cs->cs_rr0 & cs->cs_rr0_dcd)
421: tp->t_state |= TS_CARR_ON;
422:
423: if ((tp->t_state & TS_CARR_ON) ||
424: (tp->t_cflag & CLOCAL) ||
425: (flags & O_NONBLOCK) )
426: break;
427:
428: /* Sleep waiting for a status interrupt. */
429: tp->t_state |= TS_WOPEN;
430: error = ttysleep(tp, (caddr_t)&tp->t_rawq,
431: TTIPRI | PCATCH, ttopen, 0);
432: if (error) {
433: if ((tp->t_state & TS_ISOPEN) == 0) {
434: /* Never get here with softcar */
435: zs_modem(zst, 0);
436: tp->t_state &= ~TS_WOPEN;
437: ttwakeup(tp);
438: }
439: break;
440: }
441: /* The status interrupt changed cs->cs_rr0 */
442: }
443:
444: splx(s);
445: if (error == 0)
446: error = linesw[tp->t_line].l_open(dev, tp);
447: return (error);
448: }
449:
450: /*
451: * Close a zs serial port.
452: */
453: int
454: zsclose(dev, flags, mode, p)
455: dev_t dev;
456: int flags;
457: int mode;
458: struct proc *p;
459: {
460: struct zstty_softc *zst;
461: register struct zs_chanstate *cs;
462: register struct tty *tp;
463: int hup, s;
464:
465: zst = zstty_cd.cd_devs[minor(dev)];
466: cs = zst->zst_cs;
467: tp = zst->zst_tty;
468:
469: /* XXX This is for cons.c. */
470: if ((tp->t_state & TS_ISOPEN) == 0)
471: return 0;
472:
473: (*linesw[tp->t_line].l_close)(tp, flags);
474:
475: /* Disable interrupts. */
476: s = splzs();
477: cs->cs_creg[1] = cs->cs_preg[1] = 0;
478: zs_write_reg(cs, 1, cs->cs_creg[1]);
479: splx(s);
480:
481: /* Maybe do "hangup" (drop DTR). */
482: hup = tp->t_cflag & HUPCL;
483: if (zst->zst_swflags & TIOCFLAG_SOFTCAR)
484: hup = 0;
485: if (hup) {
486: zs_modem(zst, 0);
487: /* hold low for 1 second */
488: (void) tsleep((caddr_t)cs, TTIPRI, ttclos, hz);
489: }
490: if (cs->cs_creg[5] & ZSWR5_BREAK) {
491: zs_break(cs, 0);
492: }
493:
494: ttyclose(tp);
495: return (0);
496: }
497:
498: /*
499: * Read/write zs serial port.
500: */
501: int
502: zsread(dev, uio, flags)
503: dev_t dev;
504: struct uio *uio;
505: int flags;
506: {
507: register struct zstty_softc *zst;
508: register struct tty *tp;
509:
510: zst = zstty_cd.cd_devs[minor(dev)];
511: tp = zst->zst_tty;
512: return (linesw[tp->t_line].l_read(tp, uio, flags));
513: }
514:
515: int
516: zswrite(dev, uio, flags)
517: dev_t dev;
518: struct uio *uio;
519: int flags;
520: {
521: register struct zstty_softc *zst;
522: register struct tty *tp;
523:
524: zst = zstty_cd.cd_devs[minor(dev)];
525: tp = zst->zst_tty;
526: return (linesw[tp->t_line].l_write(tp, uio, flags));
527: }
528:
529: #define TIOCFLAG_ALL (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | \
530: TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF )
531:
532: int
533: zsioctl(dev, cmd, data, flag, p)
534: dev_t dev;
535: u_long cmd;
536: caddr_t data;
537: int flag;
538: struct proc *p;
539: {
540: register struct zstty_softc *zst;
541: register struct zs_chanstate *cs;
542: register struct tty *tp;
543: register int error, tmp;
544:
545: zst = zstty_cd.cd_devs[minor(dev)];
546: cs = zst->zst_cs;
547: tp = zst->zst_tty;
548:
549: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
550: if (error >= 0)
551: return (error);
552: error = ttioctl(tp, cmd, data, flag, p);
553: if (error >= 0)
554: return (error);
555:
556: #ifdef ZS_MD_IOCTL
557: error = ZS_MD_IOCTL;
558: if (error >= 0)
559: return (error);
560: #endif /* ZS_MD_IOCTL */
561:
562: switch (cmd) {
563:
564: case TIOCSBRK:
565: zs_break(cs, 1);
566: break;
567:
568: case TIOCCBRK:
569: zs_break(cs, 0);
570: break;
571:
572: case TIOCGFLAGS:
573: *(int *)data = zst->zst_swflags;
574: break;
575:
576: case TIOCSFLAGS:
577: error = suser(p, 0);
578: if (error != 0)
579: return (EPERM);
580: tmp = *(int *)data;
581: /* Check for random bits... */
582: if (tmp & ~TIOCFLAG_ALL)
583: return(EINVAL);
584: /* Silently enforce softcar on the console. */
585: if (zst->zst_hwflags & ZS_HWFLAG_CONSOLE)
586: tmp |= TIOCFLAG_SOFTCAR;
587: /* These flags take effect during open. */
588: zst->zst_swflags = tmp;
589: break;
590:
591: case TIOCSDTR:
592: zs_modem(zst, 1);
593: break;
594:
595: case TIOCCDTR:
596: zs_modem(zst, 0);
597: break;
598:
599: case TIOCMSET:
600: case TIOCMBIS:
601: case TIOCMBIC:
602: case TIOCMGET:
603: default:
604: return (ENOTTY);
605: }
606: return (0);
607: }
608:
609: /*
610: * Start or restart transmission.
611: */
612: static void
613: zsstart(tp)
614: register struct tty *tp;
615: {
616: register struct zstty_softc *zst;
617: register struct zs_chanstate *cs;
618: register int s, nch;
619:
620: zst = zstty_cd.cd_devs[minor(tp->t_dev)];
621: cs = zst->zst_cs;
622:
623: s = spltty();
624:
625: /*
626: * If currently active or delaying, no need to do anything.
627: */
628: if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
629: goto out;
630:
631: /*
632: * If under CRTSCTS hfc and halted, do nothing
633: * This flag can only be set with CRTSCTS.
634: */
635: if (zst->zst_tx_stopped)
636: goto out;
637:
638: /*
639: * If there are sleepers, and output has drained below low
640: * water mark, awaken.
641: */
642: if (tp->t_outq.c_cc <= tp->t_lowat) {
643: if (tp->t_state & TS_ASLEEP) {
644: tp->t_state &= ~TS_ASLEEP;
645: wakeup((caddr_t)&tp->t_outq);
646: }
647: selwakeup(&tp->t_wsel);
648: }
649:
650: nch = ndqb(&tp->t_outq, 0); /* XXX */
651: (void) splzs();
652:
653: if (nch) {
654: register char *p = tp->t_outq.c_cf;
655:
656: /* mark busy, enable tx done interrupts, & send first byte */
657: tp->t_state |= TS_BUSY;
658: zst->zst_tx_busy = 1;
659: cs->cs_preg[1] |= ZSWR1_TIE;
660: cs->cs_creg[1] = cs->cs_preg[1];
661: zs_write_reg(cs, 1, cs->cs_creg[1]);
662: zs_write_data(cs, *p);
663: zst->zst_tba = p + 1;
664: zst->zst_tbc = nch - 1;
665: } else {
666: /*
667: * Nothing to send, turn off transmit done interrupts.
668: * This is useful if something is doing polled output.
669: */
670: cs->cs_preg[1] &= ~ZSWR1_TIE;
671: cs->cs_creg[1] = cs->cs_preg[1];
672: zs_write_reg(cs, 1, cs->cs_creg[1]);
673: }
674: out:
675: splx(s);
676: }
677:
678: /*
679: * Stop output, e.g., for ^S or output flush.
680: */
681: int
682: zsstop(tp, flag)
683: struct tty *tp;
684: int flag;
685: {
686: register struct zstty_softc *zst;
687: register struct zs_chanstate *cs;
688: register int s;
689:
690: zst = zstty_cd.cd_devs[minor(tp->t_dev)];
691: cs = zst->zst_cs;
692:
693: s = splzs();
694: if (tp->t_state & TS_BUSY) {
695: /*
696: * Device is transmitting; must stop it.
697: * Also clear _heldtbc to prevent any
698: * flow-control event from resuming.
699: */
700: zst->zst_tbc = 0;
701: zst->zst_heldtbc = 0;
702: if ((tp->t_state & TS_TTSTOP) == 0)
703: tp->t_state |= TS_FLUSH;
704: }
705: splx(s);
706: return (0);
707: }
708:
709: /*
710: * Set ZS tty parameters from termios.
711: * XXX - Should just copy the whole termios after
712: * making sure all the changes could be done.
713: */
714: static int
715: zsparam(tp, t)
716: register struct tty *tp;
717: register struct termios *t;
718: {
719: struct zstty_softc *zst;
720: struct zs_chanstate *cs;
721: int s, bps, cflag, error;
722: u_char tmp3, tmp4, tmp5;
723:
724: zst = zstty_cd.cd_devs[minor(tp->t_dev)];
725: cs = zst->zst_cs;
726: bps = t->c_ospeed;
727: cflag = t->c_cflag;
728:
729: if (bps < 0 || (t->c_ispeed && t->c_ispeed != bps))
730: return (EINVAL);
731:
732: /*
733: * Only whack the UART when params change.
734: * Some callers need to clear tp->t_ospee
735: * to make sure initialization gets done.
736: */
737: if ((tp->t_ospeed == bps) &&
738: (tp->t_cflag == cflag) )
739: return (0);
740:
741: /*
742: * Call MD functions to deal with changed
743: * clock modes or H/W flow control modes.
744: * The BRG divisor is set now. (reg 12,13
745: */
746:
747: error = zs_set_speed(cs, bps);
748: if (error)
749: return (error);
750: error = zs_set_modes(cs, cflag);
751: if (error)
752: return (error);
753:
754: /* OK, we are now committed to do it. */
755: tp->t_cflag = cflag;
756: tp->t_ospeed = bps;
757: tp->t_ispeed = bps;
758:
759: /*
760: * Block interrupts so that state will not
761: * be altered until we are done setting it up.
762: *
763: * Initial values in cs_preg are set before
764: * our attach routine is called. The master
765: * interrupt enable is handled by zsc.c
766: */
767: s = splzs();
768:
769: /* Recompute character size bits. */
770: tmp3 = cs->cs_preg[3] & ~ZSWR3_RXSIZE;
771: tmp5 = cs->cs_preg[5] & ~ZSWR5_TXSIZE;
772: switch (cflag & CSIZE) {
773: case CS5:
774: /* These are |= 0 but let the optimizer deal with it. */
775: tmp3 |= ZSWR3_RX_5;
776: tmp5 |= ZSWR5_TX_5;
777: break;
778: case CS6:
779: tmp3 |= ZSWR3_RX_6;
780: tmp5 |= ZSWR5_TX_6;
781: break;
782: case CS7:
783: tmp3 |= ZSWR3_RX_7;
784: tmp5 |= ZSWR5_TX_7;
785: break;
786: case CS8:
787: default:
788: tmp3 |= ZSWR3_RX_8;
789: tmp5 |= ZSWR5_TX_8;
790: break;
791: }
792: /* Raise or lower DTR and RTS as appropriate. */
793: if (bps) {
794: /* Raise DTR and RTS */
795: tmp5 |= cs->cs_wr5_dtr;
796: } else {
797: /* Drop DTR and RTS */
798: /* XXX: Should SOFTCAR prevent this? */
799: tmp5 &= ~(cs->cs_wr5_dtr);
800: }
801: cs->cs_preg[3] = tmp3;
802: cs->cs_preg[5] = tmp5;
803:
804: /*
805: * Recompute the stop bits and parity bits. Note that
806: * zs_set_speed() may have set clock selection bits etc.
807: * in wr4, so those must preserved.
808: */
809: tmp4 = cs->cs_preg[4];
810: /* Recompute stop bits. */
811: tmp4 &= ~ZSWR4_SBMASK;
812: tmp4 |= (cflag & CSTOPB) ?
813: ZSWR4_TWOSB : ZSWR4_ONESB;
814: /* Recompute parity bits. */
815: tmp4 &= ~ZSWR4_PARMASK;
816: if ((cflag & PARODD) == 0)
817: tmp4 |= ZSWR4_EVENP;
818: if (cflag & PARENB)
819: tmp4 |= ZSWR4_PARENB;
820: cs->cs_preg[4] = tmp4;
821:
822: /* The MD function zs_set_modes handled CRTSCTS, etc. */
823:
824: /*
825: * If nothing is being transmitted, set up new current values,
826: * else mark them as pending.
827: */
828: if (cs->cs_heldchange == 0) {
829: if (zst->zst_tx_busy) {
830: zst->zst_heldtbc = zst->zst_tbc;
831: zst->zst_tbc = 0;
832: cs->cs_heldchange = 0xFFFF;
833: } else {
834: zs_loadchannelregs(cs);
835: }
836: }
837: splx(s);
838:
839: /* If we can throttle input, enable "high water" detection. */
840: if (cflag & CHWFLOW) {
841: zst->zst_rbhiwat = zstty_rbuf_hiwat;
842: } else {
843: /* This impossible value prevents a "high water" trigger. */
844: zst->zst_rbhiwat = zstty_rbuf_size;
845: /* XXX: Lost hwi ability, so unblock and restart. */
846: zst->zst_rx_blocked = 0;
847: if (zst->zst_tx_stopped) {
848: zst->zst_tx_stopped = 0;
849: zsstart(tp);
850: }
851: }
852:
853: return (0);
854: }
855:
856: /*
857: * Raise or lower modem control (DTR/RTS) signals. If a character is
858: * in transmission, the change is deferred.
859: */
860: static void
861: zs_modem(zst, onoff)
862: struct zstty_softc *zst;
863: int onoff;
864: {
865: struct zs_chanstate *cs;
866: int s, clr, set;
867:
868: cs = zst->zst_cs;
869: if (cs->cs_wr5_dtr == 0)
870: return;
871:
872: if (onoff) {
873: clr = 0;
874: set = cs->cs_wr5_dtr;
875: } else {
876: clr = cs->cs_wr5_dtr;
877: set = 0;
878: }
879:
880: s = splzs();
881: cs->cs_preg[5] &= ~clr;
882: cs->cs_preg[5] |= set;
883: if (cs->cs_heldchange == 0) {
884: if (zst->zst_tx_busy) {
885: zst->zst_heldtbc = zst->zst_tbc;
886: zst->zst_tbc = 0;
887: cs->cs_heldchange = (1<<5);
888: } else {
889: cs->cs_creg[5] = cs->cs_preg[5];
890: zs_write_reg(cs, 5, cs->cs_creg[5]);
891: }
892: }
893: splx(s);
894: }
895:
896: /*
897: * Try to block or unblock input using hardware flow-control.
898: * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
899: * if this function returns non-zero, the TS_TBLOCK flag will
900: * be set or cleared according to the "stop" arg passed.
901: */
902: int
903: zshwiflow(tp, stop)
904: struct tty *tp;
905: int stop;
906: {
907: register struct zstty_softc *zst;
908: register struct zs_chanstate *cs;
909: int s;
910:
911: zst = zstty_cd.cd_devs[minor(tp->t_dev)];
912: cs = zst->zst_cs;
913:
914: /* Can not do this without some bit assigned as RTS. */
915: if (cs->cs_wr5_rts == 0)
916: return (0);
917:
918: s = splzs();
919: if (stop) {
920: /*
921: * The tty layer is asking us to block input.
922: * If we already did it, just return TRUE.
923: */
924: if (zst->zst_rx_blocked)
925: goto out;
926: zst->zst_rx_blocked = 1;
927: } else {
928: /*
929: * The tty layer is asking us to resume input.
930: * The input ring is always empty by now.
931: */
932: zst->zst_rx_blocked = 0;
933: }
934: zs_hwiflow(zst, stop);
935: out:
936: splx(s);
937: return 1;
938: }
939:
940: /*
941: * Internal version of zshwiflow
942: * called at splzs
943: */
944: static void
945: zs_hwiflow(zst, stop)
946: register struct zstty_softc *zst;
947: int stop;
948: {
949: register struct zs_chanstate *cs;
950: register int clr, set;
951:
952: cs = zst->zst_cs;
953:
954: if (cs->cs_wr5_rts == 0)
955: return;
956:
957: if (stop) {
958: /* Block input (Lower RTS) */
959: clr = cs->cs_wr5_rts;
960: set = 0;
961: } else {
962: /* Unblock input (Raise RTS) */
963: clr = 0;
964: set = cs->cs_wr5_rts;
965: }
966:
967: cs->cs_preg[5] &= ~clr;
968: cs->cs_preg[5] |= set;
969: if (cs->cs_heldchange == 0) {
970: if (zst->zst_tx_busy) {
971: zst->zst_heldtbc = zst->zst_tbc;
972: zst->zst_tbc = 0;
973: cs->cs_heldchange = (1<<5);
974: } else {
975: cs->cs_creg[5] = cs->cs_preg[5];
976: zs_write_reg(cs, 5, cs->cs_creg[5]);
977: }
978: }
979: }
980:
981:
982: /****************************************************************
983: * Interface to the lower layer (zscc)
984: ****************************************************************/
985:
986: static void zstty_rxint (struct zs_chanstate *);
987: static void zstty_txint (struct zs_chanstate *);
988: static void zstty_stint (struct zs_chanstate *);
989:
990: /*
991: * receiver ready interrupt.
992: * called at splzs
993: */
994: static void
995: zstty_rxint(cs)
996: register struct zs_chanstate *cs;
997: {
998: register struct zstty_softc *zst;
999: register int cc, put, put_next, ringmask;
1000: register u_char c, rr0, rr1;
1001: register u_short ch_rr1;
1002:
1003: zst = cs->cs_private;
1004: put = zst->zst_rbput;
1005: ringmask = zst->zst_ringmask;
1006:
1007: nextchar:
1008:
1009: /*
1010: * First read the status, because reading the received char
1011: * destroys the status of this char.
1012: */
1013: rr1 = zs_read_reg(cs, 1);
1014: c = zs_read_data(cs);
1015: ch_rr1 = (c << 8) | rr1;
1016:
1017: if (ch_rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) {
1018: /* Clear the receive error. */
1019: zs_write_csr(cs, ZSWR0_RESET_ERRORS);
1020: }
1021:
1022: /* XXX: Check for the stop character? */
1023:
1024: zst->zst_rbuf[put] = ch_rr1;
1025: put_next = (put + 1) & ringmask;
1026:
1027: /* Would overrun if increment makes (put==get). */
1028: if (put_next == zst->zst_rbget) {
1029: zst->zst_rx_overrun = 1;
1030: } else {
1031: /* OK, really increment. */
1032: put = put_next;
1033: }
1034:
1035: /* Keep reading until the FIFO is empty. */
1036: rr0 = zs_read_csr(cs);
1037: if (rr0 & ZSRR0_RX_READY)
1038: goto nextchar;
1039:
1040: /* Done reading. */
1041: zst->zst_rbput = put;
1042:
1043: /*
1044: * If ring is getting too full, try to block input.
1045: */
1046: cc = put - zst->zst_rbget;
1047: if (cc < 0)
1048: cc += zstty_rbuf_size;
1049: if ((cc > zst->zst_rbhiwat) && (zst->zst_rx_blocked == 0)) {
1050: zst->zst_rx_blocked = 1;
1051: zs_hwiflow(zst, 1);
1052: }
1053:
1054: /* Ask for softint() call. */
1055: cs->cs_softreq = 1;
1056: }
1057:
1058: /*
1059: * transmitter ready interrupt. (splzs)
1060: */
1061: static void
1062: zstty_txint(cs)
1063: register struct zs_chanstate *cs;
1064: {
1065: register struct zstty_softc *zst;
1066: register int count;
1067:
1068: zst = cs->cs_private;
1069:
1070: /*
1071: * If we suspended output for a "held" change,
1072: * then handle that now and resume.
1073: * Do flow-control changes ASAP.
1074: * When the only change is for flow control,
1075: * avoid hitting other registers, because that
1076: * often makes the stupid zs drop input...
1077: */
1078: if (cs->cs_heldchange) {
1079: if (cs->cs_heldchange == (1<<5)) {
1080: /* Avoid whacking the chip... */
1081: cs->cs_creg[5] = cs->cs_preg[5];
1082: zs_write_reg(cs, 5, cs->cs_creg[5]);
1083: } else
1084: zs_loadchannelregs(cs);
1085: cs->cs_heldchange = 0;
1086: count = zst->zst_heldtbc;
1087: } else
1088: count = zst->zst_tbc;
1089:
1090: /*
1091: * If our transmit buffer still has data,
1092: * just send the next character.
1093: */
1094: if (count > 0) {
1095: /* Send the next char. */
1096: zst->zst_tbc = --count;
1097: zs_write_data(cs, *zst->zst_tba);
1098: zst->zst_tba++;
1099: return;
1100: }
1101:
1102: zs_write_csr(cs, ZSWR0_RESET_TXINT);
1103:
1104: /* Ask the softint routine for more output. */
1105: zst->zst_tx_busy = 0;
1106: zst->zst_tx_done = 1;
1107: cs->cs_softreq = 1;
1108: }
1109:
1110: /*
1111: * status change interrupt. (splzs)
1112: */
1113: static void
1114: zstty_stint(cs)
1115: register struct zs_chanstate *cs;
1116: {
1117: register struct zstty_softc *zst;
1118: register u_char rr0, delta;
1119:
1120: zst = cs->cs_private;
1121:
1122: rr0 = zs_read_csr(cs);
1123: zs_write_csr(cs, ZSWR0_RESET_STATUS);
1124:
1125: /*
1126: * Check here for console break, so that we can abort
1127: * even when interrupts are locking up the machine.
1128: */
1129: if ((rr0 & ZSRR0_BREAK) &&
1130: (zst->zst_hwflags & ZS_HWFLAG_CONSOLE))
1131: {
1132: zs_abort(cs);
1133: return;
1134: }
1135:
1136: /*
1137: * We have to accumulate status line changes here.
1138: * Otherwise, if we get multiple status interrupts
1139: * before the softint runs, we could fail to notice
1140: * some status line changes in the softint routine.
1141: * Fix from Bill Studenmund, October 1996.
1142: */
1143: delta = (cs->cs_rr0 ^ rr0);
1144: cs->cs_rr0_delta |= delta;
1145: cs->cs_rr0 = rr0;
1146:
1147: /*
1148: * Need to handle CTS output flow control here.
1149: * Output remains stopped as long as either the
1150: * zst_tx_stopped or TS_TTSTOP flag is set.
1151: * Never restart here; the softint routine will
1152: * do that after things are ready to move.
1153: */
1154: if ((delta & cs->cs_rr0_cts) &&
1155: ((rr0 & cs->cs_rr0_cts) == 0))
1156: {
1157: zst->zst_tbc = 0;
1158: zst->zst_heldtbc = 0;
1159: zst->zst_tx_stopped = 1;
1160: }
1161: zst->zst_st_check = 1;
1162:
1163: /* Ask for softint() call. */
1164: cs->cs_softreq = 1;
1165: }
1166:
1167: /*
1168: * Print out a ring or fifo overrun error message.
1169: */
1170: static void
1171: zsoverrun(zst, ptime, what)
1172: struct zstty_softc *zst;
1173: long *ptime;
1174: char *what;
1175: {
1176:
1177: if (*ptime != time_second) {
1178: *ptime = time_second;
1179: log(LOG_WARNING, "%s: %s overrun\n",
1180: zst->zst_dev.dv_xname, what);
1181: }
1182: }
1183:
1184: /*
1185: * Software interrupt. Called at zssoft
1186: *
1187: * The main job to be done here is to empty the input ring
1188: * by passing its contents up to the tty layer. The ring is
1189: * always emptied during this operation, therefore the ring
1190: * must not be larger than the space after "high water" in
1191: * the tty layer, or the tty layer might drop our input.
1192: *
1193: * Note: an "input blockage" condition is assumed to exist if
1194: * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set.
1195: */
1196: static void
1197: zstty_softint(cs)
1198: struct zs_chanstate *cs;
1199: {
1200: register struct zstty_softc *zst;
1201: register struct linesw *line;
1202: register struct tty *tp;
1203: register int get, c, s;
1204: int ringmask, overrun;
1205: register u_short ring_data;
1206: register u_char rr0, delta;
1207:
1208: zst = cs->cs_private;
1209: tp = zst->zst_tty;
1210: line = &linesw[tp->t_line];
1211: ringmask = zst->zst_ringmask;
1212: overrun = 0;
1213:
1214: /*
1215: * Raise to tty priority while servicing the ring.
1216: */
1217: s = spltty();
1218:
1219: if (zst->zst_rx_overrun) {
1220: zst->zst_rx_overrun = 0;
1221: zsoverrun(zst, &zst->zst_rotime, "ring");
1222: }
1223:
1224: /*
1225: * Copy data from the receive ring into the tty layer.
1226: */
1227: get = zst->zst_rbget;
1228: while (get != zst->zst_rbput) {
1229: ring_data = zst->zst_rbuf[get];
1230: get = (get + 1) & ringmask;
1231:
1232: if (ring_data & ZSRR1_DO)
1233: overrun++;
1234: /* low byte of ring_data is rr1 */
1235: c = (ring_data >> 8) & 0xff;
1236: if (ring_data & ZSRR1_FE)
1237: c |= TTY_FE;
1238: if (ring_data & ZSRR1_PE)
1239: c |= TTY_PE;
1240:
1241: line->l_rint(c, tp);
1242: }
1243: zst->zst_rbget = get;
1244:
1245: /*
1246: * If the overrun flag is set now, it was set while
1247: * copying char/status pairs from the ring, which
1248: * means this was a hardware (fifo) overrun.
1249: */
1250: if (overrun) {
1251: zsoverrun(zst, &zst->zst_fotime, "fifo");
1252: }
1253:
1254: /*
1255: * We have emptied the input ring. Maybe unblock input.
1256: * Note: an "input blockage" condition is assumed to exist
1257: * when EITHER zst_rx_blocked or the TS_TBLOCK flag is set,
1258: * so unblock here ONLY if TS_TBLOCK has not been set.
1259: */
1260: if (zst->zst_rx_blocked && ((tp->t_state & TS_TBLOCK) == 0)) {
1261: (void) splzs();
1262: zst->zst_rx_blocked = 0;
1263: zs_hwiflow(zst, 0); /* unblock input */
1264: (void) spltty();
1265: }
1266:
1267: /*
1268: * Do any deferred work for status interrupts.
1269: * The rr0 was saved in the h/w interrupt to
1270: * avoid another splzs in here.
1271: */
1272: if (zst->zst_st_check) {
1273: zst->zst_st_check = 0;
1274:
1275: (void) splzs();
1276: rr0 = cs->cs_rr0;
1277: delta = cs->cs_rr0_delta;
1278: cs->cs_rr0_delta = 0;
1279: (void) spltty();
1280:
1281: /* Note, the MD code may use DCD for something else. */
1282: if (delta & cs->cs_rr0_dcd) {
1283: c = ((rr0 & cs->cs_rr0_dcd) != 0);
1284: if (line->l_modem(tp, c) == 0)
1285: zs_modem(zst, c);
1286: }
1287:
1288: /* Note, cs_rr0_cts is set only with H/W flow control. */
1289: if (delta & cs->cs_rr0_cts) {
1290: /*
1291: * Only do restart here. Stop is handled
1292: * at the h/w interrupt level.
1293: */
1294: if (rr0 & cs->cs_rr0_cts) {
1295: zst->zst_tx_stopped = 0;
1296: /* tp->t_state &= ~TS_TTSTOP; */
1297: (*line->l_start)(tp);
1298: }
1299: }
1300: }
1301:
1302: if (zst->zst_tx_done) {
1303: zst->zst_tx_done = 0;
1304: tp->t_state &= ~TS_BUSY;
1305: if (tp->t_state & TS_FLUSH)
1306: tp->t_state &= ~TS_FLUSH;
1307: else
1308: ndflush(&tp->t_outq, zst->zst_tba -
1309: (caddr_t) tp->t_outq.c_cf);
1310: line->l_start(tp);
1311: }
1312:
1313: splx(s);
1314: }
1315:
1316: struct zsops zsops_tty = {
1317: zstty_rxint, /* receive char available */
1318: zstty_stint, /* external/status */
1319: zstty_txint, /* xmit buffer empty */
1320: zstty_softint, /* process software interrupt */
1321: };
1322:
CVSweb