Annotation of sys/arch/mac68k/dev/z8530tty.c, Revision 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