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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: dhu.c,v 1.55 2008/06/11 17:27:59 drochner 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.55 2008/06/11 17:27:59 drochner 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_flag = D_TTY
  207 };
  208 
  209 /* Autoconfig handles: setup the controller to interrupt, */
  210 /* then complete the housecleaning for full operation */
  211 
  212 static int
  213 dhu_match(device_t parent, cfdata_t cf, void *aux)
  214 {
  215         struct uba_attach_args *ua = aux;
  216         int n;
  217 
  218         /* Reset controller to initialize, enable TX/RX interrupts */
  219         /* to catch floating vector info elsewhere when completed */
  220 
  221         bus_space_write_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR,
  222             DHU_CSR_MASTER_RESET | DHU_CSR_RXIE | DHU_CSR_TXIE);
  223 
  224         /* Now wait up to 3 seconds for self-test to complete. */
  225 
  226         for (n = 0; n < 300; n++) {
  227                 DELAY(10000);
  228                 if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR) &
  229                     DHU_CSR_MASTER_RESET) == 0)
  230                         break;
  231         }
  232 
  233         /* If the RESET did not clear after 3 seconds, */
  234         /* the controller must be broken. */
  235 
  236         if (n >= 300)
  237                 return 0;
  238 
  239         /* Check whether diagnostic run has signalled a failure. */
  240 
  241         if ((bus_space_read_2(ua->ua_iot, ua->ua_ioh, DHU_UBA_CSR) &
  242             DHU_CSR_DIAG_FAIL) != 0)
  243                 return 0;
  244 
  245         return 1;
  246 }
  247 
  248 static void
  249 dhu_attach(device_t parent, device_t self, void *aux)
  250 {
  251         struct dhu_softc *sc = device_private(self);
  252         struct uba_attach_args *ua = aux;
  253         unsigned c;
  254         int n, i;
  255 
  256         sc->sc_dev = self;
  257         sc->sc_iot = ua->ua_iot;
  258         sc->sc_ioh = ua->ua_ioh;
  259         sc->sc_dmat = ua->ua_dmat;
  260         /* Process the 8 bytes of diagnostic info put into */
  261         /* the FIFO following the master reset operation. */
  262 
  263         aprint_normal("\n");
  264         for (n = 0; n < 8; n++) {
  265                 c = DHU_READ_WORD(DHU_UBA_RBUF);
  266 
  267                 if ((c&DHU_DIAG_CODE) == DHU_DIAG_CODE) {
  268                         if ((c&0200) == 0000)
  269                                 aprint_error_dev(self, "rom(%d) version %d\n",
  270                                         ((c>>1)&01), ((c>>2)&037));
  271                         else if (((c>>2)&07) != 0)
  272                                 aprint_error_dev(self, "diag-error(proc%d)=%x\n",
  273                                         ((c>>1)&01), ((c>>2)&07));
  274                 }
  275         }
  276 
  277         c = DHU_READ_WORD(DHU_UBA_STAT);
  278 
  279         sc->sc_type = (c & DHU_STAT_DHU)? IS_DHU: IS_DHV;
  280 
  281         sc->sc_lines = 8;       /* default */
  282         if (sc->sc_type == IS_DHU && (c & DHU_STAT_MDL))
  283                 sc->sc_lines = 16;
  284 
  285         aprint_normal_dev(self, "DH%s-11\n",
  286             sc->sc_type == IS_DHU ? "U" : "V");
  287 
  288         for (i = 0; i < sc->sc_lines; i++) {
  289                 struct tty *tp;
  290                 tp = sc->sc_dhu[i].dhu_tty = ttymalloc();
  291                 sc->sc_dhu[i].dhu_state = STATE_IDLE;
  292                 bus_dmamap_create(sc->sc_dmat, tp->t_outq.c_cn, 1,
  293                     tp->t_outq.c_cn, 0, BUS_DMA_ALLOCNOW|BUS_DMA_NOWAIT,
  294                     &sc->sc_dhu[i].dhu_dmah);
  295                 bus_dmamap_load(sc->sc_dmat, sc->sc_dhu[i].dhu_dmah,
  296                     tp->t_outq.c_cs, tp->t_outq.c_cn, 0, BUS_DMA_NOWAIT);
  297 
  298         }
  299 
  300         /* Now establish RX & TX interrupt handlers */
  301 
  302         uba_intr_establish(ua->ua_icookie, ua->ua_cvec,
  303                 dhurint, sc, &sc->sc_rintrcnt);
  304         uba_intr_establish(ua->ua_icookie, ua->ua_cvec + 4,
  305                 dhuxint, sc, &sc->sc_tintrcnt);
  306         evcnt_attach_dynamic(&sc->sc_rintrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  307                 device_xname(sc->sc_dev), "rintr");
  308         evcnt_attach_dynamic(&sc->sc_tintrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
  309                 device_xname(sc->sc_dev), "tintr");
  310 }
  311 
  312 /* Receiver Interrupt */
  313 
  314 static void
  315 dhurint(void *arg)
  316 {
  317         struct dhu_softc *sc = arg;
  318         struct tty *tp;
  319         int cc, line;
  320         unsigned c, delta;
  321         int overrun = 0;
  322 
  323         while ((c = DHU_READ_WORD(DHU_UBA_RBUF)) & DHU_RBUF_DATA_VALID) {
  324 
  325                 /* Ignore diagnostic FIFO entries. */
  326 
  327                 if ((c & DHU_DIAG_CODE) == DHU_DIAG_CODE)
  328                         continue;
  329 
  330                 cc = c & 0xFF;
  331                 line = DHU_LINE(c>>8);
  332                 tp = sc->sc_dhu[line].dhu_tty;
  333 
  334                 /* LINK.TYPE is set so we get modem control FIFO entries */
  335 
  336                 if ((c & DHU_DIAG_CODE) == DHU_MODEM_CODE) {
  337                         c = (c << 8);
  338                         /* Do MDMBUF flow control, wakeup sleeping opens */
  339                         if (c & DHU_STAT_DCD) {
  340                                 if (!(tp->t_state & TS_CARR_ON))
  341                                     (void)(*tp->t_linesw->l_modem)(tp, 1);
  342                         }
  343                         else if ((tp->t_state & TS_CARR_ON) &&
  344                                 (*tp->t_linesw->l_modem)(tp, 0) == 0)
  345                                         (void) dhumctl(sc, line, 0, DMSET);
  346 
  347                         /* Do CRTSCTS flow control */
  348                         delta = c ^ sc->sc_dhu[line].dhu_modem;
  349                         sc->sc_dhu[line].dhu_modem = c;
  350                         if ((delta & DHU_STAT_CTS) &&
  351                             (tp->t_state & TS_ISOPEN) &&
  352                             (tp->t_cflag & CRTSCTS)) {
  353                                 if (c & DHU_STAT_CTS) {
  354                                         tp->t_state &= ~TS_TTSTOP;
  355                                         ttstart(tp);
  356                                 } else {
  357                                         tp->t_state |= TS_TTSTOP;
  358                                         dhustop(tp, 0);
  359                                 }
  360                         }
  361                         continue;
  362                 }
  363 
  364                 if (!(tp->t_state & TS_ISOPEN)) {
  365                         cv_broadcast(&tp->t_rawcv);
  366                         continue;
  367                 }
  368 
  369                 if ((c & DHU_RBUF_OVERRUN_ERR) && overrun == 0) {
  370                         log(LOG_WARNING, "%s: silo overflow, line %d\n",
  371                                 device_xname(sc->sc_dev), line);
  372                         overrun = 1;
  373                 }
  374                 /* A BREAK key will appear as a NULL with a framing error */
  375                 if (c & DHU_RBUF_FRAMING_ERR)
  376                         cc |= TTY_FE;
  377                 if (c & DHU_RBUF_PARITY_ERR)
  378                         cc |= TTY_PE;
  379 
  380                 (*tp->t_linesw->l_rint)(cc, tp);
  381         }
  382 }
  383 
  384 /* Transmitter Interrupt */
  385 
  386 static void
  387 dhuxint(void *arg)
  388 {
  389         struct dhu_softc *sc = arg;
  390         struct tty *tp;
  391         int line, i;
  392 
  393         while ((i = DHU_READ_BYTE(DHU_UBA_CSR_HI)) & (DHU_CSR_TX_ACTION >> 8)) {
  394 
  395                 line = DHU_LINE(i);
  396                 tp = sc->sc_dhu[line].dhu_tty;
  397 
  398                 if (i & (DHU_CSR_TX_DMA_ERROR >> 8))
  399                         printf("%s: DMA ERROR on line: %d\n",
  400                             device_xname(sc->sc_dev), line);
  401                 if (i & (DHU_CSR_DIAG_FAIL >> 8))
  402                         printf("%s: DIAG FAIL on line: %d\n",
  403                             device_xname(sc->sc_dev), line);
  404 
  405                 tp->t_state &= ~TS_BUSY;
  406                 if (tp->t_state & TS_FLUSH)
  407                         tp->t_state &= ~TS_FLUSH;
  408                 else {
  409                         if (sc->sc_dhu[line].dhu_state == STATE_DMA_STOPPED)
  410                                 sc->sc_dhu[line].dhu_cc -=
  411                                     DHU_READ_WORD(DHU_UBA_TBUFCNT);
  412                         ndflush(&tp->t_outq, sc->sc_dhu[line].dhu_cc);
  413                         sc->sc_dhu[line].dhu_cc = 0;
  414                 }
  415 
  416                 sc->sc_dhu[line].dhu_state = STATE_IDLE;
  417 
  418                 (*tp->t_linesw->l_start)(tp);
  419         }
  420 }
  421 
  422 int
  423 dhuopen(dev_t dev, int flag, int mode, struct lwp *l)
  424 {
  425         struct tty *tp;
  426         int unit, line;
  427         struct dhu_softc *sc;
  428         int error = 0;
  429 
  430         unit = DHU_M2U(minor(dev));
  431         line = DHU_LINE(minor(dev));
  432 
  433         sc = device_lookup_private(&dhu_cd, unit);
  434         if (!sc)
  435                 return (ENXIO);
  436 
  437         if (line >= sc->sc_lines)
  438                 return ENXIO;
  439 
  440         mutex_spin_enter(&tty_lock);
  441         if (sc->sc_type == IS_DHU) {
  442                 /* CSR 3:0 must be 0 */
  443                 DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE);
  444                 /* RX int delay 10ms */
  445                 DHU_WRITE_BYTE(DHU_UBA_RXTIME, 10);
  446         }
  447         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  448         sc->sc_dhu[line].dhu_modem = DHU_READ_WORD(DHU_UBA_STAT);
  449 
  450         tp = sc->sc_dhu[line].dhu_tty;
  451 
  452         if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
  453                 return (EBUSY);
  454 
  455         tp->t_oproc   = dhustart;
  456         tp->t_param   = dhuparam;
  457         tp->t_hwiflow = dhuiflow;
  458         tp->t_dev = dev;
  459 
  460         if ((tp->t_state & TS_ISOPEN) == 0) {
  461                 ttychars(tp);
  462                 if (tp->t_ispeed == 0) {
  463                         tp->t_iflag = TTYDEF_IFLAG;
  464                         tp->t_oflag = TTYDEF_OFLAG;
  465                         tp->t_cflag = TTYDEF_CFLAG;
  466                         tp->t_lflag = TTYDEF_LFLAG;
  467                         tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
  468                 }
  469                 (void) dhuparam(tp, &tp->t_termios);
  470                 ttsetwater(tp);
  471         }
  472         /* Use DMBIS and *not* DMSET or else we clobber incoming bits */
  473         if (dhumctl(sc, line, DML_DTR|DML_RTS, DMBIS) & DML_DCD)
  474                 tp->t_state |= TS_CARR_ON;
  475         while (!(flag & O_NONBLOCK) && !(tp->t_cflag & CLOCAL) &&
  476             !(tp->t_state & TS_CARR_ON)) {
  477                 tp->t_wopen++;
  478                 error = ttysleep(tp, &tp->t_rawcv, true, 0);
  479                 tp->t_wopen--;
  480                 if (error)
  481                         break;
  482         }
  483         mutex_spin_exit(&tty_lock);
  484         if (error)
  485                 return (error);
  486         return ((*tp->t_linesw->l_open)(dev, tp));
  487 }
  488 
  489 /*ARGSUSED*/
  490 int
  491 dhuclose(dev_t dev, int flag, int mode, struct lwp *l)
  492 {
  493         const int unit = DHU_M2U(minor(dev));
  494         const int line = DHU_LINE(minor(dev));
  495         struct dhu_softc *sc = device_lookup_private(&dhu_cd, unit);
  496         struct tty *tp = sc->sc_dhu[line].dhu_tty;
  497 
  498         (*tp->t_linesw->l_close)(tp, flag);
  499 
  500         /* Make sure a BREAK state is not left enabled. */
  501 
  502         (void) dhumctl(sc, line, DML_BRK, DMBIC);
  503 
  504         /* Do a hangup if so required. */
  505 
  506         if ((tp->t_cflag & HUPCL) || tp->t_wopen || !(tp->t_state & TS_ISOPEN))
  507                 (void) dhumctl(sc, line, 0, DMSET);
  508 
  509         return (ttyclose(tp));
  510 }
  511 
  512 int
  513 dhuread(dev_t dev, struct uio *uio, int flag)
  514 {
  515         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  516         struct tty *tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  517 
  518         return ((*tp->t_linesw->l_read)(tp, uio, flag));
  519 }
  520 
  521 int
  522 dhuwrite(dev_t dev, struct uio *uio, int flag)
  523 {
  524         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  525         struct tty *tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  526 
  527         return ((*tp->t_linesw->l_write)(tp, uio, flag));
  528 }
  529 
  530 int
  531 dhupoll(dev_t dev, int events, struct lwp *l)
  532 {
  533         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  534         struct tty *tp = sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  535 
  536         return ((*tp->t_linesw->l_poll)(tp, events, l));
  537 }
  538 
  539 /*ARGSUSED*/
  540 int
  541 dhuioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
  542 {
  543         const int unit = DHU_M2U(minor(dev));
  544         const int line = DHU_LINE(minor(dev));
  545         struct dhu_softc *sc = device_lookup_private(&dhu_cd, unit);
  546         struct tty *tp = sc->sc_dhu[line].dhu_tty;
  547         int error;
  548 
  549         error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
  550         if (error != EPASSTHROUGH)
  551                 return (error);
  552 
  553         error = ttioctl(tp, cmd, data, flag, l);
  554         if (error != EPASSTHROUGH)
  555                 return (error);
  556 
  557         switch (cmd) {
  558 
  559         case TIOCSBRK:
  560                 (void) dhumctl(sc, line, DML_BRK, DMBIS);
  561                 break;
  562 
  563         case TIOCCBRK:
  564                 (void) dhumctl(sc, line, DML_BRK, DMBIC);
  565                 break;
  566 
  567         case TIOCSDTR:
  568                 (void) dhumctl(sc, line, DML_DTR|DML_RTS, DMBIS);
  569                 break;
  570 
  571         case TIOCCDTR:
  572                 (void) dhumctl(sc, line, DML_DTR|DML_RTS, DMBIC);
  573                 break;
  574 
  575         case TIOCMSET:
  576                 (void) dhumctl(sc, line, *(int *)data, DMSET);
  577                 break;
  578 
  579         case TIOCMBIS:
  580                 (void) dhumctl(sc, line, *(int *)data, DMBIS);
  581                 break;
  582 
  583         case TIOCMBIC:
  584                 (void) dhumctl(sc, line, *(int *)data, DMBIC);
  585                 break;
  586 
  587         case TIOCMGET:
  588                 *(int *)data = (dhumctl(sc, line, 0, DMGET) & ~DML_BRK);
  589                 break;
  590 
  591         default:
  592                 return (EPASSTHROUGH);
  593         }
  594         return (0);
  595 }
  596 
  597 struct tty *
  598 dhutty(dev_t dev)
  599 {
  600         struct dhu_softc *sc = device_lookup_private(&dhu_cd, DHU_M2U(minor(dev)));
  601 
  602         return sc->sc_dhu[DHU_LINE(minor(dev))].dhu_tty;
  603 }
  604 
  605 /*ARGSUSED*/
  606 void
  607 dhustop(struct tty *tp, int flag)
  608 {
  609         int s;
  610 
  611         s = spltty();
  612 
  613         if (tp->t_state & TS_BUSY) {
  614                 const int unit = DHU_M2U(minor(tp->t_dev));
  615                 const int line = DHU_LINE(minor(tp->t_dev));
  616                 struct dhu_softc *sc = device_lookup_private(&dhu_cd, unit);
  617 
  618                 if (sc->sc_dhu[line].dhu_state == STATE_DMA_RUNNING) {
  619 
  620                         sc->sc_dhu[line].dhu_state = STATE_DMA_STOPPED;
  621 
  622                         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  623                         DHU_WRITE_WORD(DHU_UBA_LNCTRL,
  624                             DHU_READ_WORD(DHU_UBA_LNCTRL) |
  625                             DHU_LNCTRL_DMA_ABORT);
  626                 }
  627 
  628                 if (!(tp->t_state & TS_TTSTOP))
  629                         tp->t_state |= TS_FLUSH;
  630         }
  631         (void) splx(s);
  632 }
  633 
  634 static void
  635 dhustart(struct tty *tp)
  636 {
  637         struct dhu_softc *sc;
  638         int line, cc;
  639         int addr;
  640         int s;
  641 
  642         s = spltty();
  643         if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
  644                 goto out;
  645         if (!ttypull(tp))
  646                 goto out;
  647         cc = ndqb(&tp->t_outq, 0);
  648         if (cc == 0)
  649                 goto out;
  650 
  651         tp->t_state |= TS_BUSY;
  652 
  653         sc = device_lookup_private(&dhu_cd,DHU_M2U(minor(tp->t_dev)));
  654 
  655         line = DHU_LINE(minor(tp->t_dev));
  656 
  657         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  658 
  659         sc->sc_dhu[line].dhu_cc = cc;
  660 
  661         if (cc == 1 && sc->sc_type == IS_DHV) {
  662 
  663                 sc->sc_dhu[line].dhu_state = STATE_TX_ONE_CHAR;
  664 
  665                 DHU_WRITE_WORD(DHU_UBA_TXCHAR,
  666                     DHU_TXCHAR_DATA_VALID | *tp->t_outq.c_cf);
  667 
  668         } else {
  669 
  670                 sc->sc_dhu[line].dhu_state = STATE_DMA_RUNNING;
  671 
  672                 addr = sc->sc_dhu[line].dhu_dmah->dm_segs[0].ds_addr +
  673                         (tp->t_outq.c_cf - tp->t_outq.c_cs);
  674 
  675                 DHU_WRITE_WORD(DHU_UBA_TBUFCNT, cc);
  676                 DHU_WRITE_WORD(DHU_UBA_TBUFAD1, addr & 0xFFFF);
  677                 DHU_WRITE_WORD(DHU_UBA_TBUFAD2, ((addr>>16) & 0x3F) |
  678                     DHU_TBUFAD2_TX_ENABLE);
  679                 DHU_WRITE_WORD(DHU_UBA_LNCTRL,
  680                     DHU_READ_WORD(DHU_UBA_LNCTRL) & ~DHU_LNCTRL_DMA_ABORT);
  681                 DHU_WRITE_WORD(DHU_UBA_TBUFAD2,
  682                     DHU_READ_WORD(DHU_UBA_TBUFAD2) | DHU_TBUFAD2_DMA_START);
  683         }
  684 out:
  685         (void) splx(s);
  686         return;
  687 }
  688 
  689 static int
  690 dhuparam(struct tty *tp, struct termios *t)
  691 {
  692         int cflag = t->c_cflag;
  693         int ispeed = ttspeedtab(t->c_ispeed, dhuspeedtab);
  694         int ospeed = ttspeedtab(t->c_ospeed, dhuspeedtab);
  695         unsigned int lpr;
  696         unsigned int lnctrl;
  697         const int unit = DHU_M2U(minor(tp->t_dev));
  698         const int line = DHU_LINE(minor(tp->t_dev));
  699         struct dhu_softc * const sc = device_lookup_private(&dhu_cd, unit);
  700         int s;
  701 
  702 
  703         /* check requested parameters */
  704         if (ospeed < 0 || ispeed < 0)
  705                 return (EINVAL);
  706 
  707         tp->t_ispeed = t->c_ispeed;
  708         tp->t_ospeed = t->c_ospeed;
  709         tp->t_cflag = cflag;
  710 
  711         if (ospeed == 0) {
  712                 (void) dhumctl(sc, line, 0, DMSET);     /* hang up line */
  713                 return (0);
  714         }
  715 
  716         s = spltty();
  717         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  718 
  719         lpr = ((ispeed&017)<<8) | ((ospeed&017)<<12) ;
  720 
  721         switch (cflag & CSIZE) {
  722 
  723         case CS5:
  724                 lpr |= DHU_LPR_5_BIT_CHAR;
  725                 break;
  726 
  727         case CS6:
  728                 lpr |= DHU_LPR_6_BIT_CHAR;
  729                 break;
  730 
  731         case CS7:
  732                 lpr |= DHU_LPR_7_BIT_CHAR;
  733                 break;
  734 
  735         default:
  736                 lpr |= DHU_LPR_8_BIT_CHAR;
  737                 break;
  738         }
  739 
  740         if (cflag & PARENB)
  741                 lpr |= DHU_LPR_PARENB;
  742         if (!(cflag & PARODD))
  743                 lpr |= DHU_LPR_EPAR;
  744         if (cflag & CSTOPB)
  745                 lpr |= DHU_LPR_2_STOP;
  746 
  747         DHU_WRITE_WORD(DHU_UBA_LPR, lpr);
  748 
  749         DHU_WRITE_WORD(DHU_UBA_TBUFAD2,
  750             DHU_READ_WORD(DHU_UBA_TBUFAD2) | DHU_TBUFAD2_TX_ENABLE);
  751 
  752         lnctrl = DHU_READ_WORD(DHU_UBA_LNCTRL);
  753 
  754         /* Setting LINK.TYPE enables modem signal change interrupts. */
  755 
  756         lnctrl |= (DHU_LNCTRL_RX_ENABLE | DHU_LNCTRL_LINK_TYPE);
  757 
  758         /* Enable the auto XON/XOFF feature on the controller */
  759 
  760         if (t->c_iflag & IXON)
  761                 lnctrl |= DHU_LNCTRL_OAUTO;
  762         else
  763                 lnctrl &= ~DHU_LNCTRL_OAUTO;
  764 
  765         if (t->c_iflag & IXOFF)
  766                 lnctrl |= DHU_LNCTRL_IAUTO;
  767         else
  768                 lnctrl &= ~DHU_LNCTRL_IAUTO;
  769 
  770         DHU_WRITE_WORD(DHU_UBA_LNCTRL, lnctrl);
  771 
  772         (void) splx(s);
  773         return (0);
  774 }
  775 
  776 static int
  777 dhuiflow(struct tty *tp, int flag)
  778 {
  779 
  780         if (tp->t_cflag & CRTSCTS) {
  781                 const int unit = DHU_M2U(minor(tp->t_dev));
  782                 const int line = DHU_LINE(minor(tp->t_dev));
  783                 struct dhu_softc * const sc = device_lookup_private(&dhu_cd, unit);
  784                 (void) dhumctl(sc, line, DML_RTS, ((flag)? DMBIC: DMBIS));
  785                 return (1);
  786         }
  787         return (0);
  788 }
  789 
  790 static unsigned int
  791 dhumctl(struct dhu_softc *sc, int line, int bits, int how)
  792 {
  793         unsigned status;
  794         unsigned lnctrl;
  795         unsigned mbits;
  796         int s;
  797 
  798         s = spltty();
  799 
  800         DHU_WRITE_BYTE(DHU_UBA_CSR, DHU_CSR_RXIE | line);
  801 
  802         mbits = 0;
  803 
  804         /* external signals as seen from the port */
  805 
  806         status = DHU_READ_WORD(DHU_UBA_STAT);
  807 
  808         if (status & DHU_STAT_CTS)
  809                 mbits |= DML_CTS;
  810 
  811         if (status & DHU_STAT_DCD)
  812                 mbits |= DML_DCD;
  813 
  814         if (status & DHU_STAT_DSR)
  815                 mbits |= DML_DSR;
  816 
  817         if (status & DHU_STAT_RI)
  818                 mbits |= DML_RI;
  819 
  820         /* internal signals/state delivered to port */
  821 
  822         lnctrl = DHU_READ_WORD(DHU_UBA_LNCTRL);
  823 
  824         if (lnctrl & DHU_LNCTRL_RTS)
  825                 mbits |= DML_RTS;
  826 
  827         if (lnctrl & DHU_LNCTRL_DTR)
  828                 mbits |= DML_DTR;
  829 
  830         if (lnctrl & DHU_LNCTRL_BREAK)
  831                 mbits |= DML_BRK;
  832 
  833         switch (how) {
  834 
  835         case DMSET:
  836                 mbits = bits;
  837                 break;
  838 
  839         case DMBIS:
  840                 mbits |= bits;
  841                 break;
  842 
  843         case DMBIC:
  844                 mbits &= ~bits;
  845                 break;
  846 
  847         case DMGET:
  848                 (void) splx(s);
  849                 return (mbits);
  850         }
  851 
  852         if (mbits & DML_RTS)
  853                 lnctrl |= DHU_LNCTRL_RTS;
  854         else
  855                 lnctrl &= ~DHU_LNCTRL_RTS;
  856 
  857         if (mbits & DML_DTR)
  858                 lnctrl |= DHU_LNCTRL_DTR;
  859         else
  860                 lnctrl &= ~DHU_LNCTRL_DTR;
  861 
  862         if (mbits & DML_BRK)
  863                 lnctrl |= DHU_LNCTRL_BREAK;
  864         else
  865                 lnctrl &= ~DHU_LNCTRL_BREAK;
  866 
  867         DHU_WRITE_WORD(DHU_UBA_LNCTRL, lnctrl);
  868 
  869         (void) splx(s);
  870         return (mbits);
  871 }

Cache object: b4e969e6c0ca260ae9d307921734b03d


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