home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / sys / hp300 / dev / dcm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-27  |  31.5 KB  |  1,322 lines

  1. /*
  2.  * Copyright (c) 1988 University of Utah.
  3.  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * This code is derived from software contributed to Berkeley by
  7.  * the Systems Programming Group of the University of Utah Computer
  8.  * Science Department.
  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 University of
  21.  *    California, Berkeley and its contributors.
  22.  * 4. Neither the name of the University nor the names of its contributors
  23.  *    may be used to endorse or promote products derived from this software
  24.  *    without specific prior written permission.
  25.  *
  26.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  27.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  28.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  29.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  30.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  31.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  32.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  33.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  34.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  35.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  36.  * SUCH DAMAGE.
  37.  *
  38.  * from: $Hdr: dcm.c 1.26 91/01/21$
  39.  *
  40.  *    @(#)dcm.c    7.14 (Berkeley) 6/27/91
  41.  */
  42.  
  43. /*
  44.  * TODO:
  45.  *    Timeouts
  46.  *    Test console support.
  47.  */
  48.  
  49. #include "dcm.h"
  50. #if NDCM > 0
  51. /*
  52.  *  98642/MUX
  53.  */
  54. #include "sys/param.h"
  55. #include "sys/systm.h"
  56. #include "sys/ioctl.h"
  57. #include "sys/tty.h"
  58. #include "sys/proc.h"
  59. #include "sys/conf.h"
  60. #include "sys/file.h"
  61. #include "sys/uio.h"
  62. #include "sys/kernel.h"
  63. #include "sys/syslog.h"
  64. #include "sys/time.h"
  65.  
  66. #include "device.h"
  67. #include "dcmreg.h"
  68. #include "machine/cpu.h"
  69. #include "../hp300/isr.h"
  70.  
  71. #ifndef DEFAULT_BAUD_RATE
  72. #define DEFAULT_BAUD_RATE 9600
  73. #endif
  74.  
  75. int    ttrstrt();
  76. int    dcmprobe(), dcmstart(), dcmintr(), dcmparam();
  77.  
  78. struct    driver dcmdriver = {
  79.     dcmprobe, "dcm",
  80. };
  81.  
  82. #define NDCMLINE (NDCM*4)
  83.  
  84. struct    tty dcm_tty[NDCMLINE];
  85. struct    modemreg *dcm_modem[NDCMLINE];
  86. char    mcndlast[NDCMLINE];    /* XXX last modem status for line */
  87. int    ndcm = NDCMLINE;
  88.  
  89. int    dcm_active;
  90. int    dcmsoftCAR[NDCM];
  91. struct    dcmdevice *dcm_addr[NDCM];
  92. struct    isr dcmisr[NDCM];
  93.  
  94. struct speedtab dcmspeedtab[] = {
  95.     0,    BR_0,
  96.     50,    BR_50,
  97.     75,    BR_75,
  98.     110,    BR_110,
  99.     134,    BR_134,
  100.     150,    BR_150,
  101.     300,    BR_300,
  102.     600,    BR_600,
  103.     1200,    BR_1200,
  104.     1800,    BR_1800,
  105.     2400,    BR_2400,
  106.     4800,    BR_4800,
  107.     9600,    BR_9600,
  108.     19200,    BR_19200,
  109.     38400,    BR_38400,
  110.     -1,    -1
  111. };
  112.  
  113. /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
  114. #define    DCM_USPERCH(s)    (10000000 / (s))
  115.  
  116. /*
  117.  * Per board interrupt scheme.  16.7ms is the polling interrupt rate
  118.  * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
  119.  */
  120. #define DIS_TIMER    0
  121. #define DIS_PERCHAR    1
  122. #define DIS_RESET    2
  123.  
  124. int    dcmistype = -1;        /* -1 == dynamic, 0 == timer, 1 == perchar */
  125. int     dcminterval = 5;    /* interval (secs) between checks */
  126. struct    dcmischeme {
  127.     int    dis_perchar;    /* non-zero if interrupting per char */
  128.     long    dis_time;    /* last time examined */
  129.     int    dis_intr;    /* recv interrupts during last interval */
  130.     int    dis_char;    /* characters read during last interval */
  131. } dcmischeme[NDCM];
  132.  
  133. /*
  134.  * Console support
  135.  */
  136. #ifdef DCMCONSOLE
  137. int    dcmconsole = DCMCONSOLE;
  138. #else
  139. int    dcmconsole = -1;
  140. #endif
  141. int    dcmconsinit;
  142. int    dcmdefaultrate = DEFAULT_BAUD_RATE;
  143. int    dcmconbrdbusy = 0;
  144. int    dcmmajor;
  145. extern    struct tty *constty;
  146.  
  147. #ifdef KGDB
  148. /*
  149.  * Kernel GDB support
  150.  */
  151. #include "machine/remote-sl.h"
  152.  
  153. extern dev_t kgdb_dev;
  154. extern int kgdb_rate;
  155. extern int kgdb_debug_init;
  156. #endif
  157.  
  158. /* #define IOSTATS */
  159.  
  160. #ifdef DEBUG
  161. int    dcmdebug = 0x0;
  162. #define DDB_SIOERR    0x01
  163. #define DDB_PARAM    0x02
  164. #define DDB_INPUT    0x04
  165. #define DDB_OUTPUT    0x08
  166. #define DDB_INTR    0x10
  167. #define DDB_IOCTL    0x20
  168. #define DDB_INTSCHM    0x40
  169. #define DDB_MODEM    0x80
  170. #define DDB_OPENCLOSE    0x100
  171. #endif
  172.  
  173. #ifdef IOSTATS
  174. #define    DCMRBSIZE    94
  175. #define DCMXBSIZE    24
  176.  
  177. struct    dcmstats {
  178.     long    xints;            /* # of xmit ints */
  179.     long    xchars;            /* # of xmit chars */
  180.     long    xempty;            /* times outq is empty in dcmstart */
  181.     long    xrestarts;        /* times completed while xmitting */
  182.     long    rints;            /* # of recv ints */
  183.     long    rchars;            /* # of recv chars */
  184.     long    xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
  185.     long    rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
  186. } dcmstats[NDCM];
  187. #endif
  188.  
  189. #define UNIT(x)        minor(x)
  190. #define    BOARD(x)    (((x) >> 2) & 0x3f)
  191. #define PORT(x)        ((x) & 3)
  192. #define MKUNIT(b,p)    (((b) << 2) | (p))
  193.  
  194. /*
  195.  * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
  196.  * the distribution panel uses "HP DCE" conventions.  If requested via
  197.  * the device flags, we swap the inputs to something closer to normal DCE,
  198.  * allowing a straight-through cable to a DTE or a reversed cable
  199.  * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
  200.  * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
  201.  * DSR or make RTS work, though).  The following gives the full
  202.  * details of a cable from this mux panel to a modem:
  203.  *
  204.  *             HP            modem
  205.  *        name    pin    pin    name
  206.  * HP inputs:
  207.  *        "Rx"     2     3    Tx
  208.  *        CTS     4     5    CTS    (only needed for CCTS_OFLOW)
  209.  *        DCD    20     8    DCD
  210.  *        "DSR"     9     6    DSR    (unneeded)
  211.  *        RI    22    22    RI    (unneeded)
  212.  *
  213.  * HP outputs:
  214.  *        "Tx"     3     2    Rx
  215.  *        "DTR"     6    not connected
  216.  *        "RTS"     8    20    DTR
  217.  *        "SR"    23     4    RTS    (often not needed)
  218.  */
  219. #define    FLAG_STDDCE    0x10    /* map inputs if this bit is set in flags */
  220. #define hp2dce_in(ibits)    (iconv[(ibits) & 0xf])
  221. static char iconv[16] = {
  222.     0,        MI_DM,        MI_CTS,        MI_CTS|MI_DM,
  223.     MI_CD,        MI_CD|MI_DM,    MI_CD|MI_CTS,    MI_CD|MI_CTS|MI_DM,
  224.     MI_RI,        MI_RI|MI_DM,    MI_RI|MI_CTS,    MI_RI|MI_CTS|MI_DM,
  225.     MI_RI|MI_CD,    MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
  226.     MI_RI|MI_CD|MI_CTS|MI_DM
  227. };
  228.  
  229. dcmprobe(hd)
  230.     register struct hp_device *hd;
  231. {
  232.     register struct dcmdevice *dcm;
  233.     register int i;
  234.     register int timo = 0;
  235.     int s, brd, isconsole, mbits;
  236.  
  237.     dcm = (struct dcmdevice *)hd->hp_addr;
  238.     if ((dcm->dcm_rsid & 0x1f) != DCMID)
  239.         return (0);
  240.     brd = hd->hp_unit;
  241.     isconsole = (brd == BOARD(dcmconsole));
  242.     /*
  243.      * XXX selected console device (CONSUNIT) as determined by
  244.      * dcmcnprobe does not agree with logical numbering imposed
  245.      * by the config file (i.e. lowest address DCM is not unit
  246.      * CONSUNIT).  Don't recognize this card.
  247.      */
  248.     if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)])
  249.         return (0);
  250.  
  251.     /*
  252.      * Empirically derived self-test magic
  253.      */
  254.     s = spltty();
  255.     dcm->dcm_rsid = DCMRS;
  256.     DELAY(50000);    /* 5000 is not long enough */
  257.     dcm->dcm_rsid = 0; 
  258.     dcm->dcm_ic = IC_IE;
  259.     dcm->dcm_cr = CR_SELFT;
  260.     while ((dcm->dcm_ic & IC_IR) == 0)
  261.         if (++timo == 20000)
  262.             return (0);
  263.     DELAY(50000)    /* XXX why is this needed ???? */
  264.     while ((dcm->dcm_iir & IIR_SELFT) == 0)
  265.         if (++timo == 400000)
  266.             return (0);
  267.     DELAY(50000)    /* XXX why is this needed ???? */
  268.     if (dcm->dcm_stcon != ST_OK) {
  269.         if (!isconsole)
  270.             printf("dcm%d: self test failed: %x\n",
  271.                    brd, dcm->dcm_stcon);
  272.         return (0);
  273.     }
  274.     dcm->dcm_ic = IC_ID;
  275.     splx(s);
  276.  
  277.     hd->hp_ipl = DCMIPL(dcm->dcm_ic);
  278.     dcm_addr[brd] = dcm;
  279.     dcm_active |= 1 << brd;
  280.     dcmsoftCAR[brd] = hd->hp_flags;
  281.     dcmisr[brd].isr_ipl = hd->hp_ipl;
  282.     dcmisr[brd].isr_arg = brd;
  283.     dcmisr[brd].isr_intr = dcmintr;
  284.     isrlink(&dcmisr[brd]);
  285. #ifdef KGDB
  286.     if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == brd) {
  287.         if (dcmconsole == UNIT(kgdb_dev))
  288.             kgdb_dev = NODEV; /* can't debug over console port */
  289. #ifndef KGDB_CHEAT
  290.         /*
  291.          * The following could potentially be replaced
  292.          * by the corresponding code in dcmcnprobe.
  293.          */
  294.         else {
  295.             (void) dcminit(kgdb_dev, kgdb_rate);
  296.             if (kgdb_debug_init) {
  297.                 printf("dcm%d: ", UNIT(kgdb_dev));
  298.                 kgdb_connect(1);
  299.             } else
  300.                 printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev));
  301.         }
  302.         /* end could be replaced */
  303. #endif
  304.     }
  305. #endif
  306.     if (dcmistype == DIS_TIMER)
  307.         dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
  308.     else
  309.         dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
  310.  
  311.     /* load pointers to modem control */
  312.     dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0;
  313.     dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1;
  314.     dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2;
  315.     dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3;
  316.     /* set DCD (modem) and CTS (flow control) on all ports */
  317.     if (dcmsoftCAR[brd] & FLAG_STDDCE)
  318.         mbits = hp2dce_in(MI_CD|MI_CTS);
  319.     else
  320.         mbits = MI_CD|MI_CTS;
  321.     for (i = 0; i < 4; i++)
  322.         dcm_modem[MKUNIT(brd, i)]->mdmmsk = mbits;
  323.  
  324.     dcm->dcm_ic = IC_IE;        /* turn all interrupts on */
  325.     /*
  326.      * Need to reset baud rate, etc. of next print so reset dcmconsole.
  327.      * Also make sure console is always "hardwired"
  328.      */
  329.     if (isconsole) {
  330.         dcmconsinit = 0;
  331.         dcmsoftCAR[brd] |= (1 << PORT(dcmconsole));
  332.     }
  333.     return (1);
  334. }
  335.  
  336. /* ARGSUSED */
  337. #ifdef __STDC__
  338. dcmopen(dev_t dev, int flag, int mode, struct proc *p)
  339. #else
  340. dcmopen(dev, flag, mode, p)
  341.     dev_t dev;
  342.     int flag, mode;
  343.     struct proc *p;
  344. #endif
  345. {
  346.     register struct tty *tp;
  347.     register int unit, brd;
  348.     int error = 0, mbits;
  349.  
  350.     unit = UNIT(dev);
  351.     brd = BOARD(unit);
  352.     if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0)
  353.         return (ENXIO);
  354.     tp = &dcm_tty[unit];
  355.     tp->t_oproc = dcmstart;
  356.     tp->t_param = dcmparam;
  357.     tp->t_dev = dev;
  358.     if ((tp->t_state & TS_ISOPEN) == 0) {
  359.         tp->t_state |= TS_WOPEN;
  360.         ttychars(tp);
  361.         if (tp->t_ispeed == 0) {
  362.             tp->t_iflag = TTYDEF_IFLAG;
  363.             tp->t_oflag = TTYDEF_OFLAG;
  364.             tp->t_cflag = TTYDEF_CFLAG;
  365.             tp->t_lflag = TTYDEF_LFLAG;
  366.             tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
  367.         }
  368.         (void) dcmparam(tp, &tp->t_termios);
  369.         ttsetwater(tp);
  370.     } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
  371.         return (EBUSY);
  372.     mbits = MO_ON;
  373.     if (dcmsoftCAR[brd] & FLAG_STDDCE)
  374.         mbits |= MO_SR;        /* pin 23, could be used as RTS */
  375.     (void) dcmmctl(dev, mbits, DMSET);    /* enable port */
  376.     if ((dcmsoftCAR[brd] & (1 << PORT(unit))) ||
  377.         (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
  378.         tp->t_state |= TS_CARR_ON;
  379. #ifdef DEBUG
  380.     if (dcmdebug & DDB_MODEM)
  381.         printf("dcm%d: dcmopen port %d softcarr %c\n",
  382.                brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0');
  383. #endif
  384.     (void) spltty();
  385.     while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
  386.         (tp->t_state & TS_CARR_ON) == 0) {
  387.         tp->t_state |= TS_WOPEN;
  388.         if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
  389.             ttopen, 0))
  390.             break;
  391.     }
  392.     (void) spl0();
  393.  
  394. #ifdef DEBUG
  395.     if (dcmdebug & DDB_OPENCLOSE)
  396.         printf("dcmopen: u %x st %x fl %x\n",
  397.             unit, tp->t_state, tp->t_flags);
  398. #endif
  399.     if (error == 0)
  400.         error = (*linesw[tp->t_line].l_open)(dev, tp);
  401.     return (error);
  402. }
  403.  
  404. /*ARGSUSED*/
  405. dcmclose(dev, flag, mode, p)
  406.     dev_t dev;
  407.     int flag, mode;
  408.     struct proc *p;
  409. {
  410.     register struct tty *tp;
  411.     int unit;
  412.  
  413.     unit = UNIT(dev);
  414.     tp = &dcm_tty[unit];
  415.     (*linesw[tp->t_line].l_close)(tp, flag);
  416.     if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
  417.         (tp->t_state&TS_ISOPEN) == 0)
  418.         (void) dcmmctl(dev, MO_OFF, DMSET);
  419. #ifdef DEBUG
  420.     if (dcmdebug & DDB_OPENCLOSE)
  421.         printf("dcmclose: u %x st %x fl %x\n",
  422.             unit, tp->t_state, tp->t_flags);
  423. #endif
  424.     ttyclose(tp);
  425.     return (0);
  426. }
  427.  
  428. dcmread(dev, uio, flag)
  429.     dev_t dev;
  430.     struct uio *uio;
  431. {
  432.     register struct tty *tp;
  433.  
  434.     tp = &dcm_tty[UNIT(dev)];
  435.     return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
  436. }
  437.  
  438. dcmwrite(dev, uio, flag)
  439.     dev_t dev;
  440.     struct uio *uio;
  441. {
  442.     int unit = UNIT(dev);
  443.     register struct tty *tp;
  444.  
  445.     tp = &dcm_tty[unit];
  446.     /*
  447.      * XXX we disallow virtual consoles if the physical console is
  448.      * a serial port.  This is in case there is a display attached that
  449.      * is not the console.  In that situation we don't need/want the X
  450.      * server taking over the console.
  451.      */
  452.     if (constty && unit == dcmconsole)
  453.         constty = NULL;
  454.     return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
  455. }
  456.  
  457. dcmintr(brd)
  458.     register int brd;
  459. {
  460.     register struct dcmdevice *dcm = dcm_addr[brd];
  461.     register struct dcmischeme *dis;
  462.     register int unit = MKUNIT(brd, 0);
  463.     register int code, i;
  464.     int pcnd[4], mcode, mcnd[4];
  465.  
  466.     /*
  467.      * Do all guarded register accesses right off to minimize
  468.      * block out of hardware.
  469.      */
  470.     SEM_LOCK(dcm);
  471.     if ((dcm->dcm_ic & IC_IR) == 0) {
  472.         SEM_UNLOCK(dcm);
  473.         return (0);
  474.     }
  475.     for (i = 0; i < 4; i++) {
  476.         pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
  477.         dcm->dcm_icrtab[i].dcm_data = 0;
  478.         code = dcm_modem[unit+i]->mdmin;
  479.         if (dcmsoftCAR[brd] & FLAG_STDDCE)
  480.             code = hp2dce_in(code);
  481.         mcnd[i] = code;
  482.     }
  483.     code = dcm->dcm_iir & IIR_MASK;
  484.     dcm->dcm_iir = 0;    /* XXX doc claims read clears interrupt?! */
  485.     mcode = dcm->dcm_modemintr;
  486.     dcm->dcm_modemintr = 0;
  487.     SEM_UNLOCK(dcm);
  488.  
  489. #ifdef DEBUG
  490.     if (dcmdebug & DDB_INTR) {
  491.         printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ",
  492.                brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]); 
  493.         printf("miir %x mc %x/%x/%x/%x\n",
  494.                mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
  495.     }
  496. #endif
  497.     if (code & IIR_TIMEO)
  498.         dcmrint(brd, dcm);
  499.     if (code & IIR_PORT0)
  500.         dcmpint(unit+0, pcnd[0], dcm);
  501.     if (code & IIR_PORT1)
  502.         dcmpint(unit+1, pcnd[1], dcm);
  503.     if (code & IIR_PORT2)
  504.         dcmpint(unit+2, pcnd[2], dcm);
  505.     if (code & IIR_PORT3)
  506.         dcmpint(unit+3, pcnd[3], dcm);
  507.     if (code & IIR_MODM) {
  508.         if (mcode == 0 || mcode & 0x1)    /* mcode==0 -> 98642 board */
  509.             dcmmint(unit+0, mcnd[0], dcm);
  510.         if (mcode & 0x2)
  511.             dcmmint(unit+1, mcnd[1], dcm);
  512.         if (mcode & 0x4)
  513.             dcmmint(unit+2, mcnd[2], dcm);
  514.         if (mcode & 0x8)
  515.             dcmmint(unit+3, mcnd[3], dcm);
  516.     }
  517.  
  518.     dis = &dcmischeme[brd];
  519.     /*
  520.      * Chalk up a receiver interrupt if the timer running or one of
  521.      * the ports reports a special character interrupt.
  522.      */
  523.     if ((code & IIR_TIMEO) ||
  524.         ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
  525.         dis->dis_intr++;
  526.     /*
  527.      * See if it is time to check/change the interrupt rate.
  528.      */
  529.     if (dcmistype < 0 &&
  530.         (i = time.tv_sec - dis->dis_time) >= dcminterval) {
  531.         /*
  532.          * If currently per-character and averaged over 70 interrupts
  533.          * per-second (66 is threshold of 600 baud) in last interval,
  534.          * switch to timer mode.
  535.          *
  536.          * XXX decay counts ala load average to avoid spikes?
  537.          */
  538.         if (dis->dis_perchar && dis->dis_intr > 70 * i)
  539.             dcmsetischeme(brd, DIS_TIMER);
  540.         /*
  541.          * If currently using timer and had more interrupts than
  542.          * received characters in the last interval, switch back
  543.          * to per-character.  Note that after changing to per-char
  544.          * we must process any characters already in the queue
  545.          * since they may have arrived before the bitmap was setup.
  546.          *
  547.          * XXX decay counts?
  548.          */
  549.         else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
  550.             dcmsetischeme(brd, DIS_PERCHAR);
  551.             dcmrint(brd, dcm);
  552.         }
  553.         dis->dis_intr = dis->dis_char = 0;
  554.         dis->dis_time = time.tv_sec;
  555.     }
  556.     return (1);
  557. }
  558.  
  559. /*
  560.  *  Port interrupt.  Can be two things:
  561.  *    First, it might be a special character (exception interrupt);
  562.  *    Second, it may be a buffer empty (transmit interrupt);
  563.  */
  564. dcmpint(unit, code, dcm)
  565.     int unit, code;
  566.     struct dcmdevice *dcm;
  567. {
  568.     struct tty *tp = &dcm_tty[unit];
  569.  
  570.     if (code & IT_SPEC)
  571.         dcmreadbuf(unit, dcm, tp);
  572.     if (code & IT_TX)
  573.         dcmxint(unit, dcm, tp);
  574. }
  575.  
  576. dcmrint(brd, dcm)
  577.     int brd;
  578.     register struct dcmdevice *dcm;
  579. {
  580.     register int i, unit;
  581.     register struct tty *tp;
  582.  
  583.     unit = MKUNIT(brd, 0);
  584.     tp = &dcm_tty[unit];
  585.     for (i = 0; i < 4; i++, tp++, unit++)
  586.         dcmreadbuf(unit, dcm, tp);
  587. }
  588.  
  589. dcmreadbuf(unit, dcm, tp)
  590.     int unit;
  591.     register struct dcmdevice *dcm;
  592.     register struct tty *tp;
  593. {
  594.     int port = PORT(unit);
  595.     register struct dcmpreg *pp = dcm_preg(dcm, port);
  596.     register struct dcmrfifo *fifo;
  597.     register int c, stat;
  598.     register unsigned head;
  599.     int nch = 0;
  600. #ifdef IOSTATS
  601.     struct dcmstats *dsp = &dcmstats[BOARD(unit)];
  602.  
  603.     dsp->rints++;
  604. #endif
  605.     if ((tp->t_state & TS_ISOPEN) == 0) {
  606. #ifdef KGDB
  607.         if ((makedev(dcmmajor, unit) == kgdb_dev) &&
  608.             (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
  609.             dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_END) {
  610.             pp->r_head = (head + 2) & RX_MASK;
  611.             kgdb_connect(0);    /* trap into kgdb */
  612.             return;
  613.         }
  614. #endif /* KGDB */
  615.         pp->r_head = pp->r_tail & RX_MASK;
  616.         return;
  617.     }
  618.  
  619.     head = pp->r_head & RX_MASK;
  620.     fifo = &dcm->dcm_rfifos[3-port][head>>1];
  621.     /*
  622.      * XXX upper bound on how many chars we will take in one swallow?
  623.      */
  624.     while (head != (pp->r_tail & RX_MASK)) {
  625.         /*
  626.          * Get character/status and update head pointer as fast
  627.          * as possible to make room for more characters.
  628.          */
  629.         c = fifo->data_char;
  630.         stat = fifo->data_stat;
  631.         head = (head + 2) & RX_MASK;
  632.         pp->r_head = head;
  633.         fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
  634.         nch++;
  635.  
  636. #ifdef DEBUG
  637.         if (dcmdebug & DDB_INPUT)
  638.             printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n",
  639.                    unit, c&0xFF, c, stat&0xFF,
  640.                    tp->t_flags, head, pp->r_tail);
  641. #endif
  642.         /*
  643.          * Check for and handle errors
  644.          */
  645.         if (stat & RD_MASK) {
  646. #ifdef DEBUG
  647.             if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
  648.                 printf("dcmreadbuf(%d): err: c%x('%c') s%x\n",
  649.                        unit, stat, c&0xFF, c);
  650. #endif
  651.             if (stat & (RD_BD | RD_FE))
  652.                 c |= TTY_FE;
  653.             else if (stat & RD_PE)
  654.                 c |= TTY_PE;
  655.             else if (stat & RD_OVF)
  656.                 log(LOG_WARNING,
  657.                     "dcm%d: silo overflow\n", unit);
  658.             else if (stat & RD_OE)
  659.                 log(LOG_WARNING,
  660.                     "dcm%d: uart overflow\n", unit);
  661.         }
  662.         (*linesw[tp->t_line].l_rint)(c, tp);
  663.     }
  664.     dcmischeme[BOARD(unit)].dis_char += nch;
  665. #ifdef IOSTATS
  666.     dsp->rchars += nch;
  667.     if (nch <= DCMRBSIZE)
  668.         dsp->rsilo[nch]++;
  669.     else
  670.         dsp->rsilo[DCMRBSIZE+1]++;
  671. #endif
  672. }
  673.  
  674. dcmxint(unit, dcm, tp)
  675.     int unit;
  676.     struct dcmdevice *dcm;
  677.     register struct tty *tp;
  678. {
  679.     tp->t_state &= ~TS_BUSY;
  680.     if (tp->t_state & TS_FLUSH)
  681.         tp->t_state &= ~TS_FLUSH;
  682.     (*linesw[tp->t_line].l_start)(tp);
  683. }
  684.  
  685. dcmmint(unit, mcnd, dcm)
  686.     register int unit;
  687.     register struct dcmdevice *dcm;
  688.         int mcnd;
  689. {
  690.     register struct tty *tp;
  691.     int delta;
  692.  
  693. #ifdef DEBUG
  694.     if (dcmdebug & DDB_MODEM)
  695.         printf("dcmmint: port %d mcnd %x mcndlast %x\n",
  696.                unit, mcnd, mcndlast[unit]);
  697. #endif
  698.     tp = &dcm_tty[unit];
  699.     delta = mcnd ^ mcndlast[unit];
  700.     mcndlast[unit] = mcnd;
  701.     if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
  702.         (tp->t_flags & CCTS_OFLOW)) {
  703.         if (mcnd & MI_CTS) {
  704.             tp->t_state &= ~TS_TTSTOP;
  705.             ttstart(tp);
  706.         } else
  707.             tp->t_state |= TS_TTSTOP;    /* inline dcmstop */
  708.     }
  709.     if (delta & MI_CD) {
  710.         if (mcnd & MI_CD)
  711.             (void)(*linesw[tp->t_line].l_modem)(tp, 1);
  712.         else if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0 &&
  713.             (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
  714.             dcm_modem[unit]->mdmout = MO_OFF;
  715.             SEM_LOCK(dcm);
  716.             dcm->dcm_modemchng |= 1<<(unit & 3);
  717.             dcm->dcm_cr |= CR_MODM;
  718.             SEM_UNLOCK(dcm);
  719.             DELAY(10); /* time to change lines */
  720.         }
  721.     }
  722. }
  723.  
  724. dcmioctl(dev, cmd, data, flag)
  725.     dev_t dev;
  726.     caddr_t data;
  727. {
  728.     register struct tty *tp;
  729.     register int unit = UNIT(dev);
  730.     register struct dcmdevice *dcm;
  731.     register int port;
  732.     int error, s;
  733.  
  734. #ifdef DEBUG
  735.     if (dcmdebug & DDB_IOCTL)
  736.         printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
  737.                unit, cmd, *data, flag);
  738. #endif
  739.     tp = &dcm_tty[unit];
  740.     error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
  741.     if (error >= 0)
  742.         return (error);
  743.     error = ttioctl(tp, cmd, data, flag);
  744.     if (error >= 0)
  745.         return (error);
  746.  
  747.     port = PORT(unit);
  748.     dcm = dcm_addr[BOARD(unit)];
  749.     switch (cmd) {
  750.     case TIOCSBRK:
  751.         /*
  752.          * Wait for transmitter buffer to empty
  753.          */
  754.         s = spltty();
  755.         while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
  756.             DELAY(DCM_USPERCH(tp->t_ospeed));
  757.         SEM_LOCK(dcm);
  758.         dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
  759.         dcm->dcm_cr |= (1 << port);    /* start break */
  760.         SEM_UNLOCK(dcm);
  761.         splx(s);
  762.         break;
  763.  
  764.     case TIOCCBRK:
  765.         SEM_LOCK(dcm);
  766.         dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
  767.         dcm->dcm_cr |= (1 << port);    /* end break */
  768.         SEM_UNLOCK(dcm);
  769.         break;
  770.  
  771.     case TIOCSDTR:
  772.         (void) dcmmctl(dev, MO_ON, DMBIS);
  773.         break;
  774.  
  775.     case TIOCCDTR:
  776.         (void) dcmmctl(dev, MO_ON, DMBIC);
  777.         break;
  778.  
  779.     case TIOCMSET:
  780.         (void) dcmmctl(dev, *(int *)data, DMSET);
  781.         break;
  782.  
  783.     case TIOCMBIS:
  784.         (void) dcmmctl(dev, *(int *)data, DMBIS);
  785.         break;
  786.  
  787.     case TIOCMBIC:
  788.         (void) dcmmctl(dev, *(int *)data, DMBIC);
  789.         break;
  790.  
  791.     case TIOCMGET:
  792.         *(int *)data = dcmmctl(dev, 0, DMGET);
  793.         break;
  794.  
  795.     default:
  796.         return (ENOTTY);
  797.     }
  798.     return (0);
  799. }
  800.  
  801. dcmparam(tp, t)
  802.     register struct tty *tp;
  803.     register struct termios *t;
  804. {
  805.     register struct dcmdevice *dcm;
  806.     register int port, mode, cflag = t->c_cflag;
  807.     int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
  808.  
  809.     /* check requested parameters */
  810.         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
  811.                 return (EINVAL);
  812.         /* and copy to tty */
  813.         tp->t_ispeed = t->c_ispeed;
  814.         tp->t_ospeed = t->c_ospeed;
  815.         tp->t_cflag = cflag;
  816.     if (ospeed == 0) {
  817.         (void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET);
  818.         return (0);
  819.     }
  820.  
  821.     mode = 0;
  822.     switch (cflag&CSIZE) {
  823.     case CS5:
  824.         mode = LC_5BITS; break;
  825.     case CS6:
  826.         mode = LC_6BITS; break;
  827.     case CS7:
  828.         mode = LC_7BITS; break;
  829.     case CS8:
  830.         mode = LC_8BITS; break;
  831.     }
  832.     if (cflag&PARENB) {
  833.         if (cflag&PARODD)
  834.             mode |= LC_PODD;
  835.         else
  836.             mode |= LC_PEVEN;
  837.     }
  838.     if (cflag&CSTOPB)
  839.         mode |= LC_2STOP;
  840.     else
  841.         mode |= LC_1STOP;
  842. #ifdef DEBUG
  843.     if (dcmdebug & DDB_PARAM)
  844.         printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n",
  845.                UNIT(tp->t_dev), cflag, mode, tp->t_ospeed,
  846.                DCM_USPERCH(tp->t_ospeed));
  847. #endif
  848.  
  849.     port = PORT(tp->t_dev);
  850.     dcm = dcm_addr[BOARD(tp->t_dev)];
  851.     /*
  852.      * Wait for transmitter buffer to empty.
  853.      */
  854.     while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
  855.         DELAY(DCM_USPERCH(tp->t_ospeed));
  856.     /*
  857.      * Make changes known to hardware.
  858.      */
  859.     dcm->dcm_data[port].dcm_baud = ospeed;
  860.     dcm->dcm_data[port].dcm_conf = mode;
  861.     SEM_LOCK(dcm);
  862.     dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
  863.     dcm->dcm_cr |= (1 << port);
  864.     SEM_UNLOCK(dcm);
  865.     /*
  866.      * Delay for config change to take place. Weighted by baud.
  867.      * XXX why do we do this?
  868.      */
  869.     DELAY(16 * DCM_USPERCH(tp->t_ospeed));
  870.     return (0);
  871. }
  872.  
  873. dcmstart(tp)
  874.     register struct tty *tp;
  875. {
  876.     register struct dcmdevice *dcm;
  877.     register struct dcmpreg *pp;
  878.     register struct dcmtfifo *fifo;
  879.     register char *bp;
  880.     register unsigned tail, next;
  881.     register int port, nch;
  882.     unsigned head;
  883.     char buf[16];
  884.     int s;
  885. #ifdef IOSTATS
  886.     struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)];
  887.     int tch = 0;
  888. #endif
  889.  
  890.     s = spltty();
  891. #ifdef IOSTATS
  892.     dsp->xints++;
  893. #endif
  894. #ifdef DEBUG
  895.     if (dcmdebug & DDB_OUTPUT)
  896.         printf("dcmstart(%d): state %x flags %x outcc %d\n",
  897.                UNIT(tp->t_dev), tp->t_state, tp->t_flags,
  898.                tp->t_outq.c_cc);
  899. #endif
  900.     if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
  901.         goto out;
  902.     if (tp->t_outq.c_cc <= tp->t_lowat) {
  903.         if (tp->t_state&TS_ASLEEP) {
  904.             tp->t_state &= ~TS_ASLEEP;
  905.             wakeup((caddr_t)&tp->t_outq);
  906.         }
  907.         if (tp->t_wsel) {
  908.             selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
  909.             tp->t_wsel = 0;
  910.             tp->t_state &= ~TS_WCOLL;
  911.         }
  912.     }
  913.     if (tp->t_outq.c_cc == 0) {
  914. #ifdef IOSTATS
  915.         dsp->xempty++;
  916. #endif
  917.         goto out;
  918.     }
  919.  
  920.     dcm = dcm_addr[BOARD(tp->t_dev)];
  921.     port = PORT(tp->t_dev);
  922.     pp = dcm_preg(dcm, port);
  923.     tail = pp->t_tail & TX_MASK;
  924.     next = (tail + 1) & TX_MASK;
  925.     head = pp->t_head & TX_MASK;
  926.     if (head == next)
  927.         goto out;
  928.     fifo = &dcm->dcm_tfifos[3-port][tail];
  929. again:
  930.     nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
  931. #ifdef IOSTATS
  932.     tch += nch;
  933. #endif
  934. #ifdef DEBUG
  935.     if (dcmdebug & DDB_OUTPUT)
  936.         printf("\thead %x tail %x nch %d\n", head, tail, nch);
  937. #endif
  938.     /*
  939.      * Loop transmitting all the characters we can.
  940.      */
  941.     for (bp = buf; --nch >= 0; bp++) {
  942.         fifo->data_char = *bp;
  943.         pp->t_tail = next;
  944.         /*
  945.          * If this is the first character,
  946.          * get the hardware moving right now.
  947.          */
  948.         if (bp == buf) {
  949.             tp->t_state |= TS_BUSY;
  950.             SEM_LOCK(dcm);
  951.             dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
  952.             dcm->dcm_cr |= (1 << port);
  953.             SEM_UNLOCK(dcm);
  954.         }
  955.         tail = next;
  956.         fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
  957.         next = (next + 1) & TX_MASK;
  958.     }
  959.     /*
  960.      * Head changed while we were loading the buffer,
  961.      * go back and load some more if we can.
  962.      */
  963.     if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
  964. #ifdef IOSTATS
  965.         dsp->xrestarts++;
  966. #endif
  967.         head = pp->t_head & TX_MASK;
  968.         goto again;
  969.     }
  970.  
  971.     /*
  972.      * Kick it one last time in case it finished while we were
  973.      * loading the last bunch.
  974.      */
  975.     if (bp > &buf[1]) {
  976.         tp->t_state |= TS_BUSY;
  977.         SEM_LOCK(dcm);
  978.         dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
  979.         dcm->dcm_cr |= (1 << port);
  980.         SEM_UNLOCK(dcm);
  981.     }
  982. #ifdef DEBUG
  983.     if (dcmdebug & DDB_INTR)
  984.         printf("dcmstart(%d): head %x tail %x outqcc %d\n",
  985.                UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc);
  986. #endif
  987. out:
  988. #ifdef IOSTATS
  989.     dsp->xchars += tch;
  990.     if (tch <= DCMXBSIZE)
  991.         dsp->xsilo[tch]++;
  992.     else
  993.         dsp->xsilo[DCMXBSIZE+1]++;
  994. #endif
  995.     splx(s);
  996. }
  997.  
  998. /*
  999.  * Stop output on a line.
  1000.  */
  1001. dcmstop(tp, flag)
  1002.     register struct tty *tp;
  1003. {
  1004.     int s;
  1005.  
  1006.     s = spltty();
  1007.     if (tp->t_state & TS_BUSY) {
  1008.         /* XXX is there some way to safely stop transmission? */
  1009.         if ((tp->t_state&TS_TTSTOP) == 0)
  1010.             tp->t_state |= TS_FLUSH;
  1011.     }
  1012.     splx(s);
  1013. }
  1014.  
  1015. /*
  1016.  * Modem control
  1017.  */
  1018. dcmmctl(dev, bits, how)
  1019.     dev_t dev;
  1020.     int bits, how;
  1021. {
  1022.     register struct dcmdevice *dcm;
  1023.     int s, unit, brd, hit = 0;
  1024.  
  1025.     unit = UNIT(dev);
  1026. #ifdef DEBUG
  1027.     if (dcmdebug & DDB_MODEM)
  1028.         printf("dcmmctl(%d) unit %d  bits 0x%x how %x\n",
  1029.                BOARD(unit), unit, bits, how);
  1030. #endif
  1031.  
  1032.     brd = BOARD(unit);
  1033.     dcm = dcm_addr[brd];
  1034.     s = spltty();
  1035.     switch (how) {
  1036.  
  1037.     case DMSET:
  1038.         dcm_modem[unit]->mdmout = bits;
  1039.         hit++;
  1040.         break;
  1041.  
  1042.     case DMBIS:
  1043.         dcm_modem[unit]->mdmout |= bits;
  1044.         hit++;
  1045.         break;
  1046.  
  1047.     case DMBIC:
  1048.         dcm_modem[unit]->mdmout &= ~bits;
  1049.         hit++;
  1050.         break;
  1051.  
  1052.     case DMGET:
  1053.         bits = dcm_modem[unit]->mdmin;
  1054.         if (dcmsoftCAR[brd] & FLAG_STDDCE)
  1055.             bits = hp2dce_in(bits);
  1056.         break;
  1057.     }
  1058.     if (hit) {
  1059.         SEM_LOCK(dcm);
  1060.         dcm->dcm_modemchng |= 1<<(unit & 3);
  1061.         dcm->dcm_cr |= CR_MODM;
  1062.         SEM_UNLOCK(dcm);
  1063.         DELAY(10); /* delay until done */
  1064.         (void) splx(s);
  1065.     }
  1066.     return (bits);
  1067. }
  1068.  
  1069. /*
  1070.  * Set board to either interrupt per-character or at a fixed interval.
  1071.  */
  1072. dcmsetischeme(brd, flags)
  1073.     int brd, flags;
  1074. {
  1075.     register struct dcmdevice *dcm = dcm_addr[brd];
  1076.     register struct dcmischeme *dis = &dcmischeme[brd];
  1077.     register int i;
  1078.     u_char mask;
  1079.     int perchar = flags & DIS_PERCHAR;
  1080.  
  1081. #ifdef DEBUG
  1082.     if (dcmdebug & DDB_INTSCHM)
  1083.         printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n",
  1084.                brd, perchar, dis->dis_perchar,
  1085.                dis->dis_intr, dis->dis_char);
  1086.     if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
  1087.         printf("dcmsetischeme(%d):  redundent request %d\n",
  1088.                brd, perchar);
  1089.         return;
  1090.     }
  1091. #endif
  1092.     /*
  1093.      * If perchar is non-zero, we enable interrupts on all characters
  1094.      * otherwise we disable perchar interrupts and use periodic
  1095.      * polling interrupts.
  1096.      */
  1097.     dis->dis_perchar = perchar;
  1098.     mask = perchar ? 0xf : 0x0;
  1099.     for (i = 0; i < 256; i++)
  1100.         dcm->dcm_bmap[i].data_data = mask;
  1101.     /*
  1102.      * Don't slow down tandem mode, interrupt on flow control
  1103.      * chars for any port on the board.
  1104.      */
  1105.     if (!perchar) {
  1106.         register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)];
  1107.         int c;
  1108.  
  1109.         for (i = 0; i < 4; i++, tp++) {
  1110.             if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
  1111.                 dcm->dcm_bmap[c].data_data |= (1 << i);
  1112.             if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
  1113.                 dcm->dcm_bmap[c].data_data |= (1 << i);
  1114.         }
  1115.     }
  1116.     /*
  1117.      * Board starts with timer disabled so if first call is to
  1118.      * set perchar mode then we don't want to toggle the timer.
  1119.      */
  1120.     if (flags == (DIS_RESET|DIS_PERCHAR))
  1121.         return;
  1122.     /*
  1123.      * Toggle card 16.7ms interrupts (we first make sure that card
  1124.      * has cleared the bit so it will see the toggle).
  1125.      */
  1126.     while (dcm->dcm_cr & CR_TIMER)
  1127.         ;
  1128.     SEM_LOCK(dcm);
  1129.     dcm->dcm_cr |= CR_TIMER;
  1130.     SEM_UNLOCK(dcm);
  1131. }
  1132.  
  1133. /*
  1134.  * Following are all routines needed for DCM to act as console
  1135.  */
  1136. #include "../hp300/cons.h"
  1137.  
  1138. dcmcnprobe(cp)
  1139.     struct consdev *cp;
  1140. {
  1141.     register struct hp_hw *hw;
  1142.     int unit;
  1143.  
  1144.     /* locate the major number */
  1145.     for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++)
  1146.         if (cdevsw[dcmmajor].d_open == dcmopen)
  1147.             break;
  1148.  
  1149.     /*
  1150.      * Implicitly assigns the lowest select code DCM card found to be
  1151.      * logical unit 0 (actually CONUNIT).  If your config file does
  1152.      * anything different, you're screwed.
  1153.      */
  1154.     for (hw = sc_table; hw->hw_type; hw++)
  1155.         if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva))
  1156.             break;
  1157.     if (!HW_ISDEV(hw, D_COMMDCM)) {
  1158.         cp->cn_pri = CN_DEAD;
  1159.         return;
  1160.     }
  1161.     unit = CONUNIT;
  1162.     dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva;
  1163.  
  1164.     /* initialize required fields */
  1165.     cp->cn_dev = makedev(dcmmajor, unit);
  1166.     cp->cn_tp = &dcm_tty[unit];
  1167.     switch (dcm_addr[BOARD(unit)]->dcm_rsid) {
  1168.     case DCMID:
  1169.         cp->cn_pri = CN_NORMAL;
  1170.         break;
  1171.     case DCMID|DCMCON:
  1172.         cp->cn_pri = CN_REMOTE;
  1173.         break;
  1174.     default:
  1175.         cp->cn_pri = CN_DEAD;
  1176.         return;
  1177.     }
  1178.     /*
  1179.      * If dcmconsole is initialized, raise our priority.
  1180.      */
  1181.     if (dcmconsole == UNIT(unit))
  1182.         cp->cn_pri = CN_REMOTE;
  1183. #ifdef KGDB_CHEAT
  1184.     /*
  1185.      * This doesn't currently work, at least not with ite consoles;
  1186.      * the console hasn't been initialized yet.
  1187.      */
  1188.     if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) {
  1189.         (void) dcminit(kgdb_dev, kgdb_rate);
  1190.         if (kgdb_debug_init) {
  1191.             /*
  1192.              * We assume that console is ready for us...
  1193.              * this assumes that a dca or ite console
  1194.              * has been selected already and will init
  1195.              * on the first putc.
  1196.              */
  1197.             printf("dcm%d: ", UNIT(kgdb_dev));
  1198.             kgdb_connect(1);
  1199.         }
  1200.     }
  1201. #endif
  1202. }
  1203.  
  1204. dcmcninit(cp)
  1205.     struct consdev *cp;
  1206. {
  1207.     dcminit(cp->cn_dev, dcmdefaultrate);
  1208.     dcmconsinit = 1;
  1209.     dcmconsole = UNIT(cp->cn_dev);
  1210. }
  1211.  
  1212. dcminit(dev, rate)
  1213.     dev_t dev;
  1214.     int rate;
  1215. {
  1216.     register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
  1217.     int s, mode, port;
  1218.  
  1219.     port = PORT(dev);
  1220.     mode = LC_8BITS | LC_1STOP;
  1221.     s = splhigh();
  1222.     /*
  1223.      * Wait for transmitter buffer to empty.
  1224.      */
  1225.     while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
  1226.         DELAY(DCM_USPERCH(rate));
  1227.     /*
  1228.      * Make changes known to hardware.
  1229.      */
  1230.     dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
  1231.     dcm->dcm_data[port].dcm_conf = mode;
  1232.     SEM_LOCK(dcm);
  1233.     dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
  1234.     dcm->dcm_cr |= (1 << port);
  1235.     SEM_UNLOCK(dcm);
  1236.     /*
  1237.      * Delay for config change to take place. Weighted by baud.
  1238.      * XXX why do we do this?
  1239.      */
  1240.     DELAY(16 * DCM_USPERCH(rate));
  1241.     splx(s);
  1242. }
  1243.  
  1244. dcmcngetc(dev)
  1245.     dev_t dev;
  1246. {
  1247.     register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
  1248.     register struct dcmrfifo *fifo;
  1249.     register struct dcmpreg *pp;
  1250.     register unsigned head;
  1251.     int s, c, stat, port;
  1252.  
  1253.     port = PORT(dev);
  1254.     pp = dcm_preg(dcm, port);
  1255.     s = splhigh();
  1256.     head = pp->r_head & RX_MASK;
  1257.     fifo = &dcm->dcm_rfifos[3-port][head>>1];
  1258.     while (head == (pp->r_tail & RX_MASK))
  1259.         ;
  1260.     /*
  1261.      * If board interrupts are enabled, just let our received char
  1262.      * interrupt through in case some other port on the board was
  1263.      * busy.  Otherwise we must clear the interrupt.
  1264.      */
  1265.     SEM_LOCK(dcm);
  1266.     if ((dcm->dcm_ic & IC_IE) == 0)
  1267.         stat = dcm->dcm_iir;
  1268.     SEM_UNLOCK(dcm);
  1269.     c = fifo->data_char;
  1270.     stat = fifo->data_stat;
  1271.     pp->r_head = (head + 2) & RX_MASK;
  1272.     splx(s);
  1273.     return (c);
  1274. }
  1275.  
  1276. /*
  1277.  * Console kernel output character routine.
  1278.  */
  1279. dcmcnputc(dev, c)
  1280.     dev_t dev;
  1281.     int c;
  1282. {
  1283.     register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
  1284.     register struct dcmpreg *pp;
  1285.     unsigned tail;
  1286.     int s, port, stat;
  1287.  
  1288.     port = PORT(dev);
  1289.     pp = dcm_preg(dcm, port);
  1290.     s = splhigh();
  1291. #ifdef KGDB
  1292.     if (dev != kgdb_dev)
  1293. #endif
  1294.     if (dcmconsinit == 0) {
  1295.         (void) dcminit(dev, dcmdefaultrate);
  1296.         dcmconsinit = 1;
  1297.     }
  1298.     tail = pp->t_tail & TX_MASK;
  1299.     while (tail != (pp->t_head & TX_MASK))
  1300.         ;
  1301.     dcm->dcm_tfifos[3-port][tail].data_char = c;
  1302.     pp->t_tail = tail = (tail + 1) & TX_MASK;
  1303.     SEM_LOCK(dcm);
  1304.     dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
  1305.     dcm->dcm_cr |= (1 << port);
  1306.     SEM_UNLOCK(dcm);
  1307.     while (tail != (pp->t_head & TX_MASK))
  1308.         ;
  1309.     /*
  1310.      * If board interrupts are enabled, just let our completion
  1311.      * interrupt through in case some other port on the board
  1312.      * was busy.  Otherwise we must clear the interrupt.
  1313.      */
  1314.     if ((dcm->dcm_ic & IC_IE) == 0) {
  1315.         SEM_LOCK(dcm);
  1316.         stat = dcm->dcm_iir;
  1317.         SEM_UNLOCK(dcm);
  1318.     }
  1319.     splx(s);
  1320. }
  1321. #endif
  1322.