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