[BACK]Return to dcm.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / arch / hp300 / dev

Annotation of src/sys/arch/hp300/dev/dcm.c, Revision 1.65

1.65    ! thorpej     1: /*     $NetBSD: dcm.c,v 1.64 2004/04/25 06:23:41 matt Exp $    */
1.42      thorpej     2:
                      3: /*-
                      4:  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
                      5:  * All rights reserved.
                      6:  *
                      7:  * This code is derived from software contributed to The NetBSD Foundation
                      8:  * by Jason R. Thorpe.
                      9:  *
                     10:  * Redistribution and use in source and binary forms, with or without
                     11:  * modification, are permitted provided that the following conditions
                     12:  * are met:
                     13:  * 1. Redistributions of source code must retain the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer.
                     15:  * 2. Redistributions in binary form must reproduce the above copyright
                     16:  *    notice, this list of conditions and the following disclaimer in the
                     17:  *    documentation and/or other materials provided with the distribution.
                     18:  * 3. All advertising materials mentioning features or use of this software
                     19:  *    must display the following acknowledgement:
                     20:  *     This product includes software developed by the NetBSD
                     21:  *     Foundation, Inc. and its contributors.
                     22:  * 4. Neither the name of The NetBSD Foundation nor the names of its
                     23:  *    contributors may be used to endorse or promote products derived
                     24:  *    from this software without specific prior written permission.
                     25:  *
                     26:  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
                     27:  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
                     28:  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
                     29:  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
                     30:  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
                     31:  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
                     32:  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
                     33:  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     34:  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
                     35:  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
                     36:  * POSSIBILITY OF SUCH DAMAGE.
                     37:  */
1.15      cgd        38:
1.1       cgd        39: /*
1.14      mycroft    40:  * Copyright (c) 1982, 1986, 1990, 1993
                     41:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd        42:  *
                     43:  * This code is derived from software contributed to Berkeley by
                     44:  * the Systems Programming Group of the University of Utah Computer
                     45:  * Science Department.
                     46:  *
                     47:  * Redistribution and use in source and binary forms, with or without
                     48:  * modification, are permitted provided that the following conditions
                     49:  * are met:
                     50:  * 1. Redistributions of source code must retain the above copyright
                     51:  *    notice, this list of conditions and the following disclaimer.
                     52:  * 2. Redistributions in binary form must reproduce the above copyright
                     53:  *    notice, this list of conditions and the following disclaimer in the
                     54:  *    documentation and/or other materials provided with the distribution.
1.62      agc        55:  * 3. Neither the name of the University nor the names of its contributors
                     56:  *    may be used to endorse or promote products derived from this software
                     57:  *    without specific prior written permission.
                     58:  *
                     59:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     60:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     61:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     62:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     63:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     64:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     65:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     66:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     67:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     68:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     69:  * SUCH DAMAGE.
                     70:  *
                     71:  * from Utah: $Hdr: dcm.c 1.29 92/01/21$
                     72:  *
                     73:  *     @(#)dcm.c       8.4 (Berkeley) 1/12/94
                     74:  */
                     75: /*
                     76:  * Copyright (c) 1988 University of Utah.
                     77:  *
                     78:  * This code is derived from software contributed to Berkeley by
                     79:  * the Systems Programming Group of the University of Utah Computer
                     80:  * Science Department.
                     81:  *
                     82:  * Redistribution and use in source and binary forms, with or without
                     83:  * modification, are permitted provided that the following conditions
                     84:  * are met:
                     85:  * 1. Redistributions of source code must retain the above copyright
                     86:  *    notice, this list of conditions and the following disclaimer.
                     87:  * 2. Redistributions in binary form must reproduce the above copyright
                     88:  *    notice, this list of conditions and the following disclaimer in the
                     89:  *    documentation and/or other materials provided with the distribution.
1.1       cgd        90:  * 3. All advertising materials mentioning features or use of this software
                     91:  *    must display the following acknowledgement:
                     92:  *     This product includes software developed by the University of
                     93:  *     California, Berkeley and its contributors.
                     94:  * 4. Neither the name of the University nor the names of its contributors
                     95:  *    may be used to endorse or promote products derived from this software
                     96:  *    without specific prior written permission.
                     97:  *
                     98:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     99:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                    100:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                    101:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                    102:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                    103:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                    104:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                    105:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                    106:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                    107:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                    108:  * SUCH DAMAGE.
                    109:  *
1.14      mycroft   110:  * from Utah: $Hdr: dcm.c 1.29 92/01/21$
                    111:  *
1.15      cgd       112:  *     @(#)dcm.c       8.4 (Berkeley) 1/12/94
1.1       cgd       113:  */
                    114:
                    115: /*
                    116:  * TODO:
                    117:  *     Timeouts
                    118:  *     Test console support.
                    119:  */
                    120:
                    121: /*
                    122:  *  98642/MUX
                    123:  */
1.50      gmcgarry  124:
                    125: #include <sys/cdefs.h>
1.65    ! thorpej   126: __KERNEL_RCSID(0, "$NetBSD: dcm.c,v 1.64 2004/04/25 06:23:41 matt Exp $");
1.47      lukem     127:
                    128: #include "opt_kgdb.h"
                    129:
1.13      mycroft   130: #include <sys/param.h>
                    131: #include <sys/systm.h>
                    132: #include <sys/ioctl.h>
                    133: #include <sys/proc.h>
                    134: #include <sys/tty.h>
                    135: #include <sys/conf.h>
                    136: #include <sys/file.h>
                    137: #include <sys/uio.h>
                    138: #include <sys/kernel.h>
                    139: #include <sys/syslog.h>
                    140: #include <sys/time.h>
1.34      thorpej   141: #include <sys/device.h>
1.13      mycroft   142:
1.59      gmcgarry  143: #include <machine/bus.h>
1.14      mycroft   144:
1.22      thorpej   145: #include <dev/cons.h>
                    146:
1.34      thorpej   147: #include <hp300/dev/diovar.h>
                    148: #include <hp300/dev/diodevs.h>
1.13      mycroft   149: #include <hp300/dev/dcmreg.h>
1.1       cgd       150:
                    151: #ifndef DEFAULT_BAUD_RATE
                    152: #define DEFAULT_BAUD_RATE 9600
                    153: #endif
                    154:
1.65    ! thorpej   155: static const struct speedtab dcmspeedtab[] = {
1.36      scottr    156:        {       0,      BR_0            },
                    157:        {       50,     BR_50           },
                    158:        {       75,     BR_75           },
                    159:        {       110,    BR_110          },
                    160:        {       134,    BR_134          },
                    161:        {       150,    BR_150          },
                    162:        {       300,    BR_300          },
                    163:        {       600,    BR_600          },
                    164:        {       1200,   BR_1200         },
                    165:        {       1800,   BR_1800         },
                    166:        {       2400,   BR_2400         },
                    167:        {       4800,   BR_4800         },
                    168:        {       9600,   BR_9600         },
                    169:        {       19200,  BR_19200        },
                    170:        {       38400,  BR_38400        },
                    171:        {       -1,     -1              },
1.1       cgd       172: };
                    173:
                    174: /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
                    175: #define        DCM_USPERCH(s)  (10000000 / (s))
                    176:
                    177: /*
                    178:  * Per board interrupt scheme.  16.7ms is the polling interrupt rate
                    179:  * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
                    180:  */
                    181: #define DIS_TIMER      0
                    182: #define DIS_PERCHAR    1
                    183: #define DIS_RESET      2
                    184:
1.65    ! thorpej   185: static int     dcmistype = -1; /* -1 == dynamic, 0 == timer, 1 == perchar */
        !           186: static int     dcminterval = 5;        /* interval (secs) between checks */
1.1       cgd       187: struct dcmischeme {
                    188:        int     dis_perchar;    /* non-zero if interrupting per char */
                    189:        long    dis_time;       /* last time examined */
                    190:        int     dis_intr;       /* recv interrupts during last interval */
                    191:        int     dis_char;       /* characters read during last interval */
1.20      thorpej   192: };
1.1       cgd       193:
                    194: #ifdef KGDB
                    195: /*
                    196:  * Kernel GDB support
                    197:  */
1.14      mycroft   198: #include <machine/remote-sl.h>
1.1       cgd       199:
                    200: extern dev_t kgdb_dev;
                    201: extern int kgdb_rate;
                    202: extern int kgdb_debug_init;
                    203: #endif
                    204:
1.14      mycroft   205: /* #define DCMSTATS */
1.1       cgd       206:
                    207: #ifdef DEBUG
                    208: int    dcmdebug = 0x0;
                    209: #define DDB_SIOERR     0x01
                    210: #define DDB_PARAM      0x02
                    211: #define DDB_INPUT      0x04
                    212: #define DDB_OUTPUT     0x08
                    213: #define DDB_INTR       0x10
                    214: #define DDB_IOCTL      0x20
                    215: #define DDB_INTSCHM    0x40
                    216: #define DDB_MODEM      0x80
                    217: #define DDB_OPENCLOSE  0x100
                    218: #endif
                    219:
1.14      mycroft   220: #ifdef DCMSTATS
1.1       cgd       221: #define        DCMRBSIZE       94
                    222: #define DCMXBSIZE      24
                    223:
                    224: struct dcmstats {
                    225:        long    xints;              /* # of xmit ints */
                    226:        long    xchars;             /* # of xmit chars */
                    227:        long    xempty;             /* times outq is empty in dcmstart */
                    228:        long    xrestarts;          /* times completed while xmitting */
                    229:        long    rints;              /* # of recv ints */
                    230:        long    rchars;             /* # of recv chars */
                    231:        long    xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
                    232:        long    rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
1.20      thorpej   233: };
1.1       cgd       234: #endif
                    235:
1.44      thorpej   236: #define DCMUNIT(x)             (minor(x) & 0x7ffff)
                    237: #define        DCMDIALOUT(x)           (minor(x) & 0x80000)
1.20      thorpej   238: #define        DCMBOARD(x)             (((x) >> 2) & 0x3f)
                    239: #define DCMPORT(x)             ((x) & 3)
1.1       cgd       240:
                    241: /*
                    242:  * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
                    243:  * the distribution panel uses "HP DCE" conventions.  If requested via
                    244:  * the device flags, we swap the inputs to something closer to normal DCE,
                    245:  * allowing a straight-through cable to a DTE or a reversed cable
                    246:  * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
                    247:  * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
                    248:  * DSR or make RTS work, though).  The following gives the full
                    249:  * details of a cable from this mux panel to a modem:
                    250:  *
                    251:  *                  HP             modem
                    252:  *             name    pin     pin     name
                    253:  * HP inputs:
                    254:  *             "Rx"     2       3      Tx
                    255:  *             CTS      4       5      CTS     (only needed for CCTS_OFLOW)
                    256:  *             DCD     20       8      DCD
                    257:  *             "DSR"    9       6      DSR     (unneeded)
                    258:  *             RI      22      22      RI      (unneeded)
                    259:  *
                    260:  * HP outputs:
                    261:  *             "Tx"     3       2      Rx
                    262:  *             "DTR"    6      not connected
                    263:  *             "RTS"    8      20      DTR
                    264:  *             "SR"    23       4      RTS     (often not needed)
                    265:  */
                    266: #define hp2dce_in(ibits)       (iconv[(ibits) & 0xf])
1.65    ! thorpej   267: static const char iconv[16] = {
1.1       cgd       268:        0,              MI_DM,          MI_CTS,         MI_CTS|MI_DM,
                    269:        MI_CD,          MI_CD|MI_DM,    MI_CD|MI_CTS,   MI_CD|MI_CTS|MI_DM,
                    270:        MI_RI,          MI_RI|MI_DM,    MI_RI|MI_CTS,   MI_RI|MI_CTS|MI_DM,
                    271:        MI_RI|MI_CD,    MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
                    272:        MI_RI|MI_CD|MI_CTS|MI_DM
                    273: };
                    274:
1.21      thorpej   275: /*
                    276:  * Note that 8-port boards appear as 2 4-port boards at consecutive
                    277:  * select codes.
                    278:  */
                    279: #define        NDCMPORT        4
1.20      thorpej   280:
                    281: struct dcm_softc {
1.34      thorpej   282:        struct  device sc_dev;          /* generic device glue */
1.59      gmcgarry  283:
                    284:        bus_space_tag_t sc_bst;
                    285:        bus_space_handle_t sc_bsh;
                    286:
1.20      thorpej   287:        struct  dcmdevice *sc_dcm;      /* pointer to hardware */
                    288:        struct  tty *sc_tty[NDCMPORT];  /* our tty instances */
                    289:        struct  modemreg *sc_modem[NDCMPORT]; /* modem control */
                    290:        char    sc_mcndlast[NDCMPORT];  /* XXX last modem status for port */
                    291:        short   sc_softCAR;             /* mask of ports with soft-carrier */
                    292:        struct  dcmischeme sc_scheme;   /* interrupt scheme for board */
                    293:
                    294:        /*
                    295:         * Mask of soft-carrier bits in config flags.
                    296:         */
                    297: #define        DCM_SOFTCAR     0x0000000f
                    298:
                    299:        int     sc_flags;               /* misc. configuration info */
                    300:
                    301:        /*
                    302:         * Bits for sc_flags
                    303:         */
                    304: #define        DCM_ACTIVE      0x00000001      /* indicates board is alive */
1.24      thorpej   305: #define        DCM_ISCONSOLE   0x00000002      /* indicates board is console */
1.20      thorpej   306: #define        DCM_STDDCE      0x00000010      /* re-map DCE to standard */
                    307: #define        DCM_FLAGMASK    (DCM_STDDCE)    /* mask of valid bits in config flags */
                    308:
                    309: #ifdef DCMSTATS
                    310:        struct  dcmstats sc_stats;      /* metrics gathering */
                    311: #endif
1.34      thorpej   312: };
                    313:
1.65    ! thorpej   314: static int     dcmintr(void *);
        !           315: static void    dcmpint(struct dcm_softc *, int, int);
        !           316: static void    dcmrint(struct dcm_softc *);
        !           317: static void    dcmreadbuf(struct dcm_softc *, int);
        !           318: static void    dcmxint(struct dcm_softc *, int);
        !           319: static void    dcmmint(struct dcm_softc *, int, int);
        !           320:
        !           321: static int     dcmparam(struct tty *, struct termios *);
        !           322: static void    dcmstart(struct tty *);
        !           323: static int     dcmmctl(dev_t, int, int);
        !           324: static void    dcmsetischeme(int, int);
        !           325: static void    dcminit(struct dcmdevice *, int, int);
        !           326:
        !           327: static int     dcmselftest(struct dcm_softc *);
1.36      scottr    328:
1.65    ! thorpej   329: static int     dcmcngetc(dev_t);
        !           330: static void    dcmcnputc(dev_t, int);
        !           331:
        !           332: int    dcmcnattach(bus_space_tag_t, bus_addr_t, int);
        !           333:
        !           334: static int     dcmmatch(struct device *, struct cfdata *, void *);
        !           335: static void    dcmattach(struct device *, struct device *, void *);
1.38      scottr    336:
1.54      thorpej   337: CFATTACH_DECL(dcm, sizeof(struct dcm_softc),
                    338:     dcmmatch, dcmattach, NULL, NULL);
1.38      scottr    339:
1.48      gmcgarry  340: /*
                    341:  * Stuff for DCM console support.  This could probably be done a little
                    342:  * better.
                    343:  */
                    344: static struct dcmdevice *dcm_cn = NULL;        /* pointer to hardware */
                    345: static int dcmconsinit;                        /* has been initialized */
                    346: /* static      int dcm_lastcnpri = CN_DEAD; */ /* XXX last priority */
                    347:
                    348: static struct consdev dcm_cons = {
1.63      tsutsui   349:        NULL,
                    350:        NULL,
                    351:        dcmcngetc,
                    352:        dcmcnputc,
                    353:        nullcnpollc,
                    354:        NULL,
                    355:        NULL,
                    356:        NULL,
                    357:        NODEV,
                    358:        CN_REMOTE
1.48      gmcgarry  359: };
                    360: int    dcmconscode;
                    361: int    dcmdefaultrate = DEFAULT_BAUD_RATE;
                    362: int    dcmconbrdbusy = 0;
                    363:
1.43      thorpej   364: extern struct cfdriver dcm_cd;
1.38      scottr    365:
1.65    ! thorpej   366: static dev_type_open(dcmopen);
        !           367: static dev_type_close(dcmclose);
        !           368: static dev_type_read(dcmread);
        !           369: static dev_type_write(dcmwrite);
        !           370: static dev_type_ioctl(dcmioctl);
        !           371: static dev_type_stop(dcmstop);
        !           372: static dev_type_tty(dcmtty);
        !           373: static dev_type_poll(dcmpoll);
1.52      gehenna   374:
                    375: const struct cdevsw dcm_cdevsw = {
                    376:        dcmopen, dcmclose, dcmread, dcmwrite, dcmioctl,
1.56      jdolecek  377:        dcmstop, dcmtty, dcmpoll, nommap, ttykqfilter, D_TTY
1.52      gehenna   378: };
                    379:
1.65    ! thorpej   380: static int
        !           381: dcmmatch(struct device *parent, struct cfdata *match, void *aux)
1.34      thorpej   382: {
                    383:        struct dio_attach_args *da = aux;
                    384:
                    385:        switch (da->da_id) {
                    386:        case DIO_DEVICE_ID_DCM:
                    387:        case DIO_DEVICE_ID_DCMREM:
                    388:                return (1);
                    389:        }
                    390:
                    391:        return (0);
                    392: }
1.20      thorpej   393:
1.65    ! thorpej   394: static void
        !           395: dcmattach(struct device *parent, struct device *self, void *aux)
1.34      thorpej   396: {
                    397:        struct dcm_softc *sc = (struct dcm_softc *)self;
                    398:        struct dio_attach_args *da = aux;
                    399:        struct dcmdevice *dcm;
                    400:        int brd = self->dv_unit;
                    401:        int scode = da->da_scode;
1.59      gmcgarry  402:        int i, mbits, code;
1.20      thorpej   403:
1.36      scottr    404:        sc->sc_flags = 0;
                    405:
1.48      gmcgarry  406:        if (scode == dcmconscode) {
                    407:                dcm = dcm_cn;
1.24      thorpej   408:                sc->sc_flags |= DCM_ISCONSOLE;
                    409:
                    410:                /*
                    411:                 * We didn't know which unit this would be during
                    412:                 * the console probe, so we have to fixup cn_dev here.
                    413:                 * Note that we always assume port 1 on the board.
                    414:                 */
1.52      gehenna   415:                cn_tab->cn_dev = makedev(cdevsw_lookup_major(&dcm_cdevsw),
                    416:                                         (brd << 2) | DCMCONSPORT);
1.34      thorpej   417:        } else {
1.59      gmcgarry  418:                sc->sc_bst = da->da_bst;
                    419:                if (bus_space_map(sc->sc_bst, da->da_addr, da->da_size,
                    420:                    BUS_SPACE_MAP_LINEAR, &sc->sc_bsh)) {
1.34      thorpej   421:                        printf("\n%s: can't map registers\n",
                    422:                            sc->sc_dev.dv_xname);
                    423:                        return;
                    424:                }
1.59      gmcgarry  425:                dcm = (struct dcmdevice *)bus_space_vaddr(sc->sc_bst,
                    426:                    sc->sc_bsh);
1.34      thorpej   427:        }
                    428:
                    429:        sc->sc_dcm = dcm;
                    430:
1.38      scottr    431:        /*
                    432:         * XXX someone _should_ fix this; the self test screws
                    433:         * autoconfig messages.
                    434:         */
                    435:        if ((sc->sc_flags & DCM_ISCONSOLE) && dcmselftest(sc)) {
1.34      thorpej   436:                printf("\n%s: self-test failed\n", sc->sc_dev.dv_xname);
                    437:                return;
1.24      thorpej   438:        }
1.20      thorpej   439:
                    440:        /* Extract configuration info from flags. */
1.34      thorpej   441:        sc->sc_softCAR = self->dv_cfdata->cf_flags & DCM_SOFTCAR;
1.36      scottr    442:        sc->sc_flags |= self->dv_cfdata->cf_flags & DCM_FLAGMASK;
1.20      thorpej   443:
                    444:        /* Mark our unit as configured. */
                    445:        sc->sc_flags |= DCM_ACTIVE;
                    446:
                    447:        /* Establish the interrupt handler. */
1.59      gmcgarry  448:        (void) dio_intr_establish(dcmintr, sc, da->da_ipl, IPL_TTY);
1.20      thorpej   449:
1.1       cgd       450:        if (dcmistype == DIS_TIMER)
                    451:                dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
                    452:        else
                    453:                dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
                    454:
                    455:        /* load pointers to modem control */
1.20      thorpej   456:        sc->sc_modem[0] = &dcm->dcm_modem0;
                    457:        sc->sc_modem[1] = &dcm->dcm_modem1;
                    458:        sc->sc_modem[2] = &dcm->dcm_modem2;
                    459:        sc->sc_modem[3] = &dcm->dcm_modem3;
                    460:
1.1       cgd       461:        /* set DCD (modem) and CTS (flow control) on all ports */
1.20      thorpej   462:        if (sc->sc_flags & DCM_STDDCE)
1.1       cgd       463:                mbits = hp2dce_in(MI_CD|MI_CTS);
                    464:        else
                    465:                mbits = MI_CD|MI_CTS;
1.20      thorpej   466:
                    467:        for (i = 0; i < NDCMPORT; i++)
                    468:                sc->sc_modem[i]->mdmmsk = mbits;
1.1       cgd       469:
1.38      scottr    470:        /*
                    471:         * Get current state of mdmin register on all ports, so that
                    472:         * deltas will work properly.
                    473:         */
                    474:        for (i = 0; i < NDCMPORT; i++) {
                    475:                code = sc->sc_modem[i]->mdmin;
                    476:                if (sc->sc_flags & DCM_STDDCE)
                    477:                        code = hp2dce_in(code);
                    478:                sc->sc_mcndlast[i] = code;
                    479:        }
                    480:
1.1       cgd       481:        dcm->dcm_ic = IC_IE;            /* turn all interrupts on */
1.20      thorpej   482:
1.1       cgd       483:        /*
1.24      thorpej   484:         * Need to reset baud rate, etc. of next print so reset dcmconsinit.
1.1       cgd       485:         * Also make sure console is always "hardwired"
                    486:         */
1.24      thorpej   487:        if (sc->sc_flags & DCM_ISCONSOLE) {
1.1       cgd       488:                dcmconsinit = 0;
1.24      thorpej   489:                sc->sc_softCAR |= (1 << DCMCONSPORT);
1.31      christos  490:                printf(": console on port %d\n", DCMCONSPORT);
1.20      thorpej   491:        } else
1.31      christos  492:                printf("\n");
1.20      thorpej   493:
                    494: #ifdef KGDB
1.52      gehenna   495:        if (cdevsw_lookup(kgdb_dev) == &dcm_cdevsw &&
1.20      thorpej   496:            DCMBOARD(DCMUNIT(kgdb_dev)) == brd) {
1.24      thorpej   497:                if (dcmconsole == DCMUNIT(kgdb_dev))    /* XXX fixme */
1.20      thorpej   498:                        kgdb_dev = NODEV; /* can't debug over console port */
                    499: #ifndef KGDB_CHEAT
                    500:                /*
                    501:                 * The following could potentially be replaced
                    502:                 * by the corresponding code in dcmcnprobe.
                    503:                 */
                    504:                else {
1.22      thorpej   505:                        dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)),
                    506:                            kgdb_rate);
1.20      thorpej   507:                        if (kgdb_debug_init) {
1.34      thorpej   508:                                printf("%s port %d: ", sc->sc_dev.dv_xname,
1.20      thorpej   509:                                    DCMPORT(DCMUNIT(kgdb_dev)));
                    510:                                kgdb_connect(1);
                    511:                        } else
1.31      christos  512:                                printf("%s port %d: kgdb enabled\n",
1.34      thorpej   513:                                    sc->sc_dev.dv_xname,
1.20      thorpej   514:                                    DCMPORT(DCMUNIT(kgdb_dev)));
                    515:                }
                    516:                /* end could be replaced */
1.34      thorpej   517: #endif /* KGDB_CHEAT */
1.1       cgd       518:        }
1.34      thorpej   519: #endif /* KGDB */
1.1       cgd       520: }
                    521:
                    522: /* ARGSUSED */
1.65    ! thorpej   523: static int
        !           524: dcmopen(dev_t dev, int flag, int mode, struct proc *p)
1.1       cgd       525: {
1.20      thorpej   526:        struct dcm_softc *sc;
                    527:        struct tty *tp;
                    528:        int unit, brd, port;
1.18      thorpej   529:        int error = 0, mbits, s;
1.1       cgd       530:
1.20      thorpej   531:        unit = DCMUNIT(dev);
                    532:        brd = DCMBOARD(unit);
                    533:        port = DCMPORT(unit);
                    534:
1.34      thorpej   535:        if (brd >= dcm_cd.cd_ndevs || port >= NDCMPORT ||
                    536:            (sc = dcm_cd.cd_devs[brd]) == NULL)
                    537:                return (ENXIO);
1.20      thorpej   538:
                    539:        if ((sc->sc_flags & DCM_ACTIVE) == 0)
                    540:                return (ENXIO);
                    541:
1.28      thorpej   542:        if (sc->sc_tty[port] == NULL) {
1.20      thorpej   543:                tp = sc->sc_tty[port] = ttymalloc();
1.28      thorpej   544:                tty_attach(tp);
                    545:        } else
1.20      thorpej   546:                tp = sc->sc_tty[port];
                    547:
1.1       cgd       548:        tp->t_oproc = dcmstart;
                    549:        tp->t_param = dcmparam;
                    550:        tp->t_dev = dev;
1.18      thorpej   551:
1.44      thorpej   552:        if ((tp->t_state & TS_ISOPEN) &&
                    553:            (tp->t_state & TS_XCLUDE) &&
1.61      fvdl      554:            p->p_ucred->cr_uid != 0)
1.44      thorpej   555:                return (EBUSY);
                    556:
                    557:        s = spltty();
                    558:
                    559:        if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
1.18      thorpej   560:                /*
                    561:                 * Sanity clause: reset the card on first open.
                    562:                 * The card might be left in an inconsistent state
                    563:                 * if the card memory is read inadvertently.
                    564:                 */
1.22      thorpej   565:                dcminit(sc->sc_dcm, port, dcmdefaultrate);
1.18      thorpej   566:
1.1       cgd       567:                ttychars(tp);
1.18      thorpej   568:                tp->t_iflag = TTYDEF_IFLAG;
                    569:                tp->t_oflag = TTYDEF_OFLAG;
                    570:                tp->t_cflag = TTYDEF_CFLAG;
                    571:                tp->t_lflag = TTYDEF_LFLAG;
                    572:                tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
                    573:
1.1       cgd       574:                (void) dcmparam(tp, &tp->t_termios);
                    575:                ttsetwater(tp);
1.18      thorpej   576:
1.44      thorpej   577:                /* Set modem control state. */
                    578:                mbits = MO_ON;
                    579:                if (sc->sc_flags & DCM_STDDCE)
                    580:                        mbits |= MO_SR; /* pin 23, could be used as RTS */
                    581:
                    582:                (void) dcmmctl(dev, mbits, DMSET);      /* enable port */
1.20      thorpej   583:
1.44      thorpej   584:                /* Set soft-carrier if so configured. */
                    585:                if ((sc->sc_softCAR & (1 << port)) ||
                    586:                    (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
                    587:                        tp->t_state |= TS_CARR_ON;
                    588:        }
1.18      thorpej   589:
1.44      thorpej   590:        splx(s);
1.18      thorpej   591:
1.1       cgd       592: #ifdef DEBUG
                    593:        if (dcmdebug & DDB_MODEM)
1.31      christos  594:                printf("%s: dcmopen port %d softcarr %c\n",
1.34      thorpej   595:                       sc->sc_dev.dv_xname, port,
1.20      thorpej   596:                       (tp->t_state & TS_CARR_ON) ? '1' : '0');
1.1       cgd       597: #endif
1.18      thorpej   598:
1.44      thorpej   599:        error = ttyopen(tp, DCMDIALOUT(dev), (flag & O_NONBLOCK));
                    600:        if (error)
                    601:                goto bad;
1.1       cgd       602:
                    603: #ifdef DEBUG
                    604:        if (dcmdebug & DDB_OPENCLOSE)
1.31      christos  605:                printf("%s port %d: dcmopen: st %x fl %x\n",
1.34      thorpej   606:                        sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags);
1.1       cgd       607: #endif
1.45      eeh       608:        error = (*tp->t_linesw->l_open)(dev, tp);
1.18      thorpej   609:
1.44      thorpej   610:  bad:
1.1       cgd       611:        return (error);
                    612: }
1.63      tsutsui   613:
1.1       cgd       614: /*ARGSUSED*/
1.65    ! thorpej   615: static int
        !           616: dcmclose(dev_t dev, int flag, int mode, struct proc *p)
1.1       cgd       617: {
1.20      thorpej   618:        int s, unit, board, port;
                    619:        struct dcm_softc *sc;
                    620:        struct tty *tp;
1.63      tsutsui   621:
1.20      thorpej   622:        unit = DCMUNIT(dev);
                    623:        board = DCMBOARD(unit);
                    624:        port = DCMPORT(unit);
                    625:
1.34      thorpej   626:        sc = dcm_cd.cd_devs[board];
1.20      thorpej   627:        tp = sc->sc_tty[port];
                    628:
1.45      eeh       629:        (*tp->t_linesw->l_close)(tp, flag);
1.18      thorpej   630:
                    631:        s = spltty();
                    632:
1.44      thorpej   633:        if (tp->t_cflag & HUPCL || tp->t_wopen != 0 ||
1.18      thorpej   634:            (tp->t_state & TS_ISOPEN) == 0)
1.1       cgd       635:                (void) dcmmctl(dev, MO_OFF, DMSET);
                    636: #ifdef DEBUG
                    637:        if (dcmdebug & DDB_OPENCLOSE)
1.31      christos  638:                printf("%s port %d: dcmclose: st %x fl %x\n",
1.34      thorpej   639:                        sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags);
1.1       cgd       640: #endif
1.18      thorpej   641:        splx(s);
1.1       cgd       642:        ttyclose(tp);
1.12      mycroft   643: #if 0
1.28      thorpej   644:        tty_detach(tp);
1.7       mycroft   645:        ttyfree(tp);
1.20      thorpej   646:        sc->sc_tty[port] == NULL;
1.12      mycroft   647: #endif
1.1       cgd       648:        return (0);
                    649: }
1.63      tsutsui   650:
1.65    ! thorpej   651: static int
        !           652: dcmread(dev_t dev, struct uio *uio, int flag)
1.1       cgd       653: {
1.20      thorpej   654:        int unit, board, port;
                    655:        struct dcm_softc *sc;
1.36      scottr    656:        struct tty *tp;
1.20      thorpej   657:
                    658:        unit = DCMUNIT(dev);
                    659:        board = DCMBOARD(unit);
                    660:        port = DCMPORT(unit);
                    661:
1.34      thorpej   662:        sc = dcm_cd.cd_devs[board];
1.20      thorpej   663:        tp = sc->sc_tty[port];
1.14      mycroft   664:
1.45      eeh       665:        return ((*tp->t_linesw->l_read)(tp, uio, flag));
1.1       cgd       666: }
1.63      tsutsui   667:
1.65    ! thorpej   668: static int
        !           669: dcmwrite(dev_t dev, struct uio *uio, int flag)
1.1       cgd       670: {
1.20      thorpej   671:        int unit, board, port;
                    672:        struct dcm_softc *sc;
1.36      scottr    673:        struct tty *tp;
1.20      thorpej   674:
                    675:        unit = DCMUNIT(dev);
                    676:        board = DCMBOARD(unit);
                    677:        port = DCMPORT(unit);
                    678:
1.34      thorpej   679:        sc = dcm_cd.cd_devs[board];
1.20      thorpej   680:        tp = sc->sc_tty[port];
1.14      mycroft   681:
1.45      eeh       682:        return ((*tp->t_linesw->l_write)(tp, uio, flag));
1.46      scw       683: }
                    684:
1.65    ! thorpej   685: static int
        !           686: dcmpoll(dev_t dev, int events, struct proc *p)
1.46      scw       687: {
                    688:        int unit, board, port;
                    689:        struct dcm_softc *sc;
                    690:        struct tty *tp;
                    691:
                    692:        unit = DCMUNIT(dev);
                    693:        board = DCMBOARD(unit);
                    694:        port = DCMPORT(unit);
                    695:
                    696:        sc = dcm_cd.cd_devs[board];
                    697:        tp = sc->sc_tty[port];
1.63      tsutsui   698:
1.61      fvdl      699:        return ((*tp->t_linesw->l_poll)(tp, events, p));
1.1       cgd       700: }
1.17      mycroft   701:
1.65    ! thorpej   702: static struct tty *
        !           703: dcmtty(dev_t dev)
1.17      mycroft   704: {
1.20      thorpej   705:        int unit, board, port;
                    706:        struct dcm_softc *sc;
1.17      mycroft   707:
1.20      thorpej   708:        unit = DCMUNIT(dev);
                    709:        board = DCMBOARD(unit);
                    710:        port = DCMPORT(unit);
                    711:
1.34      thorpej   712:        sc = dcm_cd.cd_devs[board];
1.20      thorpej   713:
                    714:        return (sc->sc_tty[port]);
1.17      mycroft   715: }
1.63      tsutsui   716:
1.65    ! thorpej   717: static int
        !           718: dcmintr(void *arg)
1.1       cgd       719: {
1.23      thorpej   720:        struct dcm_softc *sc = arg;
1.20      thorpej   721:        struct dcmdevice *dcm = sc->sc_dcm;
                    722:        struct dcmischeme *dis = &sc->sc_scheme;
1.34      thorpej   723:        int brd = sc->sc_dev.dv_unit;
1.20      thorpej   724:        int code, i;
1.1       cgd       725:        int pcnd[4], mcode, mcnd[4];
                    726:
                    727:        /*
1.36      scottr    728:         * Do all guarded accesses right off to minimize
1.1       cgd       729:         * block out of hardware.
                    730:         */
                    731:        SEM_LOCK(dcm);
                    732:        if ((dcm->dcm_ic & IC_IR) == 0) {
                    733:                SEM_UNLOCK(dcm);
                    734:                return (0);
                    735:        }
                    736:        for (i = 0; i < 4; i++) {
                    737:                pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
                    738:                dcm->dcm_icrtab[i].dcm_data = 0;
1.20      thorpej   739:                code = sc->sc_modem[i]->mdmin;
                    740:                if (sc->sc_flags & DCM_STDDCE)
1.1       cgd       741:                        code = hp2dce_in(code);
                    742:                mcnd[i] = code;
                    743:        }
                    744:        code = dcm->dcm_iir & IIR_MASK;
                    745:        dcm->dcm_iir = 0;       /* XXX doc claims read clears interrupt?! */
                    746:        mcode = dcm->dcm_modemintr;
                    747:        dcm->dcm_modemintr = 0;
                    748:        SEM_UNLOCK(dcm);
                    749:
                    750: #ifdef DEBUG
                    751:        if (dcmdebug & DDB_INTR) {
1.31      christos  752:                printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ",
1.34      thorpej   753:                       sc->sc_dev.dv_xname, code, pcnd[0], pcnd[1],
1.63      tsutsui   754:                       pcnd[2], pcnd[3]);
1.31      christos  755:                printf("miir %x mc %x/%x/%x/%x\n",
1.1       cgd       756:                       mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
                    757:        }
                    758: #endif
                    759:        if (code & IIR_TIMEO)
1.20      thorpej   760:                dcmrint(sc);
1.1       cgd       761:        if (code & IIR_PORT0)
1.20      thorpej   762:                dcmpint(sc, 0, pcnd[0]);
1.1       cgd       763:        if (code & IIR_PORT1)
1.20      thorpej   764:                dcmpint(sc, 1, pcnd[1]);
1.1       cgd       765:        if (code & IIR_PORT2)
1.20      thorpej   766:                dcmpint(sc, 2, pcnd[2]);
1.1       cgd       767:        if (code & IIR_PORT3)
1.20      thorpej   768:                dcmpint(sc, 3, pcnd[3]);
1.1       cgd       769:        if (code & IIR_MODM) {
                    770:                if (mcode == 0 || mcode & 0x1)  /* mcode==0 -> 98642 board */
1.20      thorpej   771:                        dcmmint(sc, 0, mcnd[0]);
1.1       cgd       772:                if (mcode & 0x2)
1.20      thorpej   773:                        dcmmint(sc, 1, mcnd[1]);
1.1       cgd       774:                if (mcode & 0x4)
1.20      thorpej   775:                        dcmmint(sc, 2, mcnd[2]);
1.1       cgd       776:                if (mcode & 0x8)
1.20      thorpej   777:                        dcmmint(sc, 3, mcnd[3]);
1.1       cgd       778:        }
                    779:
                    780:        /*
                    781:         * Chalk up a receiver interrupt if the timer running or one of
                    782:         * the ports reports a special character interrupt.
                    783:         */
                    784:        if ((code & IIR_TIMEO) ||
                    785:            ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
                    786:                dis->dis_intr++;
                    787:        /*
                    788:         * See if it is time to check/change the interrupt rate.
                    789:         */
                    790:        if (dcmistype < 0 &&
                    791:            (i = time.tv_sec - dis->dis_time) >= dcminterval) {
                    792:                /*
                    793:                 * If currently per-character and averaged over 70 interrupts
                    794:                 * per-second (66 is threshold of 600 baud) in last interval,
                    795:                 * switch to timer mode.
                    796:                 *
                    797:                 * XXX decay counts ala load average to avoid spikes?
                    798:                 */
                    799:                if (dis->dis_perchar && dis->dis_intr > 70 * i)
                    800:                        dcmsetischeme(brd, DIS_TIMER);
                    801:                /*
                    802:                 * If currently using timer and had more interrupts than
                    803:                 * received characters in the last interval, switch back
                    804:                 * to per-character.  Note that after changing to per-char
                    805:                 * we must process any characters already in the queue
                    806:                 * since they may have arrived before the bitmap was setup.
                    807:                 *
                    808:                 * XXX decay counts?
                    809:                 */
                    810:                else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
                    811:                        dcmsetischeme(brd, DIS_PERCHAR);
1.20      thorpej   812:                        dcmrint(sc);
1.1       cgd       813:                }
                    814:                dis->dis_intr = dis->dis_char = 0;
                    815:                dis->dis_time = time.tv_sec;
                    816:        }
                    817:        return (1);
                    818: }
                    819:
                    820: /*
                    821:  *  Port interrupt.  Can be two things:
                    822:  *     First, it might be a special character (exception interrupt);
                    823:  *     Second, it may be a buffer empty (transmit interrupt);
                    824:  */
1.65    ! thorpej   825: static void
        !           826: dcmpint(struct dcm_softc *sc, int port, int code)
1.1       cgd       827: {
                    828:
                    829:        if (code & IT_SPEC)
1.20      thorpej   830:                dcmreadbuf(sc, port);
1.1       cgd       831:        if (code & IT_TX)
1.20      thorpej   832:                dcmxint(sc, port);
1.1       cgd       833: }
                    834:
1.65    ! thorpej   835: static void
        !           836: dcmrint(struct dcm_softc *sc)
1.1       cgd       837: {
1.20      thorpej   838:        int port;
1.1       cgd       839:
1.20      thorpej   840:        for (port = 0; port < NDCMPORT; port++)
                    841:                dcmreadbuf(sc, port);
1.1       cgd       842: }
                    843:
1.65    ! thorpej   844: static void
        !           845: dcmreadbuf(struct dcm_softc *sc, int port)
1.1       cgd       846: {
1.20      thorpej   847:        struct dcmdevice *dcm = sc->sc_dcm;
                    848:        struct dcmpreg *pp = dcm_preg(dcm, port);
                    849:        struct dcmrfifo *fifo;
1.38      scottr    850:        struct tty *tp;
1.20      thorpej   851:        int c, stat;
                    852:        u_int head;
1.1       cgd       853:        int nch = 0;
1.14      mycroft   854: #ifdef DCMSTATS
1.20      thorpej   855:        struct dcmstats *dsp = &sc->sc_stats;
1.1       cgd       856:
                    857:        dsp->rints++;
                    858: #endif
1.38      scottr    859:        tp = sc->sc_tty[port];
1.40      scottr    860:        if (tp == NULL)
1.38      scottr    861:                return;
                    862:
1.1       cgd       863:        if ((tp->t_state & TS_ISOPEN) == 0) {
                    864: #ifdef KGDB
1.52      gehenna   865:                int maj;
                    866:
                    867:                maj = cdevsw_lookup_major(&dcm_cdevsw);
                    868:
                    869:                if ((makedev(maj, minor(tp->t_dev)) == kgdb_dev) &&
1.1       cgd       870:                    (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
1.14      mycroft   871:                    dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
1.1       cgd       872:                        pp->r_head = (head + 2) & RX_MASK;
                    873:                        kgdb_connect(0);        /* trap into kgdb */
                    874:                        return;
                    875:                }
                    876: #endif /* KGDB */
                    877:                pp->r_head = pp->r_tail & RX_MASK;
                    878:                return;
                    879:        }
                    880:
                    881:        head = pp->r_head & RX_MASK;
                    882:        fifo = &dcm->dcm_rfifos[3-port][head>>1];
                    883:        /*
                    884:         * XXX upper bound on how many chars we will take in one swallow?
                    885:         */
                    886:        while (head != (pp->r_tail & RX_MASK)) {
                    887:                /*
                    888:                 * Get character/status and update head pointer as fast
                    889:                 * as possible to make room for more characters.
                    890:                 */
                    891:                c = fifo->data_char;
                    892:                stat = fifo->data_stat;
                    893:                head = (head + 2) & RX_MASK;
                    894:                pp->r_head = head;
                    895:                fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
                    896:                nch++;
                    897:
                    898: #ifdef DEBUG
                    899:                if (dcmdebug & DDB_INPUT)
1.31      christos  900:                        printf("%s port %d: dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n",
1.34      thorpej   901:                               sc->sc_dev.dv_xname, port,
1.20      thorpej   902:                               c&0xFF, c, stat&0xFF,
1.1       cgd       903:                               tp->t_flags, head, pp->r_tail);
                    904: #endif
                    905:                /*
                    906:                 * Check for and handle errors
                    907:                 */
                    908:                if (stat & RD_MASK) {
                    909: #ifdef DEBUG
                    910:                        if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
1.31      christos  911:                                printf("%s port %d: dcmreadbuf: err: c%x('%c') s%x\n",
1.34      thorpej   912:                                       sc->sc_dev.dv_xname, port,
1.20      thorpej   913:                                       stat, c&0xFF, c);
1.1       cgd       914: #endif
                    915:                        if (stat & (RD_BD | RD_FE))
                    916:                                c |= TTY_FE;
                    917:                        else if (stat & RD_PE)
                    918:                                c |= TTY_PE;
                    919:                        else if (stat & RD_OVF)
                    920:                                log(LOG_WARNING,
1.20      thorpej   921:                                    "%s port %d: silo overflow\n",
1.34      thorpej   922:                                    sc->sc_dev.dv_xname, port);
1.1       cgd       923:                        else if (stat & RD_OE)
                    924:                                log(LOG_WARNING,
1.20      thorpej   925:                                    "%s port %d: uart overflow\n",
1.34      thorpej   926:                                    sc->sc_dev.dv_xname, port);
1.1       cgd       927:                }
1.45      eeh       928:                (*tp->t_linesw->l_rint)(c, tp);
1.1       cgd       929:        }
1.20      thorpej   930:        sc->sc_scheme.dis_char += nch;
                    931:
1.14      mycroft   932: #ifdef DCMSTATS
1.1       cgd       933:        dsp->rchars += nch;
                    934:        if (nch <= DCMRBSIZE)
                    935:                dsp->rsilo[nch]++;
                    936:        else
                    937:                dsp->rsilo[DCMRBSIZE+1]++;
                    938: #endif
                    939: }
                    940:
1.65    ! thorpej   941: static void
        !           942: dcmxint(struct dcm_softc *sc, int port)
1.1       cgd       943: {
1.38      scottr    944:        struct tty *tp;
                    945:
                    946:        tp = sc->sc_tty[port];
                    947:        if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
                    948:                return;
1.20      thorpej   949:
1.1       cgd       950:        tp->t_state &= ~TS_BUSY;
                    951:        if (tp->t_state & TS_FLUSH)
                    952:                tp->t_state &= ~TS_FLUSH;
1.45      eeh       953:        (*tp->t_linesw->l_start)(tp);
1.1       cgd       954: }
                    955:
1.65    ! thorpej   956: static void
        !           957: dcmmint(struct dcm_softc *sc, int port, int mcnd)
1.1       cgd       958: {
                    959:        int delta;
1.20      thorpej   960:        struct tty *tp;
                    961:        struct dcmdevice *dcm = sc->sc_dcm;
                    962:
1.1       cgd       963: #ifdef DEBUG
                    964:        if (dcmdebug & DDB_MODEM)
1.31      christos  965:                printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n",
1.34      thorpej   966:                       sc->sc_dev.dv_xname, port, mcnd, sc->sc_mcndlast[port]);
1.1       cgd       967: #endif
1.20      thorpej   968:        delta = mcnd ^ sc->sc_mcndlast[port];
                    969:        sc->sc_mcndlast[port] = mcnd;
1.58      gmcgarry  970:        tp = sc->sc_tty[port];
                    971:        if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
                    972:                return;
                    973:
1.1       cgd       974:        if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
1.55      gmcgarry  975:            (tp->t_cflag & CCTS_OFLOW)) {
1.1       cgd       976:                if (mcnd & MI_CTS) {
                    977:                        tp->t_state &= ~TS_TTSTOP;
                    978:                        ttstart(tp);
                    979:                } else
                    980:                        tp->t_state |= TS_TTSTOP;       /* inline dcmstop */
                    981:        }
                    982:        if (delta & MI_CD) {
                    983:                if (mcnd & MI_CD)
1.45      eeh       984:                        (void)(*tp->t_linesw->l_modem)(tp, 1);
1.20      thorpej   985:                else if ((sc->sc_softCAR & (1 << port)) == 0 &&
1.45      eeh       986:                    (*tp->t_linesw->l_modem)(tp, 0) == 0) {
1.20      thorpej   987:                        sc->sc_modem[port]->mdmout = MO_OFF;
1.1       cgd       988:                        SEM_LOCK(dcm);
1.20      thorpej   989:                        dcm->dcm_modemchng |= (1 << port);
1.1       cgd       990:                        dcm->dcm_cr |= CR_MODM;
                    991:                        SEM_UNLOCK(dcm);
                    992:                        DELAY(10); /* time to change lines */
                    993:                }
                    994:        }
                    995: }
                    996:
1.65    ! thorpej   997: static int
        !           998: dcmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
1.1       cgd       999: {
1.20      thorpej  1000:        struct dcm_softc *sc;
                   1001:        struct tty *tp;
                   1002:        struct dcmdevice *dcm;
                   1003:        int board, port, unit = DCMUNIT(dev);
1.1       cgd      1004:        int error, s;
1.20      thorpej  1005:
                   1006:        port = DCMPORT(unit);
                   1007:        board = DCMBOARD(unit);
                   1008:
1.34      thorpej  1009:        sc = dcm_cd.cd_devs[board];
1.20      thorpej  1010:        dcm = sc->sc_dcm;
                   1011:        tp = sc->sc_tty[port];
1.63      tsutsui  1012:
1.1       cgd      1013: #ifdef DEBUG
                   1014:        if (dcmdebug & DDB_IOCTL)
1.37      scottr   1015:                printf("%s port %d: dcmioctl: cmd %lx data %x flag %x\n",
1.34      thorpej  1016:                       sc->sc_dev.dv_xname, port, cmd, *data, flag);
1.1       cgd      1017: #endif
1.51      atatat   1018:
1.61      fvdl     1019:        error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
1.51      atatat   1020:        if (error != EPASSTHROUGH)
1.1       cgd      1021:                return (error);
1.51      atatat   1022:
1.61      fvdl     1023:        error = ttioctl(tp, cmd, data, flag, p);
1.51      atatat   1024:        if (error != EPASSTHROUGH)
1.1       cgd      1025:                return (error);
                   1026:
                   1027:        switch (cmd) {
                   1028:        case TIOCSBRK:
                   1029:                /*
                   1030:                 * Wait for transmitter buffer to empty
                   1031:                 */
                   1032:                s = spltty();
                   1033:                while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
                   1034:                        DELAY(DCM_USPERCH(tp->t_ospeed));
                   1035:                SEM_LOCK(dcm);
                   1036:                dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
                   1037:                dcm->dcm_cr |= (1 << port);     /* start break */
                   1038:                SEM_UNLOCK(dcm);
                   1039:                splx(s);
                   1040:                break;
                   1041:
                   1042:        case TIOCCBRK:
                   1043:                SEM_LOCK(dcm);
                   1044:                dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
                   1045:                dcm->dcm_cr |= (1 << port);     /* end break */
                   1046:                SEM_UNLOCK(dcm);
                   1047:                break;
                   1048:
                   1049:        case TIOCSDTR:
                   1050:                (void) dcmmctl(dev, MO_ON, DMBIS);
                   1051:                break;
                   1052:
                   1053:        case TIOCCDTR:
                   1054:                (void) dcmmctl(dev, MO_ON, DMBIC);
                   1055:                break;
                   1056:
                   1057:        case TIOCMSET:
                   1058:                (void) dcmmctl(dev, *(int *)data, DMSET);
                   1059:                break;
                   1060:
                   1061:        case TIOCMBIS:
                   1062:                (void) dcmmctl(dev, *(int *)data, DMBIS);
                   1063:                break;
                   1064:
                   1065:        case TIOCMBIC:
                   1066:                (void) dcmmctl(dev, *(int *)data, DMBIC);
                   1067:                break;
                   1068:
                   1069:        case TIOCMGET:
                   1070:                *(int *)data = dcmmctl(dev, 0, DMGET);
                   1071:                break;
1.18      thorpej  1072:
                   1073:        case TIOCGFLAGS: {
                   1074:                int bits = 0;
                   1075:
1.20      thorpej  1076:                if ((sc->sc_softCAR & (1 << port)))
1.18      thorpej  1077:                        bits |= TIOCFLAG_SOFTCAR;
                   1078:
                   1079:                if (tp->t_cflag & CLOCAL)
                   1080:                        bits |= TIOCFLAG_CLOCAL;
                   1081:
                   1082:                *(int *)data = bits;
                   1083:                break;
                   1084:        }
                   1085:
                   1086:        case TIOCSFLAGS: {
                   1087:                int userbits;
                   1088:
1.61      fvdl     1089:                error = suser(p->p_ucred, &p->p_acflag);
1.18      thorpej  1090:                if (error)
                   1091:                        return (EPERM);
                   1092:
                   1093:                userbits = *(int *)data;
                   1094:
                   1095:                if ((userbits & TIOCFLAG_SOFTCAR) ||
1.24      thorpej  1096:                    ((sc->sc_flags & DCM_ISCONSOLE) &&
                   1097:                    (port == DCMCONSPORT)))
1.20      thorpej  1098:                        sc->sc_softCAR |= (1 << port);
1.18      thorpej  1099:
                   1100:                if (userbits & TIOCFLAG_CLOCAL)
                   1101:                        tp->t_cflag |= CLOCAL;
                   1102:
                   1103:                break;
                   1104:        }
1.1       cgd      1105:
                   1106:        default:
1.51      atatat   1107:                return (EPASSTHROUGH);
1.1       cgd      1108:        }
                   1109:        return (0);
                   1110: }
                   1111:
1.65    ! thorpej  1112: static int
        !          1113: dcmparam(struct tty *tp, struct termios *t)
1.1       cgd      1114: {
1.20      thorpej  1115:        struct dcm_softc *sc;
                   1116:        struct dcmdevice *dcm;
                   1117:        int unit, board, port, mode, cflag = t->c_cflag;
1.1       cgd      1118:        int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
                   1119:
1.20      thorpej  1120:        unit = DCMUNIT(tp->t_dev);
                   1121:        board = DCMBOARD(unit);
                   1122:        port = DCMPORT(unit);
                   1123:
1.34      thorpej  1124:        sc = dcm_cd.cd_devs[board];
1.20      thorpej  1125:        dcm = sc->sc_dcm;
                   1126:
1.1       cgd      1127:        /* check requested parameters */
1.59      gmcgarry 1128:        if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
                   1129:                return (EINVAL);
                   1130:        /* and copy to tty */
                   1131:        tp->t_ispeed = t->c_ispeed;
                   1132:        tp->t_ospeed = t->c_ospeed;
                   1133:        tp->t_cflag = cflag;
1.1       cgd      1134:        if (ospeed == 0) {
1.20      thorpej  1135:                (void) dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET);
1.1       cgd      1136:                return (0);
                   1137:        }
                   1138:
                   1139:        mode = 0;
                   1140:        switch (cflag&CSIZE) {
                   1141:        case CS5:
                   1142:                mode = LC_5BITS; break;
                   1143:        case CS6:
                   1144:                mode = LC_6BITS; break;
                   1145:        case CS7:
                   1146:                mode = LC_7BITS; break;
                   1147:        case CS8:
                   1148:                mode = LC_8BITS; break;
                   1149:        }
                   1150:        if (cflag&PARENB) {
                   1151:                if (cflag&PARODD)
                   1152:                        mode |= LC_PODD;
                   1153:                else
                   1154:                        mode |= LC_PEVEN;
                   1155:        }
                   1156:        if (cflag&CSTOPB)
                   1157:                mode |= LC_2STOP;
                   1158:        else
                   1159:                mode |= LC_1STOP;
                   1160: #ifdef DEBUG
                   1161:        if (dcmdebug & DDB_PARAM)
1.31      christos 1162:                printf("%s port %d: dcmparam: cflag %x mode %x speed %d uperch %d\n",
1.34      thorpej  1163:                       sc->sc_dev.dv_xname, port, cflag, mode, tp->t_ospeed,
1.1       cgd      1164:                       DCM_USPERCH(tp->t_ospeed));
                   1165: #endif
                   1166:
                   1167:        /*
                   1168:         * Wait for transmitter buffer to empty.
                   1169:         */
                   1170:        while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
                   1171:                DELAY(DCM_USPERCH(tp->t_ospeed));
                   1172:        /*
                   1173:         * Make changes known to hardware.
                   1174:         */
                   1175:        dcm->dcm_data[port].dcm_baud = ospeed;
                   1176:        dcm->dcm_data[port].dcm_conf = mode;
                   1177:        SEM_LOCK(dcm);
                   1178:        dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
                   1179:        dcm->dcm_cr |= (1 << port);
                   1180:        SEM_UNLOCK(dcm);
                   1181:        /*
                   1182:         * Delay for config change to take place. Weighted by baud.
                   1183:         * XXX why do we do this?
                   1184:         */
                   1185:        DELAY(16 * DCM_USPERCH(tp->t_ospeed));
                   1186:        return (0);
                   1187: }
1.63      tsutsui  1188:
1.65    ! thorpej  1189: static void
        !          1190: dcmstart(struct tty *tp)
1.1       cgd      1191: {
1.20      thorpej  1192:        struct dcm_softc *sc;
                   1193:        struct dcmdevice *dcm;
                   1194:        struct dcmpreg *pp;
                   1195:        struct dcmtfifo *fifo;
                   1196:        char *bp;
                   1197:        u_int head, tail, next;
                   1198:        int unit, board, port, nch;
1.1       cgd      1199:        char buf[16];
                   1200:        int s;
1.14      mycroft  1201: #ifdef DCMSTATS
1.20      thorpej  1202:        struct dcmstats *dsp = &sc->sc_stats;
1.1       cgd      1203:        int tch = 0;
                   1204: #endif
                   1205:
1.20      thorpej  1206:        unit = DCMUNIT(tp->t_dev);
                   1207:        board = DCMBOARD(unit);
                   1208:        port = DCMPORT(unit);
                   1209:
1.34      thorpej  1210:        sc = dcm_cd.cd_devs[board];
1.20      thorpej  1211:        dcm = sc->sc_dcm;
                   1212:
1.1       cgd      1213:        s = spltty();
1.14      mycroft  1214: #ifdef DCMSTATS
1.1       cgd      1215:        dsp->xints++;
                   1216: #endif
                   1217: #ifdef DEBUG
                   1218:        if (dcmdebug & DDB_OUTPUT)
1.31      christos 1219:                printf("%s port %d: dcmstart: state %x flags %x outcc %d\n",
1.34      thorpej  1220:                       sc->sc_dev.dv_xname, port, tp->t_state, tp->t_flags,
1.7       mycroft  1221:                       tp->t_outq.c_cc);
1.1       cgd      1222: #endif
                   1223:        if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
                   1224:                goto out;
1.7       mycroft  1225:        if (tp->t_outq.c_cc <= tp->t_lowat) {
1.1       cgd      1226:                if (tp->t_state&TS_ASLEEP) {
                   1227:                        tp->t_state &= ~TS_ASLEEP;
1.7       mycroft  1228:                        wakeup((caddr_t)&tp->t_outq);
1.1       cgd      1229:                }
1.2       cgd      1230:                selwakeup(&tp->t_wsel);
1.1       cgd      1231:        }
1.7       mycroft  1232:        if (tp->t_outq.c_cc == 0) {
1.14      mycroft  1233: #ifdef DCMSTATS
1.1       cgd      1234:                dsp->xempty++;
                   1235: #endif
                   1236:                goto out;
                   1237:        }
                   1238:
                   1239:        pp = dcm_preg(dcm, port);
                   1240:        tail = pp->t_tail & TX_MASK;
                   1241:        next = (tail + 1) & TX_MASK;
                   1242:        head = pp->t_head & TX_MASK;
                   1243:        if (head == next)
                   1244:                goto out;
                   1245:        fifo = &dcm->dcm_tfifos[3-port][tail];
                   1246: again:
                   1247:        nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
1.14      mycroft  1248: #ifdef DCMSTATS
1.1       cgd      1249:        tch += nch;
                   1250: #endif
                   1251: #ifdef DEBUG
                   1252:        if (dcmdebug & DDB_OUTPUT)
1.31      christos 1253:                printf("\thead %x tail %x nch %d\n", head, tail, nch);
1.1       cgd      1254: #endif
                   1255:        /*
                   1256:         * Loop transmitting all the characters we can.
                   1257:         */
                   1258:        for (bp = buf; --nch >= 0; bp++) {
                   1259:                fifo->data_char = *bp;
                   1260:                pp->t_tail = next;
                   1261:                /*
                   1262:                 * If this is the first character,
                   1263:                 * get the hardware moving right now.
                   1264:                 */
                   1265:                if (bp == buf) {
                   1266:                        tp->t_state |= TS_BUSY;
                   1267:                        SEM_LOCK(dcm);
                   1268:                        dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
                   1269:                        dcm->dcm_cr |= (1 << port);
                   1270:                        SEM_UNLOCK(dcm);
                   1271:                }
                   1272:                tail = next;
                   1273:                fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
                   1274:                next = (next + 1) & TX_MASK;
                   1275:        }
                   1276:        /*
                   1277:         * Head changed while we were loading the buffer,
                   1278:         * go back and load some more if we can.
                   1279:         */
1.7       mycroft  1280:        if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
1.14      mycroft  1281: #ifdef DCMSTATS
1.1       cgd      1282:                dsp->xrestarts++;
                   1283: #endif
                   1284:                head = pp->t_head & TX_MASK;
                   1285:                goto again;
                   1286:        }
                   1287:
                   1288:        /*
                   1289:         * Kick it one last time in case it finished while we were
                   1290:         * loading the last bunch.
                   1291:         */
                   1292:        if (bp > &buf[1]) {
                   1293:                tp->t_state |= TS_BUSY;
                   1294:                SEM_LOCK(dcm);
                   1295:                dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
                   1296:                dcm->dcm_cr |= (1 << port);
                   1297:                SEM_UNLOCK(dcm);
                   1298:        }
                   1299: #ifdef DEBUG
                   1300:        if (dcmdebug & DDB_INTR)
1.37      scottr   1301:                printf("%s port %d: dcmstart: head %x tail %x outqcc %d\n",
1.34      thorpej  1302:                    sc->sc_dev.dv_xname, port, head, tail, tp->t_outq.c_cc);
1.1       cgd      1303: #endif
                   1304: out:
1.14      mycroft  1305: #ifdef DCMSTATS
1.1       cgd      1306:        dsp->xchars += tch;
                   1307:        if (tch <= DCMXBSIZE)
                   1308:                dsp->xsilo[tch]++;
                   1309:        else
                   1310:                dsp->xsilo[DCMXBSIZE+1]++;
                   1311: #endif
                   1312:        splx(s);
                   1313: }
1.63      tsutsui  1314:
1.1       cgd      1315: /*
                   1316:  * Stop output on a line.
                   1317:  */
1.65    ! thorpej  1318: static void
        !          1319: dcmstop(struct tty *tp, int flag)
1.1       cgd      1320: {
                   1321:        int s;
                   1322:
                   1323:        s = spltty();
                   1324:        if (tp->t_state & TS_BUSY) {
                   1325:                /* XXX is there some way to safely stop transmission? */
                   1326:                if ((tp->t_state&TS_TTSTOP) == 0)
                   1327:                        tp->t_state |= TS_FLUSH;
                   1328:        }
                   1329:        splx(s);
                   1330: }
1.63      tsutsui  1331:
1.1       cgd      1332: /*
                   1333:  * Modem control
                   1334:  */
1.36      scottr   1335: int
1.65    ! thorpej  1336: dcmmctl(dev_t dev, int bits, int how)
1.1       cgd      1337: {
1.20      thorpej  1338:        struct dcm_softc *sc;
                   1339:        struct dcmdevice *dcm;
                   1340:        int s, unit, brd, port, hit = 0;
                   1341:
                   1342:        unit = DCMUNIT(dev);
                   1343:        brd = DCMBOARD(unit);
                   1344:        port = DCMPORT(unit);
1.34      thorpej  1345:
                   1346:        sc = dcm_cd.cd_devs[brd];
1.20      thorpej  1347:        dcm = sc->sc_dcm;
1.1       cgd      1348:
                   1349: #ifdef DEBUG
                   1350:        if (dcmdebug & DDB_MODEM)
1.31      christos 1351:                printf("%s port %d: dcmmctl: bits 0x%x how %x\n",
1.34      thorpej  1352:                       sc->sc_dev.dv_xname, port, bits, how);
1.1       cgd      1353: #endif
                   1354:
                   1355:        s = spltty();
1.20      thorpej  1356:
1.1       cgd      1357:        switch (how) {
                   1358:        case DMSET:
1.20      thorpej  1359:                sc->sc_modem[port]->mdmout = bits;
1.1       cgd      1360:                hit++;
                   1361:                break;
                   1362:
                   1363:        case DMBIS:
1.20      thorpej  1364:                sc->sc_modem[port]->mdmout |= bits;
1.1       cgd      1365:                hit++;
                   1366:                break;
                   1367:
                   1368:        case DMBIC:
1.20      thorpej  1369:                sc->sc_modem[port]->mdmout &= ~bits;
1.1       cgd      1370:                hit++;
                   1371:                break;
                   1372:
                   1373:        case DMGET:
1.20      thorpej  1374:                bits = sc->sc_modem[port]->mdmin;
                   1375:                if (sc->sc_flags & DCM_STDDCE)
1.1       cgd      1376:                        bits = hp2dce_in(bits);
                   1377:                break;
                   1378:        }
                   1379:        if (hit) {
                   1380:                SEM_LOCK(dcm);
                   1381:                dcm->dcm_modemchng |= 1<<(unit & 3);
                   1382:                dcm->dcm_cr |= CR_MODM;
                   1383:                SEM_UNLOCK(dcm);
                   1384:                DELAY(10); /* delay until done */
1.49      gmcgarry 1385:                splx(s);
1.1       cgd      1386:        }
                   1387:        return (bits);
                   1388: }
                   1389:
                   1390: /*
                   1391:  * Set board to either interrupt per-character or at a fixed interval.
                   1392:  */
1.65    ! thorpej  1393: static void
        !          1394: dcmsetischeme(int brd, int flags)
1.1       cgd      1395: {
1.34      thorpej  1396:        struct dcm_softc *sc = dcm_cd.cd_devs[brd];
1.20      thorpej  1397:        struct dcmdevice *dcm = sc->sc_dcm;
                   1398:        struct dcmischeme *dis = &sc->sc_scheme;
                   1399:        int i;
1.1       cgd      1400:        u_char mask;
                   1401:        int perchar = flags & DIS_PERCHAR;
                   1402:
                   1403: #ifdef DEBUG
                   1404:        if (dcmdebug & DDB_INTSCHM)
1.31      christos 1405:                printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n",
1.34      thorpej  1406:                       sc->sc_dev.dv_xname, perchar, dis->dis_perchar,
1.1       cgd      1407:                       dis->dis_intr, dis->dis_char);
                   1408:        if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
1.31      christos 1409:                printf("%s: dcmsetischeme: redundent request %d\n",
1.34      thorpej  1410:                       sc->sc_dev.dv_xname, perchar);
1.1       cgd      1411:                return;
                   1412:        }
                   1413: #endif
                   1414:        /*
                   1415:         * If perchar is non-zero, we enable interrupts on all characters
                   1416:         * otherwise we disable perchar interrupts and use periodic
                   1417:         * polling interrupts.
                   1418:         */
                   1419:        dis->dis_perchar = perchar;
                   1420:        mask = perchar ? 0xf : 0x0;
                   1421:        for (i = 0; i < 256; i++)
                   1422:                dcm->dcm_bmap[i].data_data = mask;
                   1423:        /*
                   1424:         * Don't slow down tandem mode, interrupt on flow control
                   1425:         * chars for any port on the board.
                   1426:         */
                   1427:        if (!perchar) {
1.36      scottr   1428:                struct tty *tp;
1.1       cgd      1429:                int c;
                   1430:
1.20      thorpej  1431:                for (i = 0; i < NDCMPORT; i++) {
                   1432:                        tp = sc->sc_tty[i];
                   1433:
1.1       cgd      1434:                        if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
                   1435:                                dcm->dcm_bmap[c].data_data |= (1 << i);
                   1436:                        if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
                   1437:                                dcm->dcm_bmap[c].data_data |= (1 << i);
                   1438:                }
                   1439:        }
                   1440:        /*
                   1441:         * Board starts with timer disabled so if first call is to
                   1442:         * set perchar mode then we don't want to toggle the timer.
                   1443:         */
                   1444:        if (flags == (DIS_RESET|DIS_PERCHAR))
                   1445:                return;
                   1446:        /*
                   1447:         * Toggle card 16.7ms interrupts (we first make sure that card
                   1448:         * has cleared the bit so it will see the toggle).
                   1449:         */
                   1450:        while (dcm->dcm_cr & CR_TIMER)
                   1451:                ;
                   1452:        SEM_LOCK(dcm);
                   1453:        dcm->dcm_cr |= CR_TIMER;
                   1454:        SEM_UNLOCK(dcm);
                   1455: }
                   1456:
1.65    ! thorpej  1457: static void
        !          1458: dcminit(struct dcmdevice *dcm, int port, int rate)
1.22      thorpej  1459: {
                   1460:        int s, mode;
                   1461:
                   1462:        mode = LC_8BITS | LC_1STOP;
                   1463:
                   1464:        s = splhigh();
                   1465:
                   1466:        /*
                   1467:         * Wait for transmitter buffer to empty.
                   1468:         */
                   1469:        while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
                   1470:                DELAY(DCM_USPERCH(rate));
                   1471:
                   1472:        /*
                   1473:         * Make changes known to hardware.
                   1474:         */
                   1475:        dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
                   1476:        dcm->dcm_data[port].dcm_conf = mode;
                   1477:        SEM_LOCK(dcm);
                   1478:        dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
                   1479:        dcm->dcm_cr |= (1 << port);
                   1480:        SEM_UNLOCK(dcm);
                   1481:
                   1482:        /*
                   1483:         * Delay for config change to take place. Weighted by baud.
                   1484:         * XXX why do we do this?
                   1485:         */
                   1486:        DELAY(16 * DCM_USPERCH(rate));
                   1487:        splx(s);
                   1488: }
                   1489:
1.1       cgd      1490: /*
1.34      thorpej  1491:  * Empirically derived self-test magic
                   1492:  */
1.65    ! thorpej  1493: static int
        !          1494: dcmselftest(struct dcm_softc *sc)
1.34      thorpej  1495: {
                   1496:        struct dcmdevice *dcm = sc->sc_dcm;
1.36      scottr   1497:        int timo = 0;
                   1498:        int s, rv;
1.34      thorpej  1499:
1.35      thorpej  1500:        rv = 1;
                   1501:
                   1502:        s = splhigh();
1.34      thorpej  1503:        dcm->dcm_rsid = DCMRS;
                   1504:        DELAY(50000);   /* 5000 is not long enough */
1.63      tsutsui  1505:        dcm->dcm_rsid = 0;
1.34      thorpej  1506:        dcm->dcm_ic = IC_IE;
                   1507:        dcm->dcm_cr = CR_SELFT;
1.35      thorpej  1508:        while ((dcm->dcm_ic & IC_IR) == 0) {
1.34      thorpej  1509:                if (++timo == 20000)
1.35      thorpej  1510:                        goto out;
                   1511:                DELAY(1);
                   1512:        }
1.34      thorpej  1513:        DELAY(50000);   /* XXX why is this needed ???? */
1.35      thorpej  1514:        while ((dcm->dcm_iir & IIR_SELFT) == 0) {
1.34      thorpej  1515:                if (++timo == 400000)
1.35      thorpej  1516:                        goto out;
                   1517:                DELAY(1);
                   1518:        }
1.34      thorpej  1519:        DELAY(50000);   /* XXX why is this needed ???? */
                   1520:        if (dcm->dcm_stcon != ST_OK) {
                   1521: #if 0
                   1522:                if (hd->hp_args->hw_sc != conscode)
                   1523:                        printf("dcm%d: self test failed: %x\n",
                   1524:                               brd, dcm->dcm_stcon);
                   1525: #endif
1.35      thorpej  1526:                goto out;
1.34      thorpej  1527:        }
                   1528:        dcm->dcm_ic = IC_ID;
1.35      thorpej  1529:        rv = 0;
                   1530:
                   1531:  out:
1.34      thorpej  1532:        splx(s);
1.35      thorpej  1533:        return (rv);
1.34      thorpej  1534: }
                   1535:
                   1536: /*
1.1       cgd      1537:  * Following are all routines needed for DCM to act as console
                   1538:  */
                   1539:
1.24      thorpej  1540: int
1.48      gmcgarry 1541: dcmcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode)
1.1       cgd      1542: {
1.59      gmcgarry 1543:        bus_space_handle_t bsh;
                   1544:        caddr_t va;
                   1545:        struct dcmdevice *dcm;
1.52      gehenna  1546:        int maj;
1.48      gmcgarry 1547:
1.59      gmcgarry 1548:        if (bus_space_map(bst, addr, DIOCSIZE, 0, &bsh))
                   1549:                return (1);
1.48      gmcgarry 1550:
1.59      gmcgarry 1551:        va = bus_space_vaddr(bst, bsh);
1.48      gmcgarry 1552:        dcm = (struct dcmdevice *)va;
1.1       cgd      1553:
1.20      thorpej  1554:        switch (dcm->dcm_rsid) {
1.48      gmcgarry 1555: #ifdef CONSCODE
1.1       cgd      1556:        case DCMID:
1.48      gmcgarry 1557: #endif
1.1       cgd      1558:        case DCMID|DCMCON:
                   1559:                break;
                   1560:        default:
1.48      gmcgarry 1561:                goto error;
1.22      thorpej  1562:        }
1.24      thorpej  1563:
1.48      gmcgarry 1564:        dcminit(dcm, DCMCONSPORT, dcmdefaultrate);
1.59      gmcgarry 1565:        dcmconsinit = 1;
1.48      gmcgarry 1566:        dcmconscode = scode;
1.59      gmcgarry 1567:        dcm_cn = dcm;
1.48      gmcgarry 1568:
1.59      gmcgarry 1569:        /* locate the major number */
                   1570:        maj = cdevsw_lookup_major(&dcm_cdevsw);
1.48      gmcgarry 1571:
1.59      gmcgarry 1572:        /* initialize required fields */
                   1573:        cn_tab = &dcm_cons;
                   1574:        cn_tab->cn_dev = makedev(maj, 0);
1.22      thorpej  1575:
1.1       cgd      1576: #ifdef KGDB_CHEAT
1.24      thorpej  1577:        /* XXX this needs to be fixed. */
1.1       cgd      1578:        /*
                   1579:         * This doesn't currently work, at least not with ite consoles;
                   1580:         * the console hasn't been initialized yet.
                   1581:         */
1.52      gehenna  1582:        if (major(kgdb_dev) == maj &&
1.20      thorpej  1583:            DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) {
1.22      thorpej  1584:                dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate);
1.1       cgd      1585:                if (kgdb_debug_init) {
                   1586:                        /*
                   1587:                         * We assume that console is ready for us...
                   1588:                         * this assumes that a dca or ite console
                   1589:                         * has been selected already and will init
                   1590:                         * on the first putc.
                   1591:                         */
1.31      christos 1592:                        printf("dcm%d: ", DCMUNIT(kgdb_dev));
1.1       cgd      1593:                        kgdb_connect(1);
                   1594:                }
                   1595:        }
                   1596: #endif
                   1597:
1.20      thorpej  1598:
1.59      gmcgarry 1599:        return (0);
1.48      gmcgarry 1600:
                   1601: error:
1.59      gmcgarry 1602:        bus_space_unmap(bst, bsh, DIOCSIZE);
                   1603:        return (1);
1.1       cgd      1604: }
                   1605:
1.24      thorpej  1606: /* ARGSUSED */
1.65    ! thorpej  1607: static int
        !          1608: dcmcngetc(dev_t dev)
1.1       cgd      1609: {
1.20      thorpej  1610:        struct dcmrfifo *fifo;
                   1611:        struct dcmpreg *pp;
                   1612:        u_int head;
1.24      thorpej  1613:        int s, c, stat;
1.22      thorpej  1614:
1.24      thorpej  1615:        pp = dcm_preg(dcm_cn, DCMCONSPORT);
1.20      thorpej  1616:
1.1       cgd      1617:        s = splhigh();
                   1618:        head = pp->r_head & RX_MASK;
1.24      thorpej  1619:        fifo = &dcm_cn->dcm_rfifos[3-DCMCONSPORT][head>>1];
1.1       cgd      1620:        while (head == (pp->r_tail & RX_MASK))
                   1621:                ;
                   1622:        /*
                   1623:         * If board interrupts are enabled, just let our received char
                   1624:         * interrupt through in case some other port on the board was
                   1625:         * busy.  Otherwise we must clear the interrupt.
                   1626:         */
1.22      thorpej  1627:        SEM_LOCK(dcm_cn);
                   1628:        if ((dcm_cn->dcm_ic & IC_IE) == 0)
                   1629:                stat = dcm_cn->dcm_iir;
                   1630:        SEM_UNLOCK(dcm_cn);
1.1       cgd      1631:        c = fifo->data_char;
                   1632:        stat = fifo->data_stat;
                   1633:        pp->r_head = (head + 2) & RX_MASK;
                   1634:        splx(s);
                   1635:        return (c);
                   1636: }
                   1637:
                   1638: /*
                   1639:  * Console kernel output character routine.
                   1640:  */
1.24      thorpej  1641: /* ARGSUSED */
1.65    ! thorpej  1642: static void
        !          1643: dcmcnputc(dev_t dev, int c)
1.1       cgd      1644: {
1.20      thorpej  1645:        struct dcmpreg *pp;
1.1       cgd      1646:        unsigned tail;
1.36      scottr   1647:        int s, stat;
1.22      thorpej  1648:
1.24      thorpej  1649:        pp = dcm_preg(dcm_cn, DCMCONSPORT);
1.20      thorpej  1650:
1.1       cgd      1651:        s = splhigh();
                   1652: #ifdef KGDB
                   1653:        if (dev != kgdb_dev)
                   1654: #endif
                   1655:        if (dcmconsinit == 0) {
1.24      thorpej  1656:                dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
1.1       cgd      1657:                dcmconsinit = 1;
                   1658:        }
                   1659:        tail = pp->t_tail & TX_MASK;
                   1660:        while (tail != (pp->t_head & TX_MASK))
                   1661:                ;
1.24      thorpej  1662:        dcm_cn->dcm_tfifos[3-DCMCONSPORT][tail].data_char = c;
1.1       cgd      1663:        pp->t_tail = tail = (tail + 1) & TX_MASK;
1.22      thorpej  1664:        SEM_LOCK(dcm_cn);
1.24      thorpej  1665:        dcm_cn->dcm_cmdtab[DCMCONSPORT].dcm_data |= CT_TX;
                   1666:        dcm_cn->dcm_cr |= (1 << DCMCONSPORT);
1.22      thorpej  1667:        SEM_UNLOCK(dcm_cn);
1.1       cgd      1668:        while (tail != (pp->t_head & TX_MASK))
                   1669:                ;
                   1670:        /*
                   1671:         * If board interrupts are enabled, just let our completion
                   1672:         * interrupt through in case some other port on the board
                   1673:         * was busy.  Otherwise we must clear the interrupt.
                   1674:         */
1.22      thorpej  1675:        if ((dcm_cn->dcm_ic & IC_IE) == 0) {
                   1676:                SEM_LOCK(dcm_cn);
                   1677:                stat = dcm_cn->dcm_iir;
                   1678:                SEM_UNLOCK(dcm_cn);
1.1       cgd      1679:        }
                   1680:        splx(s);
                   1681: }

CVSweb <webmaster@jp.NetBSD.org>