root/dev/ic/z8530tty.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. zstty_match
  2. zstty_attach
  3. zstty
  4. zsopen
  5. zsclose
  6. zsread
  7. zswrite
  8. zsioctl
  9. zsstart
  10. zsstop
  11. zsparam
  12. zs_modem
  13. zshwiflow
  14. zs_hwiflow
  15. zstty_rxint
  16. zstty_txint
  17. zstty_stint
  18. zsoverrun
  19. zstty_softint

    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 

/* [<][>][^][v][top][bottom][index][help] */