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

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

CVSweb <webmaster@jp.NetBSD.org>