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

Cache object: 41e8dbc78b35feddc06b4f39937ac940


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