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