[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

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