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/qbus/dhu.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: dhu.c,v 1.58 2022/10/26 23:46:37 riastradh Exp $       */
    2 /*
    3  * Copyright (c) 2003, Hugh Graham.
    4  * Copyright (c) 1992, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Ralph Campbell and Rick Macklem.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  */
   34 
   35 /*
   36  * Copyright (c) 1996  Ken C. Wellsch.  All rights reserved.
   37  *
   38  * This code is derived from software contributed to Berkeley by
   39  * Ralph Campbell and Rick Macklem.
   40  *
   41  * Redistribution and use in source and binary forms, with or without
   42  * modification, are permitted provided that the following conditions
   43  * are met:
   44  * 1. Redistributions of source code must retain the above copyright
   45  *    notice, this list of conditions and the following disclaimer.
   46  * 2. Redistributions in binary form must reproduce the above copyright
   47  *    notice, this list of conditions and the following disclaimer in the
   48  *    documentation and/or other materials provided with the distribution.
   49  * 3. All advertising materials mentioning features or use of this software
   50  *    must display the following acknowledgement:
   51  *      This product includes software developed by the University of
   52  *      California, Berkeley and its contributors.
   53  * 4. Neither the name of the University nor the names of its contributors
   54  *    may be used to endorse or promote products derived from this software
   55  *    without specific prior written permission.
   56  *
   57  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   58  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   59  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   60  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   61  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   63  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   64  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   67  * SUCH DAMAGE.
   68  */
   69 
   70 #include <sys/cdefs.h>
   71 __KERNEL_RCSID(0, "$NetBSD: dhu.c,v 1.58 2022/10/26 23:46:37 riastradh Exp $");
   72 
   73 #include <sys/param.h>
   74 #include <sys/systm.h>
   75 #include <sys/ioctl.h>
   76 #include <sys/tty.h>
   77 #include <sys/proc.h>
   78 #include <sys/buf.h>
   79 #include <sys/conf.h>
   80 #include <sys/file.h>
   81 #include <sys/uio.h>
   82 #include <sys/kernel.h>
   83 #include <sys/syslog.h>
   84 #include <sys/device.h>
   85 #include <sys/kauth.h>
   86 
   87 #include <sys/bus.h>
   88 #include <machine/scb.h>
   89 
   90 #include <dev/qbus/ubavar.h>
   91 
   92 #include <dev/qbus/dhureg.h>
   93 
   94 #include "ioconf.h"
   95 
   96 /* A DHU-11 has 16 ports while a DHV-11 has only 8. We use 16 by default */
   97 
   98 #define NDHULINE        16
   99 
  100 #define DHU_M2U(c)      ((c)>>4)        /* convert minor(dev) to unit # */
  101 #define DHU_LINE(u)     ((u)&0xF)       /* extract line # from minor(dev) */
  102 
  103 struct dhu_softc {
  104         device_t        sc_dev;         /* Device struct used by config */
  105         struct evcnt    sc_rintrcnt;    /* Interrupt statistics */
  106         struct evcnt    sc_tintrcnt;    /* Interrupt statistics */
  107         int             sc_type;        /* controller type, DHU or DHV */
  108         int             sc_lines;       /* number of lines */
  109         bus_space_tag_t sc_iot;
  110         bus_space_handle_t sc_ioh;
  111         bus_dma_tag_t   sc_dmat;
  112         struct {
  113                 struct  tty *dhu_tty;   /* what we work on */
  114                 bus_dmamap_t dhu_dmah;
  115                 int     dhu_state;      /* to manage TX output status */
  116                 short   dhu_cc;         /* character count on TX */
  117                 short   dhu_modem;      /* modem bits state */
  118         } sc_dhu[NDHULINE];
  119 };
  120 
  121 #define IS_DHU                  16      /* Unibus DHU-11 board linecount */
  122 #define IS_DHV                   8      /* Q-bus DHV-11 or DHQ-11 */
  123 
  124 #define STATE_IDLE              000     /* no current output in progress */
  125 #define STATE_DMA_RUNNING       001     /* DMA TX in progress */
  126 #define STATE_DMA_STOPPED       002     /* DMA TX was aborted */
  127 #define STATE_TX_ONE_CHAR       004     /* did a single char directly */
  128 
  129 /* Flags used to monitor modem bits, make them understood outside driver */
  130 
  131 #define DML_DTR         TIOCM_DTR
  132 #define DML_RTS         TIOCM_RTS
  133 #define DML_CTS         TIOCM_CTS
  134 #define DML_DCD         TIOCM_CD
  135 #define DML_RI          TIOCM_RI
  136 #define DML_DSR         TIOCM_DSR
  137 #define DML_BRK         0100000         /* no equivalent, we will mask */
  138 
  139 #define DHU_READ_WORD(reg) \
  140         bus_space_read_2(sc->sc_iot, sc->sc_ioh, reg)
  141 #define DHU_WRITE_WORD(reg, val) \
  142         bus_space_write_2(sc->sc_iot, sc->sc_ioh, reg, val)
  143 #define DHU_READ_BYTE(reg) \
  144         bus_space_read_1(sc->sc_iot, sc->sc_ioh, reg)
  145 #define DHU_WRITE_BYTE(reg, val) \
  146         bus_space_write_1(sc->sc_iot, sc->sc_ioh, reg, val)
  147 
  148 
  149 /*  On a stock DHV, channel pairs (0/1, 2/3, etc.) must use */
  150 /* a baud rate from the same group.  So limiting to B is likely */
  151 /* best, although clone boards like the ABLE QHV allow all settings. */
  152 
  153 static const struct speedtab dhuspeedtab[] = {
  154   {       0,    0               },      /* Groups  */
  155   {      50,    DHU_LPR_B50     },      /* A       */
  156   {      75,    DHU_LPR_B75     },      /*       B */
  157   {     110,    DHU_LPR_B110    },      /* A and B */
  158   {     134,    DHU_LPR_B134    },      /* A and B */
  159   {     150,    DHU_LPR_B150    },      /*       B */
  160   {     300,    DHU_LPR_B300    },      /* A and B */
  161   {     600,    DHU_LPR_B600    },      /* A and B */
  162   {    1200,    DHU_LPR_B1200   },      /* A and B */
  163   {    1800,    DHU_LPR_B1800   },      /*       B */
  164   {    2000,    DHU_LPR_B2000   },      /*       B */
  165   {    2400,    DHU_LPR_B2400   },      /* A and B */
  166   {    4800,    DHU_LPR_B4800   },      /* A and B */
  167   {    7200,    DHU_LPR_B7200   },      /* A       */
  168   {    9600,    DHU_LPR_B9600   },      /* A and B */
  169   {   19200,    DHU_LPR_B19200  },      /*       B */
  170   {   38400,    DHU_LPR_B38400  },      /* A       */
  171   {      -1,    -1              }
  172 };
  173 
  174 static int      dhu_match(device_t, cfdata_t, void *);
  175 static void     dhu_attach(device_t, device_t, void *);
  176 static  void    dhurint(void *);
  177 static  void    dhuxint(void *);
  178 static  void    dhustart(struct tty *);
  179 static  int     dhuparam(struct tty *, struct termios *);
  180 static  int     dhuiflow(struct tty *, int);
  181 static unsigned dhumctl(struct dhu_softc *,int, int, int);
  182 
  183 CFATTACH_DECL_NEW(dhu, sizeof(struct dhu_softc),
  184     dhu_match, dhu_attach, NULL, NULL);
  185 
  186 static dev_type_open(dhuopen);
  187 static dev_type_close(dhuclose);
  188 static dev_type_read(dhuread);
  189 static dev_type_write(dhuwrite);
  190 static dev_type_ioctl(dhuioctl);
  191 static dev_type_stop(dhustop);
  192 static dev_type_tty(dhutty);
  193 static dev_type_poll(dhupoll);
  194 
  195 const struct cdevsw dhu_cdevsw = {
  196         .d_open = dhuopen,
  197         .d_close = dhuclose,
  198         .d_read = dhuread,
  199         .d_write = dhuwrite,
  200         .d_ioctl = dhuioctl,
  201         .d_stop = dhustop,
  202         .d_tty = dhutty,
  203         .d_poll = dhupoll,
  204         .d_mmap = nommap,
  205         .d_kqfilter = ttykqfilter,
  206         .d_discard = nodiscard,
  207         .d_flag = D_TTY
  208 };
  209 
  210 /* Autoconfig handles: setup the controller to interrupt, */
  211 /* then complete the housecleaning for full operation */
  212 
  213 static int
  214 dhu_match(device_t parent, cfdata_t cf, void *aux)
  215 {
  216         struct uba_attach_args *ua = aux;
  217         int n;
  218 
  219         /* Reset controller to initialize, enable TX/RX interrupts */
  220         /* to catch floating vector info elsewhere when completed */
  221 
  222         bus_space_write_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR,
  223             DHU_CSR_MASTER_RESET | DHU_CSR_RXIE | DHU_CSR_TXIE);
  224 
  225         /* Now wait up to 3 seconds for self-test to complete. */
  226 
  227         for (n = 0; n < 300; n++) {
  228                 DELAY(10000);
  229                 if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR) &
  230                     DHU_CSR_MASTER_RESET) == 0)
  231                         break;
  232         }
  233 
  234         /* If the RESET did not clear after 3 seconds, */
  235         /* the controller must be broken. */
  236 
  237         if (n >= 300)
  238                 return 0;
  239 
  240         /* Check whether diagnostic run has signalled a failure. */
  241 
  242         if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR) &
  243             DHU_CSR_DIAG_FAIL) != 0)
  244                 return 0;
  245 
  246         return 1;
  247 }
  248 
  249 static void
  250 dhu_attach(device_t parent, device_t self, void *aux)
  251 {
  252         struct dhu_softc *sc = device_private(self);
  253         struct uba_attach_args *ua = aux;
  254         unsigned c;
  255         int n, i;
  256 
  257         sc->sc_dev = self;
  258         sc->sc_iot = ua->ua_iot;
  259         sc->sc_ioh = ua->ua_ioh;
  260         sc->sc_dmat = ua->ua_dmat;
  261         /* Process the 8 bytes of diagnostic info put into */
  262         /* the FIFO following the master reset operation. */
  263 
  264         aprint_normal("\n");
  265         for (n = 0; n < 8; n++) {
  266                 c = DHU_READ_WORD(DHU_UBA_RBUF);
  267 
  268                 if ((c&DHU_DIAG_CODE) == DHU_DIAG_CODE) {
  269                         if ((c&0200) == 0000)
  270                                 aprint_error_dev(self, "rom(%d) version %d\n",
  271                                         ((c>>1)&01), ((c>>2)&037));
  272                         else if (((c>>2)&07) != 0)
  273                                 aprint_error_dev(self, "diag-error(proc%d)=%x\n",
  274                                         ((c>>1)&01), ((c>>2)&07));
  275                 }
  276         }
  277 
  278         c = DHU_READ_WORD(DHU_UBA_STAT);
  279 
  280         sc->sc_type = (c & DHU_STAT_DHU)? IS_DHU: IS_DHV;
  281 
  282         sc->sc_lines = 8;       /* default */
  283         if (sc->sc_type == IS_DHU && (c & DHU_STAT_MDL))
  284                 sc->sc_lines = 16;
  285 
  286         aprint_normal_dev(self, "DH%s-11\n",
  287             sc->sc_type == IS_DHU ? "U" : "V");
  288 
  289         for (i = 0; i < sc->sc_lines; i++) {
  290                 struct tty *tp;
  291 
  292                 tp = sc->sc_dhu[i].dhu_tty = tty_alloc();
  293                 sc->sc_dhu[i].dhu_state = STATE_IDLE;
  294                 bus_dmamap_create(sc->sc_dmat, tp->t_outq.c_cn, 1,
  295                     tp->t_outq.c_cn, 0, BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT,
  296                     &sc->sc_dhu[i].dhu_dmah);
  297                 bus_dmamap_load(sc->sc_dmat, sc->sc_dhu[i].dhu_dmah,
  298                     tp->t_outq.c_cs, tp->t_outq.c_cn, 0, BUS_DMA_NOWAIT);
  299 
  300         }
  301 
  302         /* Now establish RX & TX interrupt handlers */
  303 
  304         uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
  305                 dhurint, sc, &sc->sc_rintrcnt);
  306         uba_intr_establish(ua->ua_icookie, ua->ua_cvec + 4,
  307                 dhuxint, sc, &sc->sc_tintrcnt);
  308         evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  309                 device_xname(sc->sc_dev), "rintr");
  310         evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  311                 device_xname(sc->sc_dev), "tintr");
  312 }
  313 
  314 /* Receiver Interrupt */
  315 
  316 static void
  317 dhurint(void *arg)
  318 {
  319         struct dhu_softc *sc = arg;
  320         struct tty *tp;
  321         int cc, line;
  322         unsigned c, delta;
  323         int overrun = 0;
  324 
  325         while ((c = DHU_READ_WORD(DHU_UBA_RBUF)) & DHU_RBUF_DATA_VALID) {
  326 
  327                 /* Ignore diagnostic FIFO entries. */
  328 
  329                 if ((c & DHU_DIAG_CODE) == DHU_DIAG_CODE)
  330                         continue;
  331 
  332                 cc = c & 0xFF;
  333                 line = DHU_LINE(c>>8);
  334                 tp = sc->sc_dhu[line].dhu_tty;
  335 
  336                 /* LINK.TYPE is set so we get modem control FIFO entries */
  337 
  338                 if ((c & DHU_DIAG_CODE) == DHU_MODEM_CODE) {
  339                         c = (c << 8);
  340                         /* Do MDMBUF flow control, wakeup sleeping opens */
  341                         if (c & DHU_STAT_DCD) {
  342                                 if (!(tp->t_state & TS_CARR_ON))
  343                                     (void)(*tp->t_linesw->l_modem)(tp, 1);
  344                         }
  345                         else if ((tp->t_state & TS_CARR_ON) &&
  346                                 (*tp->t_linesw->l_modem)(tp, 0) == 0)
  347                                         (void) dhumctl(sc, line, 0, DMSET);
  348 
  349                         /* Do CRTSCTS flow control */
  350                         delta = c ^ sc->sc_dhu[line].dhu_modem;
  351                         sc->sc_dhu[line].dhu_modem = c;
  352                         if ((delta & DHU_STAT_CTS) &&
  353                             (tp->t_state & TS_ISOPEN) &&
  354                             (tp->t_cflag & CRTSCTS)) {
  355                                 if (c & DHU_STAT_CTS) {
  356                                         tp->t_state &= ~TS_TTSTOP;
  357                                         ttstart(tp);
  358                                 } else {
  359                                         tp->t_state |= TS_TTSTOP;
  360                                         dhustop(tp, 0);
  361                                 }
  362                         }
  363                         continue;
  364                 }
  365 
  366                 if (!(tp->t_state & TS_ISOPEN)) {
  367                         cv_broadcast(&tp->t_rawcv);
  368                         continue;
  369                 }
  370 
  371                 if ((c & DHU_RBUF_OVERRUN_ERR) && overrun == 0) {
  372                         log(LOG_WARNING, "%s: silo overflow, line %d\n",
  373                                 device_xname(sc->sc_dev), line);
  374                         overrun = 1;
  375                 }
  376                 /* A BREAK key will appear as a NULL with a framing error */
  377                 if (c & DHU_RBUF_FRAMING_ERR)
  378                         cc |= TTY_FE;
  379                 if (c & DHU_RBUF_PARITY_ERR)
  380                         cc |= TTY_PE;
  381 
  382                 (*tp->t_linesw->l_rint)(cc, tp);
  383         }
  384 }
  385 
  386 /* Transmitter Interrupt */
  387 
  388 static void
  389 dhuxint(void *arg)
  390 {
  391         struct dhu_softc *sc = arg;
  392         struct tty *tp;
  393         int line, i;
  394 
  395         while ((i = DHU_READ_BYTE(DHU_UBA_CSR_HI)) & (DHU_CSR_TX_ACTION >> 8)) {
  396 
  397                 line = DHU_LINE(i);
  398                 tp = sc->sc_dhu[line].dhu_tty;
  399 
  400                 if (i & (DHU_CSR_TX_DMA_ERROR >> 8))
  401                         printf("%s: DMA ERROR on line: %d\n",
  402                             device_xname(sc->sc_dev), line);
  403                 if (i & (DHU_CSR_DIAG_FAIL >> 8))
  404                         printf("%s: DIAG FAIL on line: %d\n",
  405                             device_xname(sc->sc_dev), line);
  406 
  407                 tp->t_state &= ~TS_BUSY;
  408                 if (tp->t_state & TS_FLUSH)
  409                         tp->t_state &= ~TS_FLUSH;
  410                 else {
  411                         if (sc->sc_dhu[line].dhu_state == STATE_DMA_STOPPED)
  412                                 sc->sc_dhu[line].dhu_cc -=
  413                                     DHU_READ_WORD(DHU_UBA_TBUFCNT);
  414                         ndflush(&tp->t_outq, sc->sc_dhu[line].dhu_cc);
  415                         sc->sc_dhu[line].dhu_cc = 0;
  416                 }
  417 
  418                 sc->sc_dhu[line].dhu_state = STATE_IDLE;
  419 
  420                 (*tp->t_linesw->l_start)(tp);
  421         }
  422 }
  423 
  424 int
  425 dhuopen(dev_t dev, int flag, int mode, struct lwp *l)
  426 {
  427         struct tty *tp;
  428         int unit, line;
  429         struct dhu_softc *sc;
  430         int error = 0;
  431 
  432         unit = DHU_M2U(minor(dev));
  433         line = DHU_LINE(minor(dev));
  434 
  435         sc = device_lookup_private(&dhu_cd, unit);
  436         if (!sc)
  437                 return (ENXIO);
  438 
  439         if (line >= sc->sc_lines)
  440                 return ENXIO;
  441 
  442         tp = sc->sc_dhu[line].dhu_tty;
  443         ttylock(tp);
  444         if (sc->sc_type == IS_DHU) {
  445                 /* CSR 3:0 must be 0 */
  446                 DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE);
  447                 /* RX int delay 10ms */
  448                 DHU_WRITE_BYTE(DHU_UBA_RXTIME, 10);
  449         }
  450         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  451         sc->sc_dhu[line].dhu_modem = DHU_READ_WORD(DHU_UBA_STAT);
  452 
  453         if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
  454                 return (EBUSY);
  455 
  456         tp->t_oproc   = dhustart;
  457         tp->t_param   = dhuparam;
  458         tp->t_hwiflow = dhuiflow;
  459         tp->t_dev = dev;
  460 
  461         if ((tp->t_state & TS_ISOPEN) == 0) {
  462                 ttychars(tp);
  463                 if (tp->t_ispeed == 0) {
  464                         tp->t_iflag = TTYDEF_IFLAG;
  465                         tp->t_oflag = TTYDEF_OFLAG;
  466                         tp->t_cflag = TTYDEF_CFLAG;
  467                         tp->t_lflag = TTYDEF_LFLAG;
  468                         tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
  469                 }
  470                 (void) dhuparam(tp, &tp->t_termios);
  471                 ttsetwater(tp);
  472         }
  473         /* Use DMBIS and *not* DMSET or else we clobber incoming bits */
  474         if (dhumctl(sc, line, DML_DTR|DML_RTS, DMBIS) & DML_DCD)
  475                 tp->t_state |= TS_CARR_ON;
  476         while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
  477             !(tp->t_state & TS_CARR_ON)) {
  478                 tp->t_wopen++;
  479                 error = ttysleep(tp, &tp->t_rawcv, true, 0);
  480                 tp->t_wopen--;
  481                 if (error)
  482                         break;
  483         }
  484         ttyunlock(tp);
  485         if (error)
  486                 return (error);
  487         return ((*tp->t_linesw->l_open)(dev, tp));
  488 }
  489 
  490 /*ARGSUSED*/
  491 int
  492 dhuclose(dev_t dev, int flag, int mode, struct lwp *l)
  493 {
  494         const int unit = DHU_M2U(minor(dev));
  495         const int line = DHU_LINE(minor(dev));
  496         struct dhu_softc *sc = device_lookup_private(&dhu_cd, unit);
  497         struct tty *tp = sc->sc_dhu[line].dhu_tty;
  498 
  499         (*tp->t_linesw->l_close)(tp, flag);
  500 
  501         /* Make sure a BREAK state is not left enabled. */
  502 
  503         (void) dhumctl(sc, line, DML_BRK, DMBIC);
  504 
  505         /* Do a hangup if so required. */
  506 
  507         if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN))
  508                 (void) dhumctl(sc, line, 0, DMSET);
  509 
  510         return (ttyclose(tp));
  511 }
  512 
  513 int
  514 dhuread(dev_t dev, struct uio *uio, int flag)
  515 {
  516         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  517         struct tty *tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  518 
  519         return ((*tp->t_linesw->l_read)(tp, uio, flag));
  520 }
  521 
  522 int
  523 dhuwrite(dev_t dev, struct uio *uio, int flag)
  524 {
  525         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  526         struct tty *tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  527 
  528         return ((*tp->t_linesw->l_write)(tp, uio, flag));
  529 }
  530 
  531 int
  532 dhupoll(dev_t dev, int events, struct lwp *l)
  533 {
  534         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  535         struct tty *tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  536 
  537         return ((*tp->t_linesw->l_poll)(tp, events, l));
  538 }
  539 
  540 /*ARGSUSED*/
  541 int
  542 dhuioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
  543 {
  544         const int unit = DHU_M2U(minor(dev));
  545         const int line = DHU_LINE(minor(dev));
  546         struct dhu_softc *sc = device_lookup_private(&dhu_cd, unit);
  547         struct tty *tp = sc->sc_dhu[line].dhu_tty;
  548         int error;
  549 
  550         error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
  551         if (error != EPASSTHROUGH)
  552                 return (error);
  553 
  554         error = ttioctl(tp, cmd, data, flag, l);
  555         if (error != EPASSTHROUGH)
  556                 return (error);
  557 
  558         switch (cmd) {
  559 
  560         case TIOCSBRK:
  561                 (void) dhumctl(sc, line, DML_BRK, DMBIS);
  562                 break;
  563 
  564         case TIOCCBRK:
  565                 (void) dhumctl(sc, line, DML_BRK, DMBIC);
  566                 break;
  567 
  568         case TIOCSDTR:
  569                 (void) dhumctl(sc, line, DML_DTR|DML_RTS, DMBIS);
  570                 break;
  571 
  572         case TIOCCDTR:
  573                 (void) dhumctl(sc, line, DML_DTR|DML_RTS, DMBIC);
  574                 break;
  575 
  576         case TIOCMSET:
  577                 (void) dhumctl(sc, line, *(int *)data, DMSET);
  578                 break;
  579 
  580         case TIOCMBIS:
  581                 (void) dhumctl(sc, line, *(int *)data, DMBIS);
  582                 break;
  583 
  584         case TIOCMBIC:
  585                 (void) dhumctl(sc, line, *(int *)data, DMBIC);
  586                 break;
  587 
  588         case TIOCMGET:
  589                 *(int *)data = (dhumctl(sc, line, 0, DMGET) & ~DML_BRK);
  590                 break;
  591 
  592         default:
  593                 return (EPASSTHROUGH);
  594         }
  595         return (0);
  596 }
  597 
  598 struct tty *
  599 dhutty(dev_t dev)
  600 {
  601         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  602 
  603         return sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  604 }
  605 
  606 /*ARGSUSED*/
  607 void
  608 dhustop(struct tty *tp, int flag)
  609 {
  610         int s;
  611 
  612         s = spltty();
  613 
  614         if (tp->t_state & TS_BUSY) {
  615                 const int unit = DHU_M2U(minor(tp->t_dev));
  616                 const int line = DHU_LINE(minor(tp->t_dev));
  617                 struct dhu_softc *sc = device_lookup_private(&dhu_cd, unit);
  618 
  619                 if (sc->sc_dhu[line].dhu_state == STATE_DMA_RUNNING) {
  620 
  621                         sc->sc_dhu[line].dhu_state = STATE_DMA_STOPPED;
  622 
  623                         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  624                         DHU_WRITE_WORD(DHU_UBA_LNCTRL,
  625                             DHU_READ_WORD(DHU_UBA_LNCTRL) |
  626                             DHU_LNCTRL_DMA_ABORT);
  627                 }
  628 
  629                 if (!(tp->t_state & TS_TTSTOP))
  630                         tp->t_state |= TS_FLUSH;
  631         }
  632         (void) splx(s);
  633 }
  634 
  635 static void
  636 dhustart(struct tty *tp)
  637 {
  638         struct dhu_softc *sc;
  639         int line, cc;
  640         int addr;
  641         int s;
  642 
  643         s = spltty();
  644         if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
  645                 goto out;
  646         if (!ttypull(tp))
  647                 goto out;
  648         cc = ndqb(&tp->t_outq, 0);
  649         if (cc == 0)
  650                 goto out;
  651 
  652         tp->t_state |= TS_BUSY;
  653 
  654         sc = device_lookup_private(&dhu_cd,DHU_M2U(minor(tp->t_dev)));
  655 
  656         line = DHU_LINE(minor(tp->t_dev));
  657 
  658         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  659 
  660         sc->sc_dhu[line].dhu_cc = cc;
  661 
  662         if (cc == 1 && sc->sc_type == IS_DHV) {
  663 
  664                 sc->sc_dhu[line].dhu_state = STATE_TX_ONE_CHAR;
  665 
  666                 DHU_WRITE_WORD(DHU_UBA_TXCHAR,
  667                     DHU_TXCHAR_DATA_VALID | *tp->t_outq.c_cf);
  668 
  669         } else {
  670 
  671                 sc->sc_dhu[line].dhu_state = STATE_DMA_RUNNING;
  672 
  673                 addr = sc->sc_dhu[line].dhu_dmah->dm_segs[0].ds_addr +
  674                         (tp->t_outq.c_cf - tp->t_outq.c_cs);
  675 
  676                 DHU_WRITE_WORD(DHU_UBA_TBUFCNT, cc);
  677                 DHU_WRITE_WORD(DHU_UBA_TBUFAD1, addr & 0xFFFF);
  678                 DHU_WRITE_WORD(DHU_UBA_TBUFAD2, ((addr>>16) & 0x3F) |
  679                     DHU_TBUFAD2_TX_ENABLE);
  680                 DHU_WRITE_WORD(DHU_UBA_LNCTRL,
  681                     DHU_READ_WORD(DHU_UBA_LNCTRL) & ~DHU_LNCTRL_DMA_ABORT);
  682                 DHU_WRITE_WORD(DHU_UBA_TBUFAD2,
  683                     DHU_READ_WORD(DHU_UBA_TBUFAD2) | DHU_TBUFAD2_DMA_START);
  684         }
  685 out:
  686         (void) splx(s);
  687         return;
  688 }
  689 
  690 static int
  691 dhuparam(struct tty *tp, struct termios *t)
  692 {
  693         int cflag = t->c_cflag;
  694         int ispeed = ttspeedtab(t->c_ispeed, dhuspeedtab);
  695         int ospeed = ttspeedtab(t->c_ospeed, dhuspeedtab);
  696         unsigned int lpr;
  697         unsigned int lnctrl;
  698         const int unit = DHU_M2U(minor(tp->t_dev));
  699         const int line = DHU_LINE(minor(tp->t_dev));
  700         struct dhu_softc * const sc = device_lookup_private(&dhu_cd, unit);
  701         int s;
  702 
  703 
  704         /* check requested parameters */
  705         if (ospeed < 0 || ispeed < 0)
  706                 return (EINVAL);
  707 
  708         tp->t_ispeed = t->c_ispeed;
  709         tp->t_ospeed = t->c_ospeed;
  710         tp->t_cflag = cflag;
  711 
  712         if (ospeed == 0) {
  713                 (void) dhumctl(sc, line, 0, DMSET);     /* hang up line */
  714                 return (0);
  715         }
  716 
  717         s = spltty();
  718         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  719 
  720         lpr = ((ispeed&017)<<8) | ((ospeed&017)<<12) ;
  721 
  722         switch (cflag & CSIZE) {
  723 
  724         case CS5:
  725                 lpr |= DHU_LPR_5_BIT_CHAR;
  726                 break;
  727 
  728         case CS6:
  729                 lpr |= DHU_LPR_6_BIT_CHAR;
  730                 break;
  731 
  732         case CS7:
  733                 lpr |= DHU_LPR_7_BIT_CHAR;
  734                 break;
  735 
  736         default:
  737                 lpr |= DHU_LPR_8_BIT_CHAR;
  738                 break;
  739         }
  740 
  741         if (cflag & PARENB)
  742                 lpr |= DHU_LPR_PARENB;
  743         if (!(cflag & PARODD))
  744                 lpr |= DHU_LPR_EPAR;
  745         if (cflag & CSTOPB)
  746                 lpr |= DHU_LPR_2_STOP;
  747 
  748         DHU_WRITE_WORD(DHU_UBA_LPR, lpr);
  749 
  750         DHU_WRITE_WORD(DHU_UBA_TBUFAD2,
  751             DHU_READ_WORD(DHU_UBA_TBUFAD2) | DHU_TBUFAD2_TX_ENABLE);
  752 
  753         lnctrl = DHU_READ_WORD(DHU_UBA_LNCTRL);
  754 
  755         /* Setting LINK.TYPE enables modem signal change interrupts. */
  756 
  757         lnctrl |= (DHU_LNCTRL_RX_ENABLE | DHU_LNCTRL_LINK_TYPE);
  758 
  759         /* Enable the auto XON/XOFF feature on the controller */
  760 
  761         if (t->c_iflag & IXON)
  762                 lnctrl |= DHU_LNCTRL_OAUTO;
  763         else
  764                 lnctrl &= ~DHU_LNCTRL_OAUTO;
  765 
  766         if (t->c_iflag & IXOFF)
  767                 lnctrl |= DHU_LNCTRL_IAUTO;
  768         else
  769                 lnctrl &= ~DHU_LNCTRL_IAUTO;
  770 
  771         DHU_WRITE_WORD(DHU_UBA_LNCTRL, lnctrl);
  772 
  773         (void) splx(s);
  774         return (0);
  775 }
  776 
  777 static int
  778 dhuiflow(struct tty *tp, int flag)
  779 {
  780 
  781         if (tp->t_cflag & CRTSCTS) {
  782                 const int unit = DHU_M2U(minor(tp->t_dev));
  783                 const int line = DHU_LINE(minor(tp->t_dev));
  784                 struct dhu_softc * const sc = device_lookup_private(&dhu_cd, unit);
  785                 (void) dhumctl(sc, line, DML_RTS, ((flag)? DMBIC: DMBIS));
  786                 return (1);
  787         }
  788         return (0);
  789 }
  790 
  791 static unsigned int
  792 dhumctl(struct dhu_softc *sc, int line, int bits, int how)
  793 {
  794         unsigned status;
  795         unsigned lnctrl;
  796         unsigned mbits;
  797         int s;
  798 
  799         s = spltty();
  800 
  801         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  802 
  803         mbits = 0;
  804 
  805         /* external signals as seen from the port */
  806 
  807         status = DHU_READ_WORD(DHU_UBA_STAT);
  808 
  809         if (status & DHU_STAT_CTS)
  810                 mbits |= DML_CTS;
  811 
  812         if (status & DHU_STAT_DCD)
  813                 mbits |= DML_DCD;
  814 
  815         if (status & DHU_STAT_DSR)
  816                 mbits |= DML_DSR;
  817 
  818         if (status & DHU_STAT_RI)
  819                 mbits |= DML_RI;
  820 
  821         /* internal signals/state delivered to port */
  822 
  823         lnctrl = DHU_READ_WORD(DHU_UBA_LNCTRL);
  824 
  825         if (lnctrl & DHU_LNCTRL_RTS)
  826                 mbits |= DML_RTS;
  827 
  828         if (lnctrl & DHU_LNCTRL_DTR)
  829                 mbits |= DML_DTR;
  830 
  831         if (lnctrl & DHU_LNCTRL_BREAK)
  832                 mbits |= DML_BRK;
  833 
  834         switch (how) {
  835 
  836         case DMSET:
  837                 mbits = bits;
  838                 break;
  839 
  840         case DMBIS:
  841                 mbits |= bits;
  842                 break;
  843 
  844         case DMBIC:
  845                 mbits &= ~bits;
  846                 break;
  847 
  848         case DMGET:
  849                 (void) splx(s);
  850                 return (mbits);
  851         }
  852 
  853         if (mbits & DML_RTS)
  854                 lnctrl |= DHU_LNCTRL_RTS;
  855         else
  856                 lnctrl &= ~DHU_LNCTRL_RTS;
  857 
  858         if (mbits & DML_DTR)
  859                 lnctrl |= DHU_LNCTRL_DTR;
  860         else
  861                 lnctrl &= ~DHU_LNCTRL_DTR;
  862 
  863         if (mbits & DML_BRK)
  864                 lnctrl |= DHU_LNCTRL_BREAK;
  865         else
  866                 lnctrl &= ~DHU_LNCTRL_BREAK;
  867 
  868         DHU_WRITE_WORD(DHU_UBA_LNCTRL, lnctrl);
  869 
  870         (void) splx(s);
  871         return (mbits);
  872 }

Cache object: 45852e5ce9d5de8c83e9cb20ec810a7b


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