[BACK]Return to dhu.c CVS log [TXT][DIR] Up to [local] / sys / arch / vax / qbus

Annotation of sys/arch/vax/qbus/dhu.c, Revision 1.1

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

CVSweb