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

Cache object: 1dc18e4c4b195d57eb7b5835eca414c8


[ 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.