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