The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/cd18xx.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: cd18xx.c,v 1.26 2008/06/12 22:30:30 cegger Exp $       */
    2 
    3 /* XXXad does this even compile? */
    4 
    5 /*
    6  * Copyright (c) 1998, 2001 Matthew R. Green
    7  * All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  *
   18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   28  * SUCH DAMAGE.
   29  */
   30 
   31 /*-
   32  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
   33  * All rights reserved.
   34  *
   35  * This code is derived from software contributed to The NetBSD Foundation
   36  * by Charles M. Hannum.
   37  *
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  *
   47  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   48  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   49  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   50  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   51  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   52  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   53  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   54  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   55  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   56  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   57  * POSSIBILITY OF SUCH DAMAGE.
   58  */
   59 
   60 /*
   61  * Copyright (c) 1991 The Regents of the University of California.
   62  * All rights reserved.
   63  *
   64  * Redistribution and use in source and binary forms, with or without
   65  * modification, are permitted provided that the following conditions
   66  * are met:
   67  * 1. Redistributions of source code must retain the above copyright
   68  *    notice, this list of conditions and the following disclaimer.
   69  * 2. Redistributions in binary form must reproduce the above copyright
   70  *    notice, this list of conditions and the following disclaimer in the
   71  *    documentation and/or other materials provided with the distribution.
   72  * 3. Neither the name of the University nor the names of its contributors
   73  *    may be used to endorse or promote products derived from this software
   74  *    without specific prior written permission.
   75  *
   76  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   77  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   78  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   79  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   80  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   81  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   82  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   83  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   84  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   85  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   86  * SUCH DAMAGE.
   87  *
   88  *      @(#)com.c       7.5 (Berkeley) 5/16/91
   89  */
   90 
   91 /*
   92  * cirrus logic CL-CD180/CD1864/CD1865 driver, based in (large) parts on
   93  * the com and z8530 drivers.  thanks charles.
   94  */
   95 
   96 #include <sys/cdefs.h>
   97 __KERNEL_RCSID(0, "$NetBSD: cd18xx.c,v 1.26 2008/06/12 22:30:30 cegger Exp $");
   98 
   99 #include <sys/param.h>
  100 #include <sys/conf.h>
  101 #include <sys/device.h>
  102 #include <sys/systm.h>
  103 #include <sys/malloc.h>
  104 #include <sys/proc.h>
  105 #include <sys/kernel.h>
  106 #include <sys/tty.h>
  107 #include <sys/fcntl.h>
  108 #include <sys/kauth.h>
  109 #include <sys/intr.h>
  110 
  111 #include <sys/bus.h>
  112 
  113 #include <dev/ic/cd18xxvar.h>
  114 #include <dev/ic/cd18xxreg.h>
  115 
  116 #include "ioconf.h"
  117 
  118 /*
  119  * some helpers
  120  */
  121 
  122 /* macros to clear/set/test flags. */
  123 #define SET(t, f)       (t) |= (f)
  124 #define CLR(t, f)       (t) &= ~(f)
  125 #define ISSET(t, f)     ((t) & (f))
  126 
  127 static void     cdtty_attach(struct cd18xx_softc *, int);
  128 
  129 static inline void cd18xx_rint(struct cd18xx_softc *, int *);
  130 static inline void cd18xx_tint(struct cd18xx_softc *, int *);
  131 static inline void cd18xx_mint(struct cd18xx_softc *, int *);
  132 
  133 void cdtty_rxsoft(struct cd18xx_softc *, struct cdtty_port *, struct tty *);
  134 void cdtty_txsoft(struct cd18xx_softc *, struct cdtty_port *, struct tty *);
  135 void cdtty_stsoft(struct cd18xx_softc *, struct cdtty_port *, struct tty *);
  136 void cd18xx_softintr(void *);
  137 
  138 dev_type_open(cdttyopen);
  139 dev_type_close(cdttyclose);
  140 dev_type_read(cdttyread);
  141 dev_type_write(cdttywrite);
  142 dev_type_ioctl(cdttyioctl);
  143 dev_type_stop(cdttystop);
  144 dev_type_tty(cdttytty);
  145 dev_type_poll(cdttypoll);
  146 
  147 const struct cdevsw cdtty_cdevsw = {
  148         cdttyopen, cdttyclose, cdttyread, cdttywrite, cdttyioctl,
  149         cdttystop, cdttytty, cdttypoll, nommap, ttykqfilter, D_TTY
  150 };
  151 
  152 static void     cdtty_shutdown(struct cd18xx_softc *, struct cdtty_port *);
  153 static void     cdttystart(struct tty *);
  154 static int      cdttyparam(struct tty *, struct termios *);
  155 static void     cdtty_break(struct cd18xx_softc *, struct cdtty_port *, int);
  156 static void     cdtty_modem(struct cd18xx_softc *, struct cdtty_port *, int);
  157 static int      cdttyhwiflow(struct tty *, int);
  158 static void     cdtty_hwiflow(struct cd18xx_softc *, struct cdtty_port *);
  159 
  160 static void     cdtty_loadchannelregs(struct cd18xx_softc *,
  161                                            struct cdtty_port *);
  162 
  163 /* default read buffer size */
  164 u_int cdtty_rbuf_size = CDTTY_RING_SIZE;
  165 
  166 /* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */
  167 u_int cdtty_rbuf_hiwat = (CDTTY_RING_SIZE * 1) / 4;
  168 u_int cdtty_rbuf_lowat = (CDTTY_RING_SIZE * 3) / 4;
  169 
  170 #define CD18XXDEBUG
  171 #ifdef CD18XXDEBUG
  172 #define CDD_INFO        0x0001
  173 #define CDD_INTR        0x0002
  174 int cd18xx_debug = CDD_INTR|CDD_INFO;
  175 # define DPRINTF(l, x)  if (cd18xx_debug & l) printf x
  176 #else
  177 # define DPRINTF(l, x)  /* nothing */
  178 #endif
  179 
  180 /* Known supported revisions. */
  181 struct cd18xx_revs {
  182         u_char  revision;
  183         u_char  onehundred_pin;
  184         char    *name;
  185 } cd18xx_revs[] = {
  186         { CD180_GFRCR_REV_B,            0, "CL-CD180 rev. B" },
  187         { CD180_GFRCR_REV_C,            0, "CL-CD180 rev. C" },
  188         { CD1864_GFRCR_REVISION_A,      1, "CL-CD1864 rev. A" },
  189         { CD1865_GFRCR_REVISION_A,      1, "CL-CD1865 rev. A" },
  190         { CD1865_GFRCR_REVISION_B,      1, "CL-CD1865 rev. B" },
  191         { CD1865_GFRCR_REVISION_C,      1, "CL-CD1865 rev. C" },
  192         { 0, 0, 0 }
  193 };
  194 
  195 /* wait for the CCR to go to zero */
  196 static inline int cd18xx_wait_ccr(struct cd18xx_softc *);
  197 static inline int
  198 cd18xx_wait_ccr(sc)
  199         struct cd18xx_softc *sc;
  200 {
  201         int i = 100000;
  202 
  203         while (--i &&
  204             bus_space_read_1(sc->sc_tag, sc->sc_handle, CD18xx_CCR) != 0)
  205                 ;
  206         return (i == 0);
  207 }
  208 
  209 /*
  210  * device attach routine, high-end portion
  211  */
  212 void
  213 cd18xx_attach(sc)
  214         struct cd18xx_softc *sc;
  215 {
  216         static int chip_id_next = 1;
  217         int onehundred_pin, revision, i, port;
  218 
  219         /* read and print the revision */
  220         revision = cd18xx_read(sc, CD18xx_GFRCR);
  221         onehundred_pin = ISSET(cd18xx_read(sc, CD18xx_SRCR),CD18xx_SRCR_PKGTYP);
  222         for (i = 0; cd18xx_revs[i].name; i++)
  223                 if (revision == cd18xx_revs[i].revision ||
  224                     onehundred_pin == cd18xx_revs[i].onehundred_pin) {
  225                         printf(": %s", cd18xx_revs[i].name);
  226                         break;
  227                 }
  228 
  229         if (cd18xx_revs[i].name == NULL) {
  230                 aprint_error_dev(&sc->sc_dev, "unknown revision, bailing.\n");
  231                 return;
  232         }
  233 
  234         /* prepare for reset */
  235         cd18xx_set_car(sc, 0);
  236         cd18xx_write(sc, CD18xx_GSVR, CD18xx_GSVR_CLEAR);
  237 
  238         /* wait for CCR to go to zero */
  239         if (cd18xx_wait_ccr(sc)) {
  240                 printf("cd18xx_attach: reset change command timed out\n");
  241                 return;
  242         }
  243 
  244         /* full reset of all channels */
  245         cd18xx_write(sc, CD18xx_CCR,
  246             CD18xx_CCR_RESET|CD18xx_CCR_RESET_HARD);
  247 
  248         /* loop until the GSVR is ready */
  249         i = 100000;
  250         while (--i && cd18xx_read(sc, CD18xx_GSVR) == CD18xx_GSVR_READY)
  251                 ;
  252         if (i == 0) {
  253                 aprint_normal("\n");
  254                 aprint_error_dev(&sc->sc_dev, "did not reset!\n");
  255                 return;
  256         }
  257 
  258         /* write the chip_id */
  259         sc->sc_chip_id = chip_id_next++;
  260 #ifdef DIAGNOSTIC
  261         if (sc->sc_chip_id > 31)
  262                 panic("more than 31 cd18xx's?  help.");
  263 #endif
  264         cd18xx_write(sc, CD18xx_GSVR, CD18xx_GSVR_SETID(sc));
  265 
  266         /* rx/tx/modem service match vectors, initalised by higher level */
  267         cd18xx_write(sc, CD18xx_MSMR, sc->sc_msmr | 0x80);
  268         cd18xx_write(sc, CD18xx_TSMR, sc->sc_tsmr | 0x80);
  269         cd18xx_write(sc, CD18xx_RSMR, sc->sc_rsmr | 0x80);
  270 
  271         printf(", gsvr %x msmr %x tsmr %x rsmr %x",
  272             cd18xx_read(sc, CD18xx_GSVR),
  273             cd18xx_read(sc, CD18xx_MSMR),
  274             cd18xx_read(sc, CD18xx_TSMR),
  275             cd18xx_read(sc, CD18xx_RSMR));
  276 
  277         /* prescale registers */
  278         sc->sc_pprh = 0xf0;
  279         sc->sc_pprl = 0;
  280         cd18xx_write(sc, CD18xx_PPRH, sc->sc_pprh);
  281         cd18xx_write(sc, CD18xx_PPRL, sc->sc_pprl);
  282 
  283         /* establish our soft interrupt. */
  284         sc->sc_si = softint_establish(SOFTINT_SERIAL, cd18xx_softintr, sc);
  285 
  286         printf(", 8 ports ready (chip id %d)\n", sc->sc_chip_id);
  287 
  288         /*
  289          * finally, we loop over all 8 channels initialising them
  290          */
  291         for (port = 0; port < 8; port++)
  292                 cdtty_attach(sc, port);
  293 }
  294 
  295 /* tty portion of the code */
  296 
  297 /*
  298  * tty portion attach routine
  299  */
  300 void
  301 cdtty_attach(sc, port)
  302         struct  cd18xx_softc *sc;
  303         int port;
  304 {
  305         struct cdtty_port *p = &sc->sc_ports[port];
  306         int i;
  307 
  308         /* load CAR with channel number */
  309         cd18xx_set_car(sc, port);
  310 
  311         /* wait for CCR to go to zero */
  312         if (cd18xx_wait_ccr(sc)) {
  313                 printf("cd18xx_attach: change command timed out setting "
  314                        "CAR for port %d\n", i);
  315                 return;
  316         }
  317 
  318         /* set the RPTR to (arbitrary) 8 */
  319         cd18xx_write(sc, CD18xx_RTPR, 8);
  320 
  321         /* reset the modem signal value register */
  322         sc->sc_ports[port].p_msvr = CD18xx_MSVR_RESET;
  323 
  324         /* zero the service request enable register */
  325         cd18xx_write(sc, CD18xx_SRER, 0);
  326 
  327         /* enable the transmitter & receiver */
  328         SET(p->p_chanctl, CD18xx_CCR_CHANCTL |
  329                           CD18xx_CCR_CHANCTL_TxEN |
  330                           CD18xx_CCR_CHANCTL_RxEN);
  331 
  332         /* XXX no console or kgdb support yet! */
  333 
  334         /* get a tty structure */
  335         p->p_tty = ttymalloc();
  336         p->p_tty->t_oproc = cdttystart;
  337         p->p_tty->t_param = cdttyparam;
  338         p->p_tty->t_hwiflow = cdttyhwiflow;
  339 
  340         p->p_rbuf = malloc(cdtty_rbuf_size << 1, M_DEVBUF, M_WAITOK);
  341         p->p_rbput = p->p_rbget = p->p_rbuf;
  342         p->p_rbavail = cdtty_rbuf_size;
  343         if (p->p_rbuf == NULL) {
  344                 aprint_error_dev(&sc->sc_dev, "unable to allocate ring buffer for tty %d\n", port);
  345                 return;
  346         }
  347         p->p_ebuf = p->p_rbuf + (cdtty_rbuf_size << 1);
  348 
  349         tty_attach(p->p_tty);
  350 }
  351 
  352 /*
  353  * cdtty_shutdown: called when the device is last closed.
  354  */
  355 void
  356 cdtty_shutdown(sc, p)
  357         struct cd18xx_softc *sc;
  358         struct cdtty_port *p;
  359 {
  360         struct tty *tp = p->p_tty;
  361         int s;
  362 
  363         s = splserial();
  364 
  365         /* If we were asserting flow control, then deassert it. */
  366         SET(p->p_rx_flags, RX_IBUF_BLOCKED);
  367         cdtty_hwiflow(sc, p);
  368 
  369         /* Clear any break condition set with TIOCSBRK. */
  370         cdtty_break(sc, p, 0);
  371 
  372         /*
  373          * Hang up if necessary.  Wait a bit, so the other side has time to
  374          * notice even if we immediately open the port again.
  375          * Avoid tsleeping above splhigh().
  376          */
  377         if (ISSET(tp->t_cflag, HUPCL)) {
  378                 cdtty_modem(sc, p, 0);
  379                 splx(s);
  380                 /* XXX tsleep will only timeout */
  381                 (void) tsleep(sc, TTIPRI, ttclos, hz);
  382                 s = splserial();
  383         }
  384 
  385         /* Turn off interrupts. */
  386         p->p_srer = 0;
  387         cd18xx_write(sc, CD18xx_SRER, p->p_srer);
  388 
  389         splx(s);
  390 }
  391 
  392 /*
  393  * cdttyopen:  open syscall for cdtty terminals..
  394  */
  395 int
  396 cdttyopen(dev, flag, mode, p)
  397         dev_t dev;
  398         int flag;
  399         int mode;
  400         struct proc *p;
  401 {
  402         struct tty *tp;
  403         struct cd18xx_softc *sc;
  404         struct cdtty_port *port;
  405         int channel, instance, s, error;
  406 
  407         channel = CD18XX_CHANNEL(dev);
  408         instance = CD18XX_INSTANCE(dev);
  409 
  410         /* ensure instance is valid */
  411         if (instance >= clcd_cd.cd_ndevs)
  412                 return (ENXIO);
  413 
  414         /* get softc and port */
  415         sc = device_lookup_private(&clcd_cd, instance);
  416         if (sc == NULL)
  417                 return (ENXIO);
  418         port = &sc->sc_ports[channel];
  419         if (port == NULL || port->p_rbuf == NULL)
  420                 return (ENXIO);
  421 
  422         /* kgdb support?  maybe later... */
  423 
  424         tp = port->p_tty;
  425 
  426         if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
  427                 return (EBUSY);
  428 
  429         s = spltty();
  430 
  431         /*
  432          * Do the following iff this is a first open.
  433          */
  434         if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
  435                 struct termios t;
  436 
  437                 /* set up things in tp as necessary */
  438                 tp->t_dev = dev;
  439 
  440                 /*
  441                  * Initialize the termios status to the defaults.  Add in the
  442                  * sticky bits from TIOCSFLAGS.
  443                  */
  444                 t.c_ispeed = 0;
  445                 t.c_ospeed = TTYDEF_SPEED;
  446                 t.c_cflag = TTYDEF_CFLAG;
  447 
  448                 if (ISSET(port->p_swflags, TIOCFLAG_CLOCAL))
  449                         SET(t.c_cflag, CLOCAL);
  450                 if (ISSET(port->p_swflags, TIOCFLAG_CRTSCTS))
  451                         SET(t.c_cflag, CRTSCTS);
  452                 if (ISSET(port->p_swflags, TIOCFLAG_CDTRCTS))
  453                         SET(t.c_cflag, CDTRCTS);
  454                 if (ISSET(port->p_swflags, TIOCFLAG_MDMBUF))
  455                         SET(t.c_cflag, MDMBUF);
  456 
  457                 /* Make sure param will see changes. */
  458                 tp->t_ospeed = 0;       /* XXX set above ignored? */
  459                 (void)cdttyparam(tp, &t);
  460 
  461                 tp->t_iflag = TTYDEF_IFLAG;
  462                 tp->t_oflag = TTYDEF_OFLAG;
  463                 tp->t_lflag = TTYDEF_LFLAG;
  464                 ttychars(tp);
  465                 ttsetwater(tp);
  466 
  467                 (void)splserial();
  468 
  469                 /* turn on rx and modem interrupts */
  470                 cd18xx_set_car(sc, CD18XX_CHANNEL(dev));
  471                 SET(port->p_srer, CD18xx_SRER_Rx |
  472                                   CD18xx_SRER_RxSC |
  473                                   CD18xx_SRER_CD);
  474                 cd18xx_write(sc, CD18xx_SRER, port->p_srer);
  475 
  476                 /* always turn on DTR when open */
  477                 cdtty_modem(sc, port, 1);
  478 
  479                 /* initialise ring buffer */
  480                 port->p_rbget = port->p_rbput = port->p_rbuf;
  481                 port->p_rbavail = cdtty_rbuf_size;
  482                 CLR(port->p_rx_flags, RX_ANY_BLOCK);
  483                 cdtty_hwiflow(sc, port);
  484         }
  485 
  486         /* drop spl back before going into the line open */
  487         splx(s);
  488 
  489         error = ttyopen(tp, CD18XX_DIALOUT(dev), ISSET(flag, O_NONBLOCK));
  490         if (error == 0)
  491                 error = (*tp->t_linesw->l_open)(dev, tp);
  492 
  493         return (error);
  494 }
  495 
  496 /*
  497  * cdttyclose:  close syscall for cdtty terminals..
  498  */
  499 int
  500 cdttyclose(dev, flag, mode, p)
  501         dev_t dev;
  502         int flag;
  503         int mode;
  504         struct proc *p;
  505 {
  506         struct cd18xx_softc *sc;
  507         struct cdtty_port *port;
  508         struct tty *tp;
  509         int channel, instance;
  510 
  511         channel = CD18XX_CHANNEL(dev);
  512         instance = CD18XX_INSTANCE(dev);
  513 
  514         /* ensure instance is valid */
  515         if (instance >= clcd_cd.cd_ndevs)
  516                 return (ENXIO);
  517 
  518         /* get softc and port */
  519         sc = device_lookup_private(&clcd_cd, instance);
  520         if (sc == NULL)
  521                 return (ENXIO);
  522         port = &sc->sc_ports[channel];
  523 
  524         tp = port->p_tty;
  525 
  526         (*tp->t_linesw->l_close)(tp, flag);
  527         ttyclose(tp);
  528 
  529         if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0) {
  530                 /*
  531                  * Although we got a last close, the device may still be in
  532                  * use; e.g. if this was the dialout node, and there are still
  533                  * processes waiting for carrier on the non-dialout node.
  534                  */
  535                 cdtty_shutdown(sc, port);
  536         }
  537 
  538         return (0);
  539 }
  540 
  541 /*
  542  * cdttyread:  read syscall for cdtty terminals..
  543  */
  544 int
  545 cdttyread(dev_t dev, struct uio *uio, int flag)
  546 {
  547         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(dev));
  548         struct cdtty_port *port = &sc->sc_ports[CD18XX_CHANNEL(dev)];
  549         struct tty *tp = port->p_tty;
  550 
  551         return ((*tp->t_linesw->l_read)(tp, uio, flag));
  552 }
  553 
  554 /*
  555  * cdttywrite:  write syscall for cdtty terminals..
  556  */
  557 int
  558 cdttywrite(dev_t dev, struct uio *uio, int flag)
  559 {
  560         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(dev));
  561         struct cdtty_port *port = &sc->sc_ports[CD18XX_CHANNEL(dev)];
  562         struct tty *tp = port->p_tty;
  563 
  564         return ((*tp->t_linesw->l_write)(tp, uio, flag));
  565 }
  566 
  567 int
  568 cdttypoll(dev_t dev, int events, struct proc *p)
  569 {
  570         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(dev));
  571         struct cdtty_port *port = &sc->sc_ports[CD18XX_CHANNEL(dev)];
  572         struct tty *tp = port->p_tty;
  573 
  574         return ((*tp->t_linesw->l_poll)(tp, events, p));
  575 }
  576 
  577 /*
  578  * cdttytty:  return a pointer to our (cdtty) tp.
  579  */
  580 struct tty *
  581 cdttytty(dev_t dev)
  582 {
  583         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(dev));
  584         struct cdtty_port *port = &sc->sc_ports[CD18XX_CHANNEL(dev)];
  585 
  586         return (port->p_tty);
  587 }
  588 
  589 /*
  590  * cdttyioctl:  ioctl syscall for cdtty terminals..
  591  */
  592 int
  593 cdttyioctl(dev_t dev, u_long cmd, void *data, int flag, struct proc *p)
  594 {
  595         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(dev));
  596         struct cdtty_port *port = &sc->sc_ports[CD18XX_CHANNEL(dev)];
  597         struct tty *tp = port->p_tty;
  598         int error, s;
  599 
  600         error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
  601         if (error != EPASSTHROUGH)
  602                 return (error);
  603 
  604         error = ttioctl(tp, cmd, data, flag, p);
  605         if (error != EPASSTHROUGH)
  606                 return (error);
  607 
  608         s = splserial();
  609 
  610         switch (cmd) {
  611         case TIOCSBRK:
  612                 cdtty_break(sc, port, 1);
  613                 break;
  614 
  615         case TIOCCBRK:
  616                 cdtty_break(sc, port, 0);
  617                 break;
  618 
  619         case TIOCSDTR:
  620                 cdtty_modem(sc, port, 1);
  621                 break;
  622 
  623         case TIOCCDTR:
  624                 cdtty_modem(sc, port, 0);
  625                 break;
  626 
  627         case TIOCGFLAGS:
  628                 *(int *)data = port->p_swflags;
  629                 break;
  630 
  631         case TIOCSFLAGS:
  632                 error = kauth_authorize_device_tty(l->l_cred,
  633                     KAUTH_DEVICE_TTY_PRIVSET, tp);
  634                 if (error)
  635                         return (error);
  636                 port->p_swflags = *(int *)data;
  637                 break;
  638 
  639         case TIOCMSET:
  640         case TIOCMBIS:
  641         case TIOCMBIC:
  642         case TIOCMGET:
  643         default:
  644                 return (EPASSTHROUGH);
  645         }
  646 
  647         splx(s);
  648         return (0);
  649 }
  650 
  651 /*
  652  * Start or restart transmission.
  653  */
  654 static void
  655 cdttystart(struct tty *tp)
  656 {
  657         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(tp->t_dev));
  658         struct cdtty_port *p = &sc->sc_ports[CD18XX_CHANNEL(tp->t_dev)];
  659         int s;
  660 
  661         s = spltty();
  662         if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP))
  663                 goto out;
  664         if (p->p_tx_stopped)
  665                 goto out;
  666 
  667         if (!ttypull(tp))
  668                 goto out;
  669 
  670         /* Grab the first contiguous region of buffer space. */
  671         {
  672                 u_char *tba;
  673                 int tbc;
  674 
  675                 tba = tp->t_outq.c_cf;
  676                 tbc = ndqb(&tp->t_outq, 0);
  677 
  678                 (void)splserial();
  679 
  680                 p->p_tba = tba;
  681                 p->p_tbc = tbc;
  682         }
  683 
  684         SET(tp->t_state, TS_BUSY);
  685         p->p_tx_busy = 1;
  686 
  687         /* turn on tx interrupts */
  688         if ((p->p_srer & CD18xx_SRER_Tx) == 0) {
  689                 cd18xx_set_car(sc, CD18XX_CHANNEL(tp->t_dev));
  690                 SET(p->p_srer, CD18xx_SRER_Tx);
  691                 cd18xx_write(sc, CD18xx_SRER, p->p_srer);
  692         }
  693 
  694         /*
  695          * Now bail; we can't actually transmit bytes until we're in a
  696          * transmit interrupt service routine.
  697          */
  698 out:
  699         splx(s);
  700         return;
  701 }
  702 
  703 /*
  704  * cdttystop:  handing ^S or other stop signals, for a cdtty
  705  */
  706 void
  707 cdttystop(struct tty *tp, int flag)
  708 {
  709         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(tp->t_dev));
  710         struct cdtty_port *p = &sc->sc_ports[CD18XX_CHANNEL(tp->t_dev)];
  711         int s;
  712 
  713         s = splserial();
  714         if (ISSET(tp->t_state, TS_BUSY)) {
  715                 /* Stop transmitting at the next chunk. */
  716                 p->p_tbc = 0;
  717                 p->p_heldtbc = 0;
  718                 if (!ISSET(tp->t_state, TS_TTSTOP))
  719                         SET(tp->t_state, TS_FLUSH);
  720         }
  721         splx(s);
  722 }
  723 
  724 /*
  725  * load a channel's registers.
  726  */
  727 void
  728 cdtty_loadchannelregs(sc, p)
  729         struct cd18xx_softc *sc;
  730         struct cdtty_port *p;
  731 {
  732 
  733         cd18xx_set_car(sc, CD18XX_CHANNEL(p->p_tty->t_dev));
  734         cd18xx_write(sc, CD18xx_SRER, p->p_srer);
  735         cd18xx_write(sc, CD18xx_MSVR, p->p_msvr_active = p->p_msvr);
  736         cd18xx_write(sc, CD18xx_COR1, p->p_cor1);
  737         cd18xx_write(sc, CD18xx_COR2, p->p_cor2);
  738         cd18xx_write(sc, CD18xx_COR3, p->p_cor3);
  739         /*
  740          * COR2 and COR3 change commands are not required here for
  741          * the CL-CD1865 but we do them anyway for simplicity.
  742          */
  743         cd18xx_write(sc, CD18xx_CCR, CD18xx_CCR_CORCHG |
  744                                      CD18xx_CCR_CORCHG_COR1 |
  745                                      CD18xx_CCR_CORCHG_COR2 |
  746                                      CD18xx_CCR_CORCHG_COR3);
  747         cd18xx_write(sc, CD18xx_RBPRH, p->p_rbprh);
  748         cd18xx_write(sc, CD18xx_RBPRL, p->p_rbprl);
  749         cd18xx_write(sc, CD18xx_TBPRH, p->p_tbprh);
  750         cd18xx_write(sc, CD18xx_TBPRL, p->p_tbprl);
  751         if (cd18xx_wait_ccr(sc)) {
  752                 DPRINTF(CDD_INFO,
  753                     ("%s: cdtty_loadchannelregs ccr wait timed out\n",
  754                     device_xname(&sc->sc_dev)));
  755         }
  756         cd18xx_write(sc, CD18xx_CCR, p->p_chanctl);
  757 }
  758 
  759 /*
  760  * Set tty parameters from termios.
  761  * XXX - Should just copy the whole termios after
  762  * making sure all the changes could be done.
  763  */
  764 static int
  765 cdttyparam(struct tty *tp, struct termios *t)
  766 {
  767         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(tp->t_dev));
  768         struct cdtty_port *p = &sc->sc_ports[CD18XX_CHANNEL(tp->t_dev)];
  769         int s;
  770 
  771         /* Check requested parameters. */
  772         if (t->c_ospeed < 0)
  773                 return (EINVAL);
  774         if (t->c_ispeed && t->c_ispeed != t->c_ospeed)
  775                 return (EINVAL);
  776 
  777         /*
  778          * For the console, always force CLOCAL and !HUPCL, so that the port
  779          * is always active.
  780          */
  781         if (ISSET(p->p_swflags, TIOCFLAG_SOFTCAR)) {
  782                 SET(t->c_cflag, CLOCAL);
  783                 CLR(t->c_cflag, HUPCL);
  784         }
  785 
  786         /*
  787          * If there were no changes, don't do anything.  This avoids dropping
  788          * input and improves performance when all we did was frob things like
  789          * VMIN and VTIME.
  790          */
  791         if (tp->t_ospeed == t->c_ospeed &&
  792             tp->t_cflag == t->c_cflag)
  793                 return (0);
  794 
  795         /*
  796          * Block interrupts so that state will not
  797          * be altered until we are done setting it up.
  798          */
  799         s = splserial();
  800 
  801         /*
  802          * Copy across the size, parity and stop bit info.
  803          */
  804         switch (t->c_cflag & CSIZE) {
  805         case CS5:
  806                 p->p_cor1 = CD18xx_COR1_CS5;
  807                 break;
  808         case CS6:
  809                 p->p_cor1 = CD18xx_COR1_CS6;
  810                 break;
  811         case CS7:
  812                 p->p_cor1 = CD18xx_COR1_CS7;
  813                 break;
  814         default:
  815                 p->p_cor1 = CD18xx_COR1_CS8;
  816                 break;
  817         }
  818         if (ISSET(t->c_cflag, PARENB)) {
  819                 SET(p->p_cor1, CD18xx_COR1_PARITY_NORMAL);
  820                 if (ISSET(t->c_cflag, PARODD))
  821                         SET(p->p_cor1, CD18xx_COR1_PARITY_ODD);
  822         }
  823         if (!ISSET(t->c_iflag, INPCK))
  824                 SET(p->p_cor1, CD18xx_COR1_IGNORE);
  825         if (ISSET(t->c_cflag, CSTOPB))
  826                 SET(p->p_cor1, CD18xx_COR1_STOPBIT_2);
  827 
  828         /*
  829          * If we're not in a mode that assumes a connection is present, then
  830          * ignore carrier changes.
  831          */
  832         if (ISSET(t->c_cflag, CLOCAL | MDMBUF))
  833                 p->p_msvr_dcd = 0;
  834         else
  835                 p->p_msvr_dcd = CD18xx_MSVR_CD;
  836 
  837         /*
  838          * Set the flow control pins depending on the current flow control
  839          * mode.
  840          */
  841         if (ISSET(t->c_cflag, CRTSCTS)) {
  842                 p->p_mcor1_dtr = CD18xx_MCOR1_DTR;
  843                 p->p_msvr_rts = CD18xx_MSVR_RTS;
  844                 p->p_msvr_cts = CD18xx_MSVR_CTS;
  845                 p->p_cor2 = CD18xx_COR2_RTSAOE|CD18xx_COR2_CTSAE;
  846         } else if (ISSET(t->c_cflag, MDMBUF)) {
  847                 /*
  848                  * For DTR/DCD flow control, make sure we don't toggle DTR for
  849                  * carrier detection.
  850                  */
  851                 p->p_mcor1_dtr = 0;
  852                 p->p_msvr_rts = CD18xx_MSVR_DTR;
  853                 p->p_msvr_cts = CD18xx_MSVR_CD;
  854                 p->p_cor2 = 0;
  855         } else {
  856                 /*
  857                  * If no flow control, then always set RTS.  This will make
  858                  * the other side happy if it mistakenly thinks we're doing
  859                  * RTS/CTS flow control.
  860                  */
  861                 p->p_mcor1_dtr = CD18xx_MSVR_DTR;
  862                 p->p_msvr_rts = 0;
  863                 p->p_msvr_cts = 0;
  864                 p->p_cor2 = 0;
  865         }
  866         p->p_msvr_mask = p->p_msvr_cts | p->p_msvr_dcd;
  867 
  868         /*
  869          * Set the FIFO threshold based on the receive speed.
  870          *
  871          *  * If it's a low speed, it's probably a mouse or some other
  872          *    interactive device, so set the threshold low.
  873          *  * If it's a high speed, trim the trigger level down to prevent
  874          *    overflows.
  875          *  * Otherwise set it a bit higher.
  876          */
  877         p->p_cor3 = (t->c_ospeed <= 1200 ? 1 : t->c_ospeed <= 38400 ? 8 : 4);
  878 
  879 #define PORT_RATE(o, s) \
  880         (((((o) + (s)/2) / (s)) + CD18xx_xBRPR_TPC/2) / CD18xx_xBRPR_TPC)
  881         /* Compute BPS for the requested speeds */
  882         if (t->c_ospeed) {
  883                 u_int32_t tbpr = PORT_RATE(sc->sc_osc, t->c_ospeed);
  884 
  885                 if (tbpr == 0 || tbpr > 0xffff)
  886                         return (EINVAL);
  887 
  888                 p->p_tbprh = tbpr >> 8;
  889                 p->p_tbprl = tbpr & 0xff;
  890         }
  891 
  892         if (t->c_ispeed) {
  893                 u_int32_t rbpr = PORT_RATE(sc->sc_osc, t->c_ispeed);
  894 
  895                 if (rbpr == 0 || rbpr > 0xffff)
  896                         return (EINVAL);
  897 
  898                 p->p_rbprh = rbpr >> 8;
  899                 p->p_rbprl = rbpr & 0xff;
  900         }
  901 
  902         /* And copy to tty. */
  903         tp->t_ispeed = 0;
  904         tp->t_ospeed = t->c_ospeed;
  905         tp->t_cflag = t->c_cflag;
  906 
  907         if (!p->p_heldchange) {
  908                 if (p->p_tx_busy) {
  909                         p->p_heldtbc = p->p_tbc;
  910                         p->p_tbc = 0;
  911                         p->p_heldchange = 1;
  912                 } else
  913                         cdtty_loadchannelregs(sc, p);
  914         }
  915 
  916         if (!ISSET(t->c_cflag, CHWFLOW)) {
  917                 /* Disable the high water mark. */
  918                 p->p_r_hiwat = 0;
  919                 p->p_r_lowat = 0;
  920                 if (ISSET(p->p_rx_flags, RX_TTY_OVERFLOWED)) {
  921                         CLR(p->p_rx_flags, RX_TTY_OVERFLOWED);
  922                         softint_schedule(sc->sc_si);
  923                 }
  924                 if (ISSET(p->p_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) {
  925                         CLR(p->p_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED);
  926                         cdtty_hwiflow(sc, p);
  927                 }
  928         } else {
  929                 p->p_r_hiwat = cdtty_rbuf_hiwat;
  930                 p->p_r_lowat = cdtty_rbuf_lowat;
  931         }
  932 
  933         splx(s);
  934 
  935         /*
  936          * Update the tty layer's idea of the carrier bit, in case we changed
  937          * CLOCAL or MDMBUF.  We don't hang up here; we only do that by
  938          * explicit request.
  939          */
  940         (void) (*tp->t_linesw->l_modem)(tp, ISSET(p->p_msvr, CD18xx_MSVR_CD));
  941 
  942         if (!ISSET(t->c_cflag, CHWFLOW)) {
  943                 if (p->p_tx_stopped) {
  944                         p->p_tx_stopped = 0;
  945                         cdttystart(tp);
  946                 }
  947         }
  948 
  949         return (0);
  950 }
  951 
  952 static void
  953 cdtty_break(sc, p, onoff)
  954         struct cd18xx_softc *sc;
  955         struct cdtty_port *p;
  956         int onoff;
  957 {
  958 
  959         /* tell tx intr handler we need a break */
  960         p->p_needbreak = !!onoff;
  961 
  962         /* turn on tx interrupts if break has changed */
  963         if (p->p_needbreak != p->p_break)
  964                 SET(p->p_srer, CD18xx_SRER_Tx);
  965 
  966         if (!p->p_heldchange) {
  967                 if (p->p_tx_busy) {
  968                         p->p_heldtbc = p->p_tbc;
  969                         p->p_tbc = 0;
  970                         p->p_heldchange = 1;
  971                 } else
  972                         cdtty_loadchannelregs(sc, p);
  973         }
  974 }
  975 
  976 /*
  977  * Raise or lower modem control (DTR/RTS) signals.  If a character is
  978  * in transmission, the change is deferred.
  979  */
  980 static void
  981 cdtty_modem(sc, p, onoff)
  982         struct cd18xx_softc *sc;
  983         struct cdtty_port *p;
  984         int onoff;
  985 {
  986 
  987         if (p->p_mcor1_dtr == 0)
  988                 return;
  989 
  990         if (onoff)
  991                 CLR(p->p_mcor1, p->p_mcor1_dtr);
  992         else
  993                 SET(p->p_mcor1, p->p_mcor1_dtr);
  994 
  995         if (!p->p_heldchange) {
  996                 if (p->p_tx_busy) {
  997                         p->p_heldtbc = p->p_tbc;
  998                         p->p_tbc = 0;
  999                         p->p_heldchange = 1;
 1000                 } else
 1001                         cdtty_loadchannelregs(sc, p);
 1002         }
 1003 }
 1004 
 1005 /*
 1006  * Try to block or unblock input using hardware flow-control.
 1007  * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and
 1008  * if this function returns non-zero, the TS_TBLOCK flag will
 1009  * be set or cleared according to the "block" arg passed.
 1010  */
 1011 int
 1012 cdttyhwiflow(struct tty *tp, int block)
 1013 {
 1014         struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, CD18XX_INSTANCE(tp->t_dev));
 1015         struct cdtty_port *p = &sc->sc_ports[CD18XX_CHANNEL(tp->t_dev)];
 1016         int s;
 1017 
 1018         if (p->p_msvr_rts == 0)
 1019                 return (0);
 1020 
 1021         s = splserial();
 1022         if (block) {
 1023                 if (!ISSET(p->p_rx_flags, RX_TTY_BLOCKED)) {
 1024                         SET(p->p_rx_flags, RX_TTY_BLOCKED);
 1025                         cdtty_hwiflow(sc, p);
 1026                 }
 1027         } else {
 1028                 if (ISSET(p->p_rx_flags, RX_TTY_OVERFLOWED)) {
 1029                         CLR(p->p_rx_flags, RX_TTY_OVERFLOWED);
 1030                         softint_schedule(sc->sc_si);
 1031                 }
 1032                 if (ISSET(p->p_rx_flags, RX_TTY_BLOCKED)) {
 1033                         CLR(p->p_rx_flags, RX_TTY_BLOCKED);
 1034                         cdtty_hwiflow(sc, p);
 1035                 }
 1036         }
 1037         splx(s);
 1038         return (1);
 1039 }
 1040 
 1041 /*
 1042  * Internal version of cdttyhwiflow, called at cdtty's priority.
 1043  */
 1044 static void
 1045 cdtty_hwiflow(sc, p)
 1046         struct cd18xx_softc *sc;
 1047         struct cdtty_port *p;
 1048 {
 1049 
 1050         if (p->p_msvr_rts == 0)
 1051                 return;
 1052 
 1053         if (ISSET(p->p_rx_flags, RX_ANY_BLOCK)) {
 1054                 CLR(p->p_msvr, p->p_msvr_rts);
 1055                 CLR(p->p_msvr_active, p->p_msvr_rts);
 1056         } else {
 1057                 SET(p->p_msvr, p->p_msvr_rts);
 1058                 SET(p->p_msvr_active, p->p_msvr_rts);
 1059         }
 1060         cd18xx_set_car(sc, CD18XX_CHANNEL(p->p_tty->t_dev));
 1061         cd18xx_write(sc, CD18xx_MSVR, p->p_msvr_active);
 1062 }
 1063 
 1064 /*
 1065  * indiviual interrupt routines.
 1066  */
 1067 
 1068 /*
 1069  * this is the number of interrupts allowed, total.  set it to 0
 1070  * to allow unlimited interrpts
 1071  */
 1072 #define INTR_MAX_ALLOWED        0
 1073 
 1074 #if INTR_MAX_ALLOWED == 0
 1075 #define GOTINTR(sc, p)  /* nothing */
 1076 #else
 1077 int intrcount;
 1078 #define GOTINTR(sc, p)  \
 1079 do { \
 1080         if (intrcount++ == INTR_MAX_ALLOWED) { \
 1081                 CLR(p->p_srer, CD18xx_SRER_Tx); \
 1082                 cd18xx_write(sc, CD18xx_SRER, p->p_srer); \
 1083         } \
 1084         DPRINTF(CDD_INTR, (", intrcount %d srer %x", intrcount, p->p_srer)); \
 1085 } while (0)
 1086 #endif
 1087 
 1088 /* receiver interrupt */
 1089 static inline void
 1090 cd18xx_rint(sc, ns)
 1091         struct cd18xx_softc *sc;
 1092         int *ns;
 1093 {
 1094         struct cdtty_port *p;
 1095         u_int channel, count;
 1096         u_char *put, *end;
 1097         u_int cc;
 1098 
 1099         /* work out the channel and softc */
 1100         channel = cd18xx_get_gscr1_channel(sc);
 1101         p = &sc->sc_ports[channel];
 1102         DPRINTF(CDD_INTR, ("%s: rint: channel %d", device_xname(&sc->sc_dev), channel));
 1103         GOTINTR(sc, p);
 1104 
 1105         end = p->p_ebuf;
 1106         put = p->p_rbput;
 1107         cc = p->p_rbavail;
 1108 
 1109         /* read as many bytes as necessary */
 1110         count = cd18xx_read(sc, CD18xx_RDCR);
 1111         DPRINTF(CDD_INTR, (", %d bytes available: ", count));
 1112 
 1113         while (cc > 0 && count > 0) {
 1114                 u_char rcsr = cd18xx_read(sc, CD18xx_RCSR);
 1115 
 1116                 put[0] = cd18xx_read(sc, CD18xx_RDR);
 1117                 put[1] = rcsr;
 1118 
 1119                 if (rcsr)
 1120                         *ns = 1;
 1121 
 1122                 put += 2;
 1123                 if (put >= end)
 1124                         put = p->p_rbuf;
 1125 
 1126                 DPRINTF(CDD_INTR, ("."));
 1127                 cc--;
 1128                 count--;
 1129         }
 1130 
 1131         DPRINTF(CDD_INTR, (" finished reading"));
 1132 
 1133         /*
 1134          * Current string of incoming characters ended because
 1135          * no more data was available or we ran out of space.
 1136          * If we're out of space, turn off receive interrupts.
 1137          */
 1138         p->p_rbput = put;
 1139         p->p_rbavail = cc;
 1140         if (!ISSET(p->p_rx_flags, RX_TTY_OVERFLOWED)) {
 1141                 p->p_rx_ready = 1;
 1142         }
 1143 
 1144         /*
 1145          * If we're out of space, disable receive interrupts
 1146          * until the queue has drained a bit.
 1147          */
 1148         if (!cc) {
 1149                 SET(p->p_rx_flags, RX_IBUF_OVERFLOWED);
 1150                 CLR(p->p_srer, CD18xx_SRER_Rx |
 1151                                CD18xx_SRER_RxSC |
 1152                                CD18xx_SRER_CD);
 1153                 cd18xx_write(sc, CD18xx_SRER, p->p_srer);
 1154         }
 1155 
 1156         /* finish the interrupt transaction with the IC */
 1157         cd18xx_write(sc, CD18xx_EOSRR, 0);
 1158         DPRINTF(CDD_INTR, (", done\n"));
 1159 }
 1160 
 1161 /*
 1162  * transmitter interrupt
 1163  *
 1164  * note this relys on the fact that we allow the transmitter FIFO to
 1165  * drain completely
 1166  */
 1167 static inline void
 1168 cd18xx_tint(sc, ns)
 1169         struct cd18xx_softc *sc;
 1170         int *ns;
 1171 {
 1172         struct cdtty_port *p;
 1173         u_int channel;
 1174 
 1175         /* work out the channel and softc */
 1176         channel = cd18xx_get_gscr1_channel(sc);
 1177         p = &sc->sc_ports[channel];
 1178         DPRINTF(CDD_INTR, ("%s: tint: channel %d", device_xname(&sc->sc_dev),
 1179             channel));
 1180         GOTINTR(sc, p);
 1181 
 1182         /* if the current break condition is wrong, fix it */
 1183         if (p->p_break != p->p_needbreak) {
 1184                 u_char buf[2];
 1185 
 1186                 DPRINTF(CDD_INTR, (", changing break to %d", p->p_needbreak));
 1187 
 1188                 /* turn on ETC processing */
 1189                 cd18xx_write(sc, CD18xx_COR2, p->p_cor2 | CD18xx_COR2_ETC);
 1190 
 1191                 buf[0] = CD18xx_TDR_ETC_BYTE;
 1192                 buf[1] = p->p_needbreak ? CD18xx_TDR_BREAK_BYTE :
 1193                                             CD18xx_TDR_NOBREAK_BYTE;
 1194                 cd18xx_write_multi(sc, CD18xx_TDR, buf, 2);
 1195 
 1196                 p->p_break = p->p_needbreak;
 1197 
 1198                 /* turn off ETC processing */
 1199                 cd18xx_write(sc, CD18xx_COR2, p->p_cor2);
 1200         }
 1201 
 1202         /*
 1203          * If we've delayed a parameter change, do it now, and restart
 1204          * output.
 1205          */
 1206         if (p->p_heldchange) {
 1207                 cdtty_loadchannelregs(sc, p);
 1208                 p->p_heldchange = 0;
 1209                 p->p_tbc = p->p_heldtbc;
 1210                 p->p_heldtbc = 0;
 1211         }
 1212 
 1213         /* Output the next chunk of the contiguous buffer, if any. */
 1214         if (p->p_tbc > 0) {
 1215                 int n;
 1216 
 1217                 n = p->p_tbc;
 1218                 if (n > 8) /* write up to 8 entries */
 1219                         n = 8;
 1220                 DPRINTF(CDD_INTR, (", writing %d bytes to TDR", n));
 1221                 cd18xx_write_multi(sc, CD18xx_TDR, p->p_tba, n);
 1222                 p->p_tbc -= n;
 1223                 p->p_tba += n;
 1224         }
 1225 
 1226         /* Disable transmit completion interrupts if we ran out of bytes. */
 1227         if (p->p_tbc == 0) {
 1228                 /* Note that Tx interrupts should already be enabled */
 1229                 if (ISSET(p->p_srer, CD18xx_SRER_Tx)) {
 1230                         DPRINTF(CDD_INTR, (", disabling tx interrupts"));
 1231                         CLR(p->p_srer, CD18xx_SRER_Tx);
 1232                         cd18xx_write(sc, CD18xx_SRER, p->p_srer);
 1233                 }
 1234                 if (p->p_tx_busy) {
 1235                         p->p_tx_busy = 0;
 1236                         p->p_tx_done = 1;
 1237                 }
 1238         }
 1239         *ns = 1;
 1240 
 1241         /* finish the interrupt transaction with the IC */
 1242         cd18xx_write(sc, CD18xx_EOSRR, 0);
 1243         DPRINTF(CDD_INTR, (", done\n"));
 1244 }
 1245 
 1246 /* modem signal change interrupt */
 1247 static inline void
 1248 cd18xx_mint(sc, ns)
 1249         struct cd18xx_softc *sc;
 1250         int *ns;
 1251 {
 1252         struct cdtty_port *p;
 1253         u_int channel;
 1254         u_char msvr, delta;
 1255 
 1256         /* work out the channel and softc */
 1257         channel = cd18xx_get_gscr1_channel(sc);
 1258         p = &sc->sc_ports[channel];
 1259         DPRINTF(CDD_INTR, ("%s: mint: channel %d", device_xname(&sc->sc_dev), channel));
 1260         GOTINTR(sc, p);
 1261 
 1262         /*
 1263          * We ignore the MCR register, and handle detecting deltas
 1264          * via software, like many other serial drivers.
 1265          */
 1266         msvr = cd18xx_read(sc, CD18xx_MSVR);
 1267         delta = msvr ^ p->p_msvr;
 1268         DPRINTF(CDD_INTR, (", msvr %d", msvr));
 1269 
 1270         /*
 1271          * Process normal status changes
 1272          */
 1273         if (ISSET(delta, p->p_msvr_mask)) {
 1274                 SET(p->p_msvr_delta, delta);
 1275 
 1276                 DPRINTF(CDD_INTR, (", status changed delta %d", delta));
 1277                 /*
 1278                  * Stop output immediately if we lose the output
 1279                  * flow control signal or carrier detect.
 1280                  */
 1281                 if (ISSET(~msvr, p->p_msvr_mask)) {
 1282                         p->p_tbc = 0;
 1283                         p->p_heldtbc = 0;
 1284                         /* Stop modem interrupt processing */
 1285                 }
 1286                 p->p_st_check = 1;
 1287                 *ns = 1;
 1288         }
 1289 
 1290         /* reset the modem signal register */
 1291         cd18xx_write(sc, CD18xx_MCR, 0);
 1292 
 1293         /* finish the interrupt transaction with the IC */
 1294         cd18xx_write(sc, CD18xx_EOSRR, 0);
 1295         DPRINTF(CDD_INTR, (", done\n"));
 1296 }
 1297 
 1298 /*
 1299  * hardware interrupt routine.  call the relevant interrupt routines until
 1300  * no interrupts are pending.
 1301  *
 1302  * note:  we do receive interrupts before all others (as we'd rather lose
 1303  * a chance to transmit, than lose a character).  and we do transmit
 1304  * interrupts before modem interrupts.
 1305  *
 1306  * we have to traverse all of the cd18xx's attached, unfortunately.
 1307  */
 1308 int
 1309 cd18xx_hardintr(void *v)
 1310 {
 1311         int i, rv = 0;
 1312         u_char ack;
 1313 
 1314         DPRINTF(CDD_INTR, ("cd18xx_hardintr (ndevs %d):\n", clcd_cd.cd_ndevs));
 1315         for (i = 0; i < clcd_cd.cd_ndevs; i++)
 1316         {
 1317                 struct cd18xx_softc *sc = device_lookup_private(&clcd_cd, i);
 1318                 int status, ns = 0;
 1319                 int count = 1;  /* process only 1 interrupts at a time for now */
 1320 
 1321                 if (sc == NULL)
 1322                         continue;
 1323 
 1324                 DPRINTF(CDD_INTR, ("%s:", device_xname(&sc->sc_dev)));
 1325                 while (count-- &&
 1326                     (status = (cd18xx_read(sc, CD18xx_SRSR) &
 1327                      CD18xx_SRSR_PENDING))) {
 1328                         rv = 1;
 1329 
 1330                         DPRINTF(CDD_INTR, (" status %x:", status));
 1331                         if (ISSET(status, CD18xx_SRSR_RxPEND)) {
 1332                                 ack = (*sc->sc_ackfunc)(sc->sc_ackfunc_arg,
 1333                                     CD18xx_INTRACK_RxINT);
 1334                                 DPRINTF(CDD_INTR, (" rx: ack1 %x\n", ack));
 1335                                 cd18xx_rint(sc, &ns);
 1336                         }
 1337                         if (ISSET(status, CD18xx_SRSR_TxPEND)) {
 1338                                 ack = (*sc->sc_ackfunc)(sc->sc_ackfunc_arg,
 1339                                     CD18xx_INTRACK_TxINT);
 1340                                 DPRINTF(CDD_INTR, (" tx: ack1 %x\n", ack));
 1341                                 cd18xx_tint(sc, &ns);
 1342 
 1343                         }
 1344                         if (ISSET(status, CD18xx_SRSR_MxPEND)) {
 1345                                 ack = (*sc->sc_ackfunc)(sc->sc_ackfunc_arg,
 1346                                     CD18xx_INTRACK_MxINT);
 1347                                 DPRINTF(CDD_INTR, (" mx: ack1 %x\n", ack));
 1348                                 cd18xx_mint(sc, &ns);
 1349                         }
 1350                 }
 1351                 if (ns)
 1352                         softint_schedule(sc->sc_si);
 1353         }
 1354 
 1355         return (rv);
 1356 }
 1357 
 1358 /*
 1359  * software interrupt
 1360  */
 1361 
 1362 void
 1363 cdtty_rxsoft(sc, p, tp)
 1364         struct cd18xx_softc *sc;
 1365         struct cdtty_port *p;
 1366         struct tty *tp;
 1367 {
 1368         u_char *get, *end;
 1369         u_int cc, scc;
 1370         u_char rcsr;
 1371         int code;
 1372         int s;
 1373 
 1374         end = p->p_ebuf;
 1375         get = p->p_rbget;
 1376         scc = cc = cdtty_rbuf_size - p->p_rbavail;
 1377 
 1378         if (cc == cdtty_rbuf_size) {
 1379                 p->p_floods++;
 1380 #if 0
 1381                 if (p->p_errors++ == 0)
 1382                         callout_reset(&p->p_diag_callout, 60 * hz,
 1383                             cdttydiag, p);
 1384 #endif
 1385         }
 1386 
 1387         while (cc) {
 1388                 code = get[0];
 1389                 rcsr = get[1];
 1390                 if (ISSET(rcsr, CD18xx_RCSR_OVERRUNERR | CD18xx_RCSR_BREAK |
 1391                                 CD18xx_RCSR_FRAMERR | CD18xx_RCSR_PARITYERR)) {
 1392                         if (ISSET(rcsr, CD18xx_RCSR_OVERRUNERR)) {
 1393                                 p->p_overflows++;
 1394 #if 0
 1395                                 if (p->p_errors++ == 0)
 1396                                         callout_reset(&p->p_diag_callout,
 1397                                             60 * hz, cdttydiag, p);
 1398 #endif
 1399                         }
 1400                         if (ISSET(rcsr, CD18xx_RCSR_BREAK|CD18xx_RCSR_FRAMERR))
 1401                                 SET(code, TTY_FE);
 1402                         if (ISSET(rcsr, CD18xx_RCSR_PARITYERR))
 1403                                 SET(code, TTY_PE);
 1404                 }
 1405                 if ((*tp->t_linesw->l_rint)(code, tp) == -1) {
 1406                         /*
 1407                          * The line discipline's buffer is out of space.
 1408                          */
 1409                         if (!ISSET(p->p_rx_flags, RX_TTY_BLOCKED)) {
 1410                                 /*
 1411                                  * We're either not using flow control, or the
 1412                                  * line discipline didn't tell us to block for
 1413                                  * some reason.  Either way, we have no way to
 1414                                  * know when there's more space available, so
 1415                                  * just drop the rest of the data.
 1416                                  */
 1417                                 get += cc << 1;
 1418                                 if (get >= end)
 1419                                         get -= cdtty_rbuf_size << 1;
 1420                                 cc = 0;
 1421                         } else {
 1422                                 /*
 1423                                  * Don't schedule any more receive processing
 1424                                  * until the line discipline tells us there's
 1425                                  * space available (through cdttyhwiflow()).
 1426                                  * Leave the rest of the data in the input
 1427                                  * buffer.
 1428                                  */
 1429                                 SET(p->p_rx_flags, RX_TTY_OVERFLOWED);
 1430                         }
 1431                         break;
 1432                 }
 1433                 get += 2;
 1434                 if (get >= end)
 1435                         get = p->p_rbuf;
 1436                 cc--;
 1437         }
 1438 
 1439         if (cc != scc) {
 1440                 p->p_rbget = get;
 1441                 s = splserial();
 1442 
 1443                 cc = p->p_rbavail += scc - cc;
 1444                 /* Buffers should be ok again, release possible block. */
 1445                 if (cc >= p->p_r_lowat) {
 1446                         if (ISSET(p->p_rx_flags, RX_IBUF_OVERFLOWED)) {
 1447                                 CLR(p->p_rx_flags, RX_IBUF_OVERFLOWED);
 1448                                 cd18xx_set_car(sc, CD18XX_CHANNEL(tp->t_dev));
 1449                                 SET(p->p_srer, CD18xx_SRER_Rx |
 1450                                                CD18xx_SRER_RxSC |
 1451                                                CD18xx_SRER_CD);
 1452                                 cd18xx_write(sc, CD18xx_SRER, p->p_srer);
 1453                         }
 1454                         if (ISSET(p->p_rx_flags, RX_IBUF_BLOCKED)) {
 1455                                 CLR(p->p_rx_flags, RX_IBUF_BLOCKED);
 1456                                 cdtty_hwiflow(sc, p);
 1457                         }
 1458                 }
 1459                 splx(s);
 1460         }
 1461 }
 1462 
 1463 void
 1464 cdtty_txsoft(sc, p, tp)
 1465         struct cd18xx_softc *sc;
 1466         struct cdtty_port *p;
 1467         struct tty *tp;
 1468 {
 1469 
 1470         CLR(tp->t_state, TS_BUSY);
 1471         if (ISSET(tp->t_state, TS_FLUSH))
 1472                 CLR(tp->t_state, TS_FLUSH);
 1473         else
 1474                 ndflush(&tp->t_outq, (int)(p->p_tba - tp->t_outq.c_cf));
 1475         (*tp->t_linesw->l_start)(tp);
 1476 }
 1477 
 1478 void
 1479 cdtty_stsoft(sc, p, tp)
 1480         struct cd18xx_softc *sc;
 1481         struct cdtty_port *p;
 1482         struct tty *tp;
 1483 {
 1484         u_char msvr, delta;
 1485         int s;
 1486 
 1487         s = splserial();
 1488         msvr = p->p_msvr;
 1489         delta = p->p_msvr_delta;
 1490         p->p_msvr_delta = 0;
 1491         splx(s);
 1492 
 1493         if (ISSET(delta, p->p_msvr_dcd)) {
 1494                 /*
 1495                  * Inform the tty layer that carrier detect changed.
 1496                  */
 1497                 (void) (*tp->t_linesw->l_modem)(tp, ISSET(msvr, CD18xx_MSVR_CD));
 1498         }
 1499 
 1500         if (ISSET(delta, p->p_msvr_cts)) {
 1501                 /* Block or unblock output according to flow control. */
 1502                 if (ISSET(msvr, p->p_msvr_cts)) {
 1503                         p->p_tx_stopped = 0;
 1504                         (*tp->t_linesw->l_start)(tp);
 1505                 } else {
 1506                         p->p_tx_stopped = 1;
 1507                 }
 1508         }
 1509 }
 1510 
 1511 void
 1512 cd18xx_softintr(v)
 1513         void *v;
 1514 {
 1515         struct cd18xx_softc *sc = v;
 1516         struct cdtty_port *p;
 1517         struct tty *tp;
 1518         int i;
 1519 
 1520         for (i = 0; i < 8; i++) {
 1521                 p = &sc->sc_ports[i];
 1522 
 1523                 tp = p->p_tty;
 1524                 if (tp == NULL)
 1525                         continue;
 1526                 if (!ISSET(tp->t_state, TS_ISOPEN) && tp->t_wopen == 0)
 1527                         continue;
 1528 
 1529                 if (p->p_rx_ready) {
 1530                         p->p_rx_ready = 0;
 1531                         cdtty_rxsoft(sc, p, tp);
 1532                 }
 1533 
 1534                 if (p->p_st_check) {
 1535                         p->p_st_check = 0;
 1536                         cdtty_stsoft(sc, p, tp);
 1537                 }
 1538 
 1539                 if (p->p_tx_done) {
 1540                         p->p_tx_done = 0;
 1541                         cdtty_txsoft(sc, p, tp);
 1542                 }
 1543         }
 1544 }

Cache object: a698a8f98c688025d6d3e64e22b545ce


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.