[BACK]Return to z8530tty.c CVS log [TXT][DIR] Up to [local] / sys / arch / mac68k / dev

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