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