xref: /netbsd-src/sys/arch/hp300/dev/dcm.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /*	$NetBSD: dcm.c,v 1.88 2014/11/15 19:20:01 christos 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.88 2014/11/15 19:20:01 christos 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)		TTUNIT(x)
195 #define	DCMDIALOUT(x)		TTDIALOUT(x)
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 	.d_open = dcmopen,
335 	.d_close = dcmclose,
336 	.d_read = dcmread,
337 	.d_write = dcmwrite,
338 	.d_ioctl = dcmioctl,
339 	.d_stop = dcmstop,
340 	.d_tty = dcmtty,
341 	.d_poll = dcmpoll,
342 	.d_mmap = nommap,
343 	.d_kqfilter = ttykqfilter,
344 	.d_discard = nodiscard,
345 	.d_flag = D_TTY
346 };
347 
348 static int
349 dcmmatch(device_t parent, cfdata_t cf, void *aux)
350 {
351 	struct dio_attach_args *da = aux;
352 
353 	switch (da->da_id) {
354 	case DIO_DEVICE_ID_DCM:
355 	case DIO_DEVICE_ID_DCMREM:
356 		return 1;
357 	}
358 
359 	return 0;
360 }
361 
362 static void
363 dcmattach(device_t parent, device_t self, void *aux)
364 {
365 	struct dcm_softc *sc = device_private(self);
366 	struct dio_attach_args *da = aux;
367 	struct dcmdevice *dcm;
368 	int brd = device_unit(self);
369 	int scode = da->da_scode;
370 	int i, mbits, code;
371 
372 	sc->sc_dev = self;
373 	sc->sc_flags = 0;
374 
375 	if (scode == dcmconscode) {
376 		dcm = dcm_cn;
377 		sc->sc_flags |= DCM_ISCONSOLE;
378 
379 		/*
380 		 * We didn't know which unit this would be during
381 		 * the console probe, so we have to fixup cn_dev here.
382 		 * Note that we always assume port 1 on the board.
383 		 */
384 		cn_tab->cn_dev = makedev(cdevsw_lookup_major(&dcm_cdevsw),
385 		    (brd << 2) | DCMCONSPORT);
386 	} else {
387 		sc->sc_bst = da->da_bst;
388 		if (bus_space_map(sc->sc_bst, da->da_addr, da->da_size,
389 		    BUS_SPACE_MAP_LINEAR, &sc->sc_bsh)) {
390 			aprint_error(": can't map registers\n");
391 			return;
392 		}
393 		dcm = bus_space_vaddr(sc->sc_bst, sc->sc_bsh);
394 	}
395 
396 	sc->sc_dcm = dcm;
397 
398 	/*
399 	 * XXX someone _should_ fix this; the self test screws
400 	 * autoconfig messages.
401 	 */
402 	if ((sc->sc_flags & DCM_ISCONSOLE) && dcmselftest(sc)) {
403 		aprint_normal("\n");
404 		aprint_error_dev(self, "self-test failed\n");
405 		return;
406 	}
407 
408 	/* Extract configuration info from flags. */
409 	sc->sc_softCAR = device_cfdata(self)->cf_flags & DCM_SOFTCAR;
410 	sc->sc_flags |= device_cfdata(self)->cf_flags & DCM_FLAGMASK;
411 
412 	/* Mark our unit as configured. */
413 	sc->sc_flags |= DCM_ACTIVE;
414 
415 	/* Establish the interrupt handler. */
416 	(void)dio_intr_establish(dcmintr, sc, da->da_ipl, IPL_TTY);
417 
418 	if (dcmistype == DIS_TIMER)
419 		dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
420 	else
421 		dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
422 
423 	/* load pointers to modem control */
424 	sc->sc_modem[0] = &dcm->dcm_modem0;
425 	sc->sc_modem[1] = &dcm->dcm_modem1;
426 	sc->sc_modem[2] = &dcm->dcm_modem2;
427 	sc->sc_modem[3] = &dcm->dcm_modem3;
428 
429 	/* set DCD (modem) and CTS (flow control) on all ports */
430 	if (sc->sc_flags & DCM_STDDCE)
431 		mbits = hp2dce_in(MI_CD|MI_CTS);
432 	else
433 		mbits = MI_CD|MI_CTS;
434 
435 	for (i = 0; i < NDCMPORT; i++)
436 		sc->sc_modem[i]->mdmmsk = mbits;
437 
438 	/*
439 	 * Get current state of mdmin register on all ports, so that
440 	 * deltas will work properly.
441 	 */
442 	for (i = 0; i < NDCMPORT; i++) {
443 		code = sc->sc_modem[i]->mdmin;
444 		if (sc->sc_flags & DCM_STDDCE)
445 			code = hp2dce_in(code);
446 		sc->sc_mcndlast[i] = code;
447 	}
448 
449 	dcm->dcm_ic = IC_IE;		/* turn all interrupts on */
450 
451 	/*
452 	 * Need to reset baud rate, etc. of next print so reset dcmconsinit.
453 	 * Also make sure console is always "hardwired"
454 	 */
455 	if (sc->sc_flags & DCM_ISCONSOLE) {
456 		dcmconsinit = 0;
457 		sc->sc_softCAR |= (1 << DCMCONSPORT);
458 		aprint_normal(": console on port %d\n", DCMCONSPORT);
459 	} else
460 		aprint_normal("\n");
461 
462 #ifdef KGDB
463 	if (cdevsw_lookup(kgdb_dev) == &dcm_cdevsw &&
464 	    DCMBOARD(DCMUNIT(kgdb_dev)) == brd) {
465 		if (dcmconsole == DCMUNIT(kgdb_dev))	/* XXX fixme */
466 			kgdb_dev = NODEV; /* can't debug over console port */
467 #ifndef KGDB_CHEAT
468 		/*
469 		 * The following could potentially be replaced
470 		 * by the corresponding code in dcmcnprobe.
471 		 */
472 		else {
473 			dcminit(dcm, DCMPORT(DCMUNIT(kgdb_dev)),
474 			    kgdb_rate);
475 			if (kgdb_debug_init) {
476 				aprint_normal_dev(self, "port %d: ",
477 				    DCMPORT(DCMUNIT(kgdb_dev)));
478 				kgdb_connect(1);
479 			} else
480 				aprint_normal_dev(self,
481 				    "port %d: kgdb enabled\n",
482 				    DCMPORT(DCMUNIT(kgdb_dev)));
483 		}
484 		/* end could be replaced */
485 #endif /* KGDB_CHEAT */
486 	}
487 #endif /* KGDB */
488 }
489 
490 /* ARGSUSED */
491 static int
492 dcmopen(dev_t dev, int flag, int mode, struct lwp *l)
493 {
494 	struct dcm_softc *sc;
495 	struct tty *tp;
496 	int unit, brd, port;
497 	int error = 0, mbits, s;
498 
499 	unit = DCMUNIT(dev);
500 	brd = DCMBOARD(unit);
501 	port = DCMPORT(unit);
502 
503 	sc = device_lookup_private(&dcm_cd, brd);
504 	if (sc == NULL)
505 		return ENXIO;
506 
507 	if ((sc->sc_flags & DCM_ACTIVE) == 0)
508 		return ENXIO;
509 
510 	if (sc->sc_tty[port] == NULL) {
511 		tp = sc->sc_tty[port] = tty_alloc();
512 		tty_attach(tp);
513 	} else
514 		tp = sc->sc_tty[port];
515 
516 	tp->t_oproc = dcmstart;
517 	tp->t_param = dcmparam;
518 	tp->t_dev = dev;
519 
520 	if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
521 		return (EBUSY);
522 
523 	s = spltty();
524 
525 	if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) {
526 		/*
527 		 * Sanity clause: reset the card on first open.
528 		 * The card might be left in an inconsistent state
529 		 * if the card memory is read inadvertently.
530 		 */
531 		dcminit(sc->sc_dcm, port, dcmdefaultrate);
532 
533 		ttychars(tp);
534 		tp->t_iflag = TTYDEF_IFLAG;
535 		tp->t_oflag = TTYDEF_OFLAG;
536 		tp->t_cflag = TTYDEF_CFLAG;
537 		tp->t_lflag = TTYDEF_LFLAG;
538 		tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
539 
540 		(void) dcmparam(tp, &tp->t_termios);
541 		ttsetwater(tp);
542 
543 		/* Set modem control state. */
544 		mbits = MO_ON;
545 		if (sc->sc_flags & DCM_STDDCE)
546 			mbits |= MO_SR;	/* pin 23, could be used as RTS */
547 
548 		(void) dcmmctl(dev, mbits, DMSET);	/* enable port */
549 
550 		/* Set soft-carrier if so configured. */
551 		if ((sc->sc_softCAR & (1 << port)) ||
552 		    (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
553 			tp->t_state |= TS_CARR_ON;
554 	}
555 
556 	splx(s);
557 
558 #ifdef DEBUG
559 	if (dcmdebug & DDB_MODEM)
560 		printf("%s: dcmopen port %d softcarr %c\n",
561 		    device_xname(sc->sc_dev), port,
562 		    (tp->t_state & TS_CARR_ON) ? '1' : '0');
563 #endif
564 
565 	error = ttyopen(tp, DCMDIALOUT(dev), (flag & O_NONBLOCK));
566 	if (error)
567 		goto bad;
568 
569 #ifdef DEBUG
570 	if (dcmdebug & DDB_OPENCLOSE)
571 		printf("%s port %d: dcmopen: st %x fl %x\n",
572 		    device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags);
573 #endif
574 	error = (*tp->t_linesw->l_open)(dev, tp);
575 
576  bad:
577 	return error;
578 }
579 
580 /*ARGSUSED*/
581 static int
582 dcmclose(dev_t dev, int flag, int mode, struct lwp *l)
583 {
584 	int s, unit, board, port;
585 	struct dcm_softc *sc;
586 	struct tty *tp;
587 
588 	unit = DCMUNIT(dev);
589 	board = DCMBOARD(unit);
590 	port = DCMPORT(unit);
591 
592 	sc = device_lookup_private(&dcm_cd,board);
593 	tp = sc->sc_tty[port];
594 
595 	(*tp->t_linesw->l_close)(tp, flag);
596 
597 	s = spltty();
598 
599 	if (tp->t_cflag & HUPCL || tp->t_wopen != 0 ||
600 	    (tp->t_state & TS_ISOPEN) == 0)
601 		(void) dcmmctl(dev, MO_OFF, DMSET);
602 #ifdef DEBUG
603 	if (dcmdebug & DDB_OPENCLOSE)
604 		printf("%s port %d: dcmclose: st %x fl %x\n",
605 		    device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags);
606 #endif
607 	splx(s);
608 	ttyclose(tp);
609 #if 0
610 	tty_detach(tp);
611 	tty_free(tp);
612 	sc->sc_tty[port] == NULL;
613 #endif
614 	return 0;
615 }
616 
617 static int
618 dcmread(dev_t dev, struct uio *uio, int flag)
619 {
620 	int unit, board, port;
621 	struct dcm_softc *sc;
622 	struct tty *tp;
623 
624 	unit = DCMUNIT(dev);
625 	board = DCMBOARD(unit);
626 	port = DCMPORT(unit);
627 
628 	sc = device_lookup_private(&dcm_cd,board);
629 	tp = sc->sc_tty[port];
630 
631 	return (*tp->t_linesw->l_read)(tp, uio, flag);
632 }
633 
634 static int
635 dcmwrite(dev_t dev, struct uio *uio, int flag)
636 {
637 	int unit, board, port;
638 	struct dcm_softc *sc;
639 	struct tty *tp;
640 
641 	unit = DCMUNIT(dev);
642 	board = DCMBOARD(unit);
643 	port = DCMPORT(unit);
644 
645 	sc = device_lookup_private(&dcm_cd, board);
646 	tp = sc->sc_tty[port];
647 
648 	return (*tp->t_linesw->l_write)(tp, uio, flag);
649 }
650 
651 static int
652 dcmpoll(dev_t dev, int events, struct lwp *l)
653 {
654 	int unit, board, port;
655 	struct dcm_softc *sc;
656 	struct tty *tp;
657 
658 	unit = DCMUNIT(dev);
659 	board = DCMBOARD(unit);
660 	port = DCMPORT(unit);
661 
662 	sc = device_lookup_private(&dcm_cd, board);
663 	tp = sc->sc_tty[port];
664 
665 	return (*tp->t_linesw->l_poll)(tp, events, l);
666 }
667 
668 static struct tty *
669 dcmtty(dev_t dev)
670 {
671 	int unit, board, port;
672 	struct dcm_softc *sc;
673 
674 	unit = DCMUNIT(dev);
675 	board = DCMBOARD(unit);
676 	port = DCMPORT(unit);
677 
678 	sc = device_lookup_private(&dcm_cd, board);
679 
680 	return sc->sc_tty[port];
681 }
682 
683 static int
684 dcmintr(void *arg)
685 {
686 	struct dcm_softc *sc = arg;
687 	struct dcmdevice *dcm = sc->sc_dcm;
688 	struct dcmischeme *dis = &sc->sc_scheme;
689 	int brd = device_unit(sc->sc_dev);
690 	int code, i;
691 	int pcnd[4], mcode, mcnd[4];
692 
693 	/*
694 	 * Do all guarded accesses right off to minimize
695 	 * block out of hardware.
696 	 */
697 	SEM_LOCK(dcm);
698 	if ((dcm->dcm_ic & IC_IR) == 0) {
699 		SEM_UNLOCK(dcm);
700 		return 0;
701 	}
702 	for (i = 0; i < 4; i++) {
703 		pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
704 		dcm->dcm_icrtab[i].dcm_data = 0;
705 		code = sc->sc_modem[i]->mdmin;
706 		if (sc->sc_flags & DCM_STDDCE)
707 			code = hp2dce_in(code);
708 		mcnd[i] = code;
709 	}
710 	code = dcm->dcm_iir & IIR_MASK;
711 	dcm->dcm_iir = 0;	/* XXX doc claims read clears interrupt?! */
712 	mcode = dcm->dcm_modemintr;
713 	dcm->dcm_modemintr = 0;
714 	SEM_UNLOCK(dcm);
715 
716 #ifdef DEBUG
717 	if (dcmdebug & DDB_INTR) {
718 		printf("%s: dcmintr: iir %x pc %x/%x/%x/%x ",
719 		    device_xname(sc->sc_dev), code, pcnd[0], pcnd[1],
720 		    pcnd[2], pcnd[3]);
721 		printf("miir %x mc %x/%x/%x/%x\n",
722 		    mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
723 	}
724 #endif
725 	if (code & IIR_TIMEO)
726 		dcmrint(sc);
727 	if (code & IIR_PORT0)
728 		dcmpint(sc, 0, pcnd[0]);
729 	if (code & IIR_PORT1)
730 		dcmpint(sc, 1, pcnd[1]);
731 	if (code & IIR_PORT2)
732 		dcmpint(sc, 2, pcnd[2]);
733 	if (code & IIR_PORT3)
734 		dcmpint(sc, 3, pcnd[3]);
735 	if (code & IIR_MODM) {
736 		if (mcode == 0 || mcode & 0x1)	/* mcode==0 -> 98642 board */
737 			dcmmint(sc, 0, mcnd[0]);
738 		if (mcode & 0x2)
739 			dcmmint(sc, 1, mcnd[1]);
740 		if (mcode & 0x4)
741 			dcmmint(sc, 2, mcnd[2]);
742 		if (mcode & 0x8)
743 			dcmmint(sc, 3, mcnd[3]);
744 	}
745 
746 	/*
747 	 * Chalk up a receiver interrupt if the timer running or one of
748 	 * the ports reports a special character interrupt.
749 	 */
750 	if ((code & IIR_TIMEO) ||
751 	    ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
752 		dis->dis_intr++;
753 	/*
754 	 * See if it is time to check/change the interrupt rate.
755 	 */
756 	if (dcmistype < 0 &&
757 	    (i = time_second - dis->dis_time) >= dcminterval) {
758 		/*
759 		 * If currently per-character and averaged over 70 interrupts
760 		 * per-second (66 is threshold of 600 baud) in last interval,
761 		 * switch to timer mode.
762 		 *
763 		 * XXX decay counts ala load average to avoid spikes?
764 		 */
765 		if (dis->dis_perchar && dis->dis_intr > 70 * i)
766 			dcmsetischeme(brd, DIS_TIMER);
767 		/*
768 		 * If currently using timer and had more interrupts than
769 		 * received characters in the last interval, switch back
770 		 * to per-character.  Note that after changing to per-char
771 		 * we must process any characters already in the queue
772 		 * since they may have arrived before the bitmap was setup.
773 		 *
774 		 * XXX decay counts?
775 		 */
776 		else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
777 			dcmsetischeme(brd, DIS_PERCHAR);
778 			dcmrint(sc);
779 		}
780 		dis->dis_intr = dis->dis_char = 0;
781 		dis->dis_time = time_second;
782 	}
783 	return 1;
784 }
785 
786 /*
787  *  Port interrupt.  Can be two things:
788  *	First, it might be a special character (exception interrupt);
789  *	Second, it may be a buffer empty (transmit interrupt);
790  */
791 static void
792 dcmpint(struct dcm_softc *sc, int port, int code)
793 {
794 
795 	if (code & IT_SPEC)
796 		dcmreadbuf(sc, port);
797 	if (code & IT_TX)
798 		dcmxint(sc, port);
799 }
800 
801 static void
802 dcmrint(struct dcm_softc *sc)
803 {
804 	int port;
805 
806 	for (port = 0; port < NDCMPORT; port++)
807 		dcmreadbuf(sc, port);
808 }
809 
810 static void
811 dcmreadbuf(struct dcm_softc *sc, int port)
812 {
813 	struct dcmdevice *dcm = sc->sc_dcm;
814 	struct dcmpreg *pp = dcm_preg(dcm, port);
815 	struct dcmrfifo *fifo;
816 	struct tty *tp;
817 	int c, stat;
818 	u_int head;
819 	int nch = 0;
820 #ifdef DCMSTATS
821 	struct dcmstats *dsp = &sc->sc_stats;
822 
823 	dsp->rints++;
824 #endif
825 	tp = sc->sc_tty[port];
826 	if (tp == NULL)
827 		return;
828 
829 	if ((tp->t_state & TS_ISOPEN) == 0) {
830 #ifdef KGDB
831 		int maj;
832 
833 		maj = cdevsw_lookup_major(&dcm_cdevsw);
834 
835 		if ((makedev(maj, minor(tp->t_dev)) == kgdb_dev) &&
836 		    (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
837 		    dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
838 			pp->r_head = (head + 2) & RX_MASK;
839 			kgdb_connect(0);	/* trap into kgdb */
840 			return;
841 		}
842 #endif /* KGDB */
843 		pp->r_head = pp->r_tail & RX_MASK;
844 		return;
845 	}
846 
847 	head = pp->r_head & RX_MASK;
848 	fifo = &dcm->dcm_rfifos[3-port][head>>1];
849 	/*
850 	 * XXX upper bound on how many chars we will take in one swallow?
851 	 */
852 	while (head != (pp->r_tail & RX_MASK)) {
853 		/*
854 		 * Get character/status and update head pointer as fast
855 		 * as possible to make room for more characters.
856 		 */
857 		c = fifo->data_char;
858 		stat = fifo->data_stat;
859 		head = (head + 2) & RX_MASK;
860 		pp->r_head = head;
861 		fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
862 		nch++;
863 
864 #ifdef DEBUG
865 		if (dcmdebug & DDB_INPUT)
866 			printf("%s port %d: "
867 			    "dcmreadbuf: c%x('%c') s%x f%x h%x t%x\n",
868 			    device_xname(sc->sc_dev), port,
869 			    c&0xFF, c, stat&0xFF,
870 			    tp->t_flags, head, pp->r_tail);
871 #endif
872 		/*
873 		 * Check for and handle errors
874 		 */
875 		if (stat & RD_MASK) {
876 #ifdef DEBUG
877 			if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
878 				printf("%s port %d: "
879 				    "dcmreadbuf: err: c%x('%c') s%x\n",
880 				    device_xname(sc->sc_dev), port,
881 				    stat, c&0xFF, c);
882 #endif
883 			if (stat & (RD_BD | RD_FE))
884 				c |= TTY_FE;
885 			else if (stat & RD_PE)
886 				c |= TTY_PE;
887 			else if (stat & RD_OVF)
888 				log(LOG_WARNING,
889 				    "%s port %d: silo overflow\n",
890 				    device_xname(sc->sc_dev), port);
891 			else if (stat & RD_OE)
892 				log(LOG_WARNING,
893 				    "%s port %d: uart overflow\n",
894 				    device_xname(sc->sc_dev), port);
895 		}
896 		(*tp->t_linesw->l_rint)(c, tp);
897 	}
898 	sc->sc_scheme.dis_char += nch;
899 
900 #ifdef DCMSTATS
901 	dsp->rchars += nch;
902 	if (nch <= DCMRBSIZE)
903 		dsp->rsilo[nch]++;
904 	else
905 		dsp->rsilo[DCMRBSIZE+1]++;
906 #endif
907 }
908 
909 static void
910 dcmxint(struct dcm_softc *sc, int port)
911 {
912 	struct tty *tp;
913 
914 	tp = sc->sc_tty[port];
915 	if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
916 		return;
917 
918 	tp->t_state &= ~TS_BUSY;
919 	if (tp->t_state & TS_FLUSH)
920 		tp->t_state &= ~TS_FLUSH;
921 	(*tp->t_linesw->l_start)(tp);
922 }
923 
924 static void
925 dcmmint(struct dcm_softc *sc, int port, int mcnd)
926 {
927 	int delta;
928 	struct tty *tp;
929 	struct dcmdevice *dcm = sc->sc_dcm;
930 
931 #ifdef DEBUG
932 	if (dcmdebug & DDB_MODEM)
933 		printf("%s port %d: dcmmint: mcnd %x mcndlast %x\n",
934 		    device_xname(sc->sc_dev), port, mcnd,
935 		    sc->sc_mcndlast[port]);
936 #endif
937 	delta = mcnd ^ sc->sc_mcndlast[port];
938 	sc->sc_mcndlast[port] = mcnd;
939 	tp = sc->sc_tty[port];
940 	if (tp == NULL || (tp->t_state & TS_ISOPEN) == 0)
941 		return;
942 
943 	if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
944 	    (tp->t_cflag & CCTS_OFLOW)) {
945 		if (mcnd & MI_CTS) {
946 			tp->t_state &= ~TS_TTSTOP;
947 			ttstart(tp);
948 		} else
949 			tp->t_state |= TS_TTSTOP;	/* inline dcmstop */
950 	}
951 	if (delta & MI_CD) {
952 		if (mcnd & MI_CD)
953 			(void)(*tp->t_linesw->l_modem)(tp, 1);
954 		else if ((sc->sc_softCAR & (1 << port)) == 0 &&
955 		    (*tp->t_linesw->l_modem)(tp, 0) == 0) {
956 			sc->sc_modem[port]->mdmout = MO_OFF;
957 			SEM_LOCK(dcm);
958 			dcm->dcm_modemchng |= (1 << port);
959 			dcm->dcm_cr |= CR_MODM;
960 			SEM_UNLOCK(dcm);
961 			DELAY(10); /* time to change lines */
962 		}
963 	}
964 }
965 
966 static int
967 dcmioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
968 {
969 	struct dcm_softc *sc;
970 	struct tty *tp;
971 	struct dcmdevice *dcm;
972 	int board, port, unit = DCMUNIT(dev);
973 	int error, s;
974 
975 	port = DCMPORT(unit);
976 	board = DCMBOARD(unit);
977 
978 	sc = device_lookup_private(&dcm_cd, board);
979 	dcm = sc->sc_dcm;
980 	tp = sc->sc_tty[port];
981 
982 #ifdef DEBUG
983 	if (dcmdebug & DDB_IOCTL)
984 		printf("%s port %d: dcmioctl: cmd %lx data %x flag %x\n",
985 		    device_xname(sc->sc_dev), port, cmd, *(int *)data, flag);
986 #endif
987 
988 	error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
989 	if (error != EPASSTHROUGH)
990 		return error;
991 
992 	error = ttioctl(tp, cmd, data, flag, l);
993 	if (error != EPASSTHROUGH)
994 		return error;
995 
996 	switch (cmd) {
997 	case TIOCSBRK:
998 		/*
999 		 * Wait for transmitter buffer to empty
1000 		 */
1001 		s = spltty();
1002 		while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1003 			DELAY(DCM_USPERCH(tp->t_ospeed));
1004 		SEM_LOCK(dcm);
1005 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
1006 		dcm->dcm_cr |= (1 << port);	/* start break */
1007 		SEM_UNLOCK(dcm);
1008 		splx(s);
1009 		break;
1010 
1011 	case TIOCCBRK:
1012 		SEM_LOCK(dcm);
1013 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
1014 		dcm->dcm_cr |= (1 << port);	/* end break */
1015 		SEM_UNLOCK(dcm);
1016 		break;
1017 
1018 	case TIOCSDTR:
1019 		(void) dcmmctl(dev, MO_ON, DMBIS);
1020 		break;
1021 
1022 	case TIOCCDTR:
1023 		(void) dcmmctl(dev, MO_ON, DMBIC);
1024 		break;
1025 
1026 	case TIOCMSET:
1027 		(void) dcmmctl(dev, *(int *)data, DMSET);
1028 		break;
1029 
1030 	case TIOCMBIS:
1031 		(void) dcmmctl(dev, *(int *)data, DMBIS);
1032 		break;
1033 
1034 	case TIOCMBIC:
1035 		(void) dcmmctl(dev, *(int *)data, DMBIC);
1036 		break;
1037 
1038 	case TIOCMGET:
1039 		*(int *)data = dcmmctl(dev, 0, DMGET);
1040 		break;
1041 
1042 	case TIOCGFLAGS: {
1043 		int bits = 0;
1044 
1045 		if ((sc->sc_softCAR & (1 << port)))
1046 			bits |= TIOCFLAG_SOFTCAR;
1047 
1048 		if (tp->t_cflag & CLOCAL)
1049 			bits |= TIOCFLAG_CLOCAL;
1050 
1051 		*(int *)data = bits;
1052 		break;
1053 	}
1054 
1055 	case TIOCSFLAGS: {
1056 		int userbits;
1057 
1058 		if (kauth_authorize_device_tty(l->l_cred,
1059 		    KAUTH_DEVICE_TTY_PRIVSET, tp))
1060 			return (EPERM);
1061 
1062 		userbits = *(int *)data;
1063 
1064 		if ((userbits & TIOCFLAG_SOFTCAR) ||
1065 		    ((sc->sc_flags & DCM_ISCONSOLE) &&
1066 		    (port == DCMCONSPORT)))
1067 			sc->sc_softCAR |= (1 << port);
1068 
1069 		if (userbits & TIOCFLAG_CLOCAL)
1070 			tp->t_cflag |= CLOCAL;
1071 
1072 		break;
1073 	}
1074 
1075 	default:
1076 		return EPASSTHROUGH;
1077 	}
1078 	return 0;
1079 }
1080 
1081 static int
1082 dcmparam(struct tty *tp, struct termios *t)
1083 {
1084 	struct dcm_softc *sc;
1085 	struct dcmdevice *dcm;
1086 	int unit, board, port, mode, cflag = t->c_cflag;
1087 	int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
1088 
1089 	unit = DCMUNIT(tp->t_dev);
1090 	board = DCMBOARD(unit);
1091 	port = DCMPORT(unit);
1092 
1093 	sc = device_lookup_private(&dcm_cd, board);
1094 	dcm = sc->sc_dcm;
1095 
1096 	/* check requested parameters */
1097 	if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
1098 		return EINVAL;
1099 	/* and copy to tty */
1100 	tp->t_ispeed = t->c_ispeed;
1101 	tp->t_ospeed = t->c_ospeed;
1102 	tp->t_cflag = cflag;
1103 	if (ospeed == 0) {
1104 		(void)dcmmctl(DCMUNIT(tp->t_dev), MO_OFF, DMSET);
1105 		return 0;
1106 	}
1107 
1108 	mode = 0;
1109 	switch (cflag&CSIZE) {
1110 	case CS5:
1111 		mode = LC_5BITS; break;
1112 	case CS6:
1113 		mode = LC_6BITS; break;
1114 	case CS7:
1115 		mode = LC_7BITS; break;
1116 	case CS8:
1117 		mode = LC_8BITS; break;
1118 	}
1119 	if (cflag&PARENB) {
1120 		if (cflag&PARODD)
1121 			mode |= LC_PODD;
1122 		else
1123 			mode |= LC_PEVEN;
1124 	}
1125 	if (cflag&CSTOPB)
1126 		mode |= LC_2STOP;
1127 	else
1128 		mode |= LC_1STOP;
1129 #ifdef DEBUG
1130 	if (dcmdebug & DDB_PARAM)
1131 		printf("%s port %d: "
1132 		    "dcmparam: cflag %x mode %x speed %d uperch %d\n",
1133 		    device_xname(sc->sc_dev), port, cflag, mode, tp->t_ospeed,
1134 		    DCM_USPERCH(tp->t_ospeed));
1135 #endif
1136 
1137 	/*
1138 	 * Wait for transmitter buffer to empty.
1139 	 */
1140 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1141 		DELAY(DCM_USPERCH(tp->t_ospeed));
1142 	/*
1143 	 * Make changes known to hardware.
1144 	 */
1145 	dcm->dcm_data[port].dcm_baud = ospeed;
1146 	dcm->dcm_data[port].dcm_conf = mode;
1147 	SEM_LOCK(dcm);
1148 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1149 	dcm->dcm_cr |= (1 << port);
1150 	SEM_UNLOCK(dcm);
1151 	/*
1152 	 * Delay for config change to take place. Weighted by baud.
1153 	 * XXX why do we do this?
1154 	 */
1155 	DELAY(16 * DCM_USPERCH(tp->t_ospeed));
1156 	return 0;
1157 }
1158 
1159 static void
1160 dcmstart(struct tty *tp)
1161 {
1162 	struct dcm_softc *sc;
1163 	struct dcmdevice *dcm;
1164 	struct dcmpreg *pp;
1165 	struct dcmtfifo *fifo;
1166 	char *bp;
1167 	u_int head, tail, next;
1168 	int unit, board, port, nch;
1169 	char buf[16];
1170 	int s;
1171 #ifdef DCMSTATS
1172 	struct dcmstats *dsp = &sc->sc_stats;
1173 	int tch = 0;
1174 #endif
1175 
1176 	unit = DCMUNIT(tp->t_dev);
1177 	board = DCMBOARD(unit);
1178 	port = DCMPORT(unit);
1179 
1180 	sc = device_lookup_private(&dcm_cd, board);
1181 	dcm = sc->sc_dcm;
1182 
1183 	s = spltty();
1184 #ifdef DCMSTATS
1185 	dsp->xints++;
1186 #endif
1187 #ifdef DEBUG
1188 	if (dcmdebug & DDB_OUTPUT)
1189 		printf("%s port %d: dcmstart: state %x flags %x outcc %d\n",
1190 		    device_xname(sc->sc_dev), port, tp->t_state, tp->t_flags,
1191 		    tp->t_outq.c_cc);
1192 #endif
1193 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
1194 		goto out;
1195 	if (!ttypull(tp)) {
1196 #ifdef DCMSTATS
1197 		dsp->xempty++;
1198 #endif
1199 		goto out;
1200 	}
1201 
1202 	pp = dcm_preg(dcm, port);
1203 	tail = pp->t_tail & TX_MASK;
1204 	next = (tail + 1) & TX_MASK;
1205 	head = pp->t_head & TX_MASK;
1206 	if (head == next)
1207 		goto out;
1208 	fifo = &dcm->dcm_tfifos[3-port][tail];
1209 again:
1210 	nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
1211 #ifdef DCMSTATS
1212 	tch += nch;
1213 #endif
1214 #ifdef DEBUG
1215 	if (dcmdebug & DDB_OUTPUT)
1216 		printf("\thead %x tail %x nch %d\n", head, tail, nch);
1217 #endif
1218 	/*
1219 	 * Loop transmitting all the characters we can.
1220 	 */
1221 	for (bp = buf; --nch >= 0; bp++) {
1222 		fifo->data_char = *bp;
1223 		pp->t_tail = next;
1224 		/*
1225 		 * If this is the first character,
1226 		 * get the hardware moving right now.
1227 		 */
1228 		if (bp == buf) {
1229 			tp->t_state |= TS_BUSY;
1230 			SEM_LOCK(dcm);
1231 			dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1232 			dcm->dcm_cr |= (1 << port);
1233 			SEM_UNLOCK(dcm);
1234 		}
1235 		tail = next;
1236 		fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
1237 		next = (next + 1) & TX_MASK;
1238 	}
1239 	/*
1240 	 * Head changed while we were loading the buffer,
1241 	 * go back and load some more if we can.
1242 	 */
1243 	if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
1244 #ifdef DCMSTATS
1245 		dsp->xrestarts++;
1246 #endif
1247 		head = pp->t_head & TX_MASK;
1248 		goto again;
1249 	}
1250 
1251 	/*
1252 	 * Kick it one last time in case it finished while we were
1253 	 * loading the last bunch.
1254 	 */
1255 	if (bp > &buf[1]) {
1256 		tp->t_state |= TS_BUSY;
1257 		SEM_LOCK(dcm);
1258 		dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1259 		dcm->dcm_cr |= (1 << port);
1260 		SEM_UNLOCK(dcm);
1261 	}
1262 #ifdef DEBUG
1263 	if (dcmdebug & DDB_INTR)
1264 		printf("%s port %d: dcmstart: head %x tail %x outqcc %d\n",
1265 		    device_xname(sc->sc_dev), port, head, tail,
1266 		    tp->t_outq.c_cc);
1267 #endif
1268 out:
1269 #ifdef DCMSTATS
1270 	dsp->xchars += tch;
1271 	if (tch <= DCMXBSIZE)
1272 		dsp->xsilo[tch]++;
1273 	else
1274 		dsp->xsilo[DCMXBSIZE+1]++;
1275 #endif
1276 	splx(s);
1277 }
1278 
1279 /*
1280  * Stop output on a line.
1281  */
1282 static void
1283 dcmstop(struct tty *tp, int flag)
1284 {
1285 	int s;
1286 
1287 	s = spltty();
1288 	if (tp->t_state & TS_BUSY) {
1289 		/* XXX is there some way to safely stop transmission? */
1290 		if ((tp->t_state&TS_TTSTOP) == 0)
1291 			tp->t_state |= TS_FLUSH;
1292 	}
1293 	splx(s);
1294 }
1295 
1296 /*
1297  * Modem control
1298  */
1299 int
1300 dcmmctl(dev_t dev, int bits, int how)
1301 {
1302 	struct dcm_softc *sc;
1303 	struct dcmdevice *dcm;
1304 	int s, unit, brd, port, hit = 0;
1305 
1306 	unit = DCMUNIT(dev);
1307 	brd = DCMBOARD(unit);
1308 	port = DCMPORT(unit);
1309 
1310 	sc = device_lookup_private(&dcm_cd, brd);
1311 	dcm = sc->sc_dcm;
1312 
1313 #ifdef DEBUG
1314 	if (dcmdebug & DDB_MODEM)
1315 		printf("%s port %d: dcmmctl: bits 0x%x how %x\n",
1316 		    device_xname(sc->sc_dev), port, bits, how);
1317 #endif
1318 
1319 	s = spltty();
1320 
1321 	switch (how) {
1322 	case DMSET:
1323 		sc->sc_modem[port]->mdmout = bits;
1324 		hit++;
1325 		break;
1326 
1327 	case DMBIS:
1328 		sc->sc_modem[port]->mdmout |= bits;
1329 		hit++;
1330 		break;
1331 
1332 	case DMBIC:
1333 		sc->sc_modem[port]->mdmout &= ~bits;
1334 		hit++;
1335 		break;
1336 
1337 	case DMGET:
1338 		bits = sc->sc_modem[port]->mdmin;
1339 		if (sc->sc_flags & DCM_STDDCE)
1340 			bits = hp2dce_in(bits);
1341 		break;
1342 	}
1343 	if (hit) {
1344 		SEM_LOCK(dcm);
1345 		dcm->dcm_modemchng |= 1<<(unit & 3);
1346 		dcm->dcm_cr |= CR_MODM;
1347 		SEM_UNLOCK(dcm);
1348 		DELAY(10); /* delay until done */
1349 		splx(s);
1350 	}
1351 	return bits;
1352 }
1353 
1354 /*
1355  * Set board to either interrupt per-character or at a fixed interval.
1356  */
1357 static void
1358 dcmsetischeme(int brd, int flags)
1359 {
1360 	struct dcm_softc *sc = device_lookup_private(&dcm_cd, brd);
1361 	struct dcmdevice *dcm = sc->sc_dcm;
1362 	struct dcmischeme *dis = &sc->sc_scheme;
1363 	int i;
1364 	u_char mask;
1365 	int perchar = flags & DIS_PERCHAR;
1366 
1367 #ifdef DEBUG
1368 	if (dcmdebug & DDB_INTSCHM)
1369 		printf("%s: dcmsetischeme(%d): cur %d, ints %d, chars %d\n",
1370 		    device_xname(sc->sc_dev), perchar, dis->dis_perchar,
1371 		    dis->dis_intr, dis->dis_char);
1372 	if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
1373 		printf("%s: dcmsetischeme: redundent request %d\n",
1374 		    device_xname(sc->sc_dev), perchar);
1375 		return;
1376 	}
1377 #endif
1378 	/*
1379 	 * If perchar is non-zero, we enable interrupts on all characters
1380 	 * otherwise we disable perchar interrupts and use periodic
1381 	 * polling interrupts.
1382 	 */
1383 	dis->dis_perchar = perchar;
1384 	mask = perchar ? 0xf : 0x0;
1385 	for (i = 0; i < 256; i++)
1386 		dcm->dcm_bmap[i].data_data = mask;
1387 	/*
1388 	 * Don't slow down tandem mode, interrupt on flow control
1389 	 * chars for any port on the board.
1390 	 */
1391 	if (!perchar) {
1392 		struct tty *tp;
1393 		int c;
1394 
1395 		for (i = 0; i < NDCMPORT; i++) {
1396 			tp = sc->sc_tty[i];
1397 
1398 			c = tty_getctrlchar(tp, VSTART);
1399 			if (c != _POSIX_VDISABLE)
1400 				dcm->dcm_bmap[c].data_data |= (1 << i);
1401 			c = tty_getctrlchar(tp, VSTOP);
1402 			if (c != _POSIX_VDISABLE)
1403 				dcm->dcm_bmap[c].data_data |= (1 << i);
1404 		}
1405 	}
1406 	/*
1407 	 * Board starts with timer disabled so if first call is to
1408 	 * set perchar mode then we don't want to toggle the timer.
1409 	 */
1410 	if (flags == (DIS_RESET|DIS_PERCHAR))
1411 		return;
1412 	/*
1413 	 * Toggle card 16.7ms interrupts (we first make sure that card
1414 	 * has cleared the bit so it will see the toggle).
1415 	 */
1416 	while (dcm->dcm_cr & CR_TIMER)
1417 		;
1418 	SEM_LOCK(dcm);
1419 	dcm->dcm_cr |= CR_TIMER;
1420 	SEM_UNLOCK(dcm);
1421 }
1422 
1423 static void
1424 dcminit(struct dcmdevice *dcm, int port, int rate)
1425 {
1426 	int s, mode;
1427 
1428 	mode = LC_8BITS | LC_1STOP;
1429 
1430 	s = splhigh();
1431 
1432 	/*
1433 	 * Wait for transmitter buffer to empty.
1434 	 */
1435 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1436 		DELAY(DCM_USPERCH(rate));
1437 
1438 	/*
1439 	 * Make changes known to hardware.
1440 	 */
1441 	dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
1442 	dcm->dcm_data[port].dcm_conf = mode;
1443 	SEM_LOCK(dcm);
1444 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1445 	dcm->dcm_cr |= (1 << port);
1446 	SEM_UNLOCK(dcm);
1447 
1448 	/*
1449 	 * Delay for config change to take place. Weighted by baud.
1450 	 * XXX why do we do this?
1451 	 */
1452 	DELAY(16 * DCM_USPERCH(rate));
1453 	splx(s);
1454 }
1455 
1456 /*
1457  * Empirically derived self-test magic
1458  */
1459 static int
1460 dcmselftest(struct dcm_softc *sc)
1461 {
1462 	struct dcmdevice *dcm = sc->sc_dcm;
1463 	int timo = 0;
1464 	int s, rv;
1465 
1466 	rv = 1;
1467 
1468 	s = splhigh();
1469 	dcm->dcm_rsid = DCMRS;
1470 	DELAY(50000);	/* 5000 is not long enough */
1471 	dcm->dcm_rsid = 0;
1472 	dcm->dcm_ic = IC_IE;
1473 	dcm->dcm_cr = CR_SELFT;
1474 	while ((dcm->dcm_ic & IC_IR) == 0) {
1475 		if (++timo == 20000)
1476 			goto out;
1477 		DELAY(1);
1478 	}
1479 	DELAY(50000);	/* XXX why is this needed ???? */
1480 	while ((dcm->dcm_iir & IIR_SELFT) == 0) {
1481 		if (++timo == 400000)
1482 			goto out;
1483 		DELAY(1);
1484 	}
1485 	DELAY(50000);	/* XXX why is this needed ???? */
1486 	if (dcm->dcm_stcon != ST_OK) {
1487 #if 0
1488 		if (hd->hp_args->hw_sc != conscode)
1489 			aprint_error_dev(sc->sc_dev, "self test failed: %x\n",
1490 			    dcm->dcm_stcon);
1491 #endif
1492 		goto out;
1493 	}
1494 	dcm->dcm_ic = IC_ID;
1495 	rv = 0;
1496 
1497  out:
1498 	splx(s);
1499 	return rv;
1500 }
1501 
1502 /*
1503  * Following are all routines needed for DCM to act as console
1504  */
1505 
1506 int
1507 dcmcnattach(bus_space_tag_t bst, bus_addr_t addr, int scode)
1508 {
1509 	bus_space_handle_t bsh;
1510 	void *va;
1511 	struct dcmdevice *dcm;
1512 	int maj;
1513 
1514 	if (bus_space_map(bst, addr, DIOCSIZE, 0, &bsh))
1515 		return 1;
1516 
1517 	va = bus_space_vaddr(bst, bsh);
1518 	dcm = (struct dcmdevice *)va;
1519 
1520 	switch (dcm->dcm_rsid) {
1521 #ifdef CONSCODE
1522 	case DCMID:
1523 #endif
1524 	case DCMID|DCMCON:
1525 		break;
1526 	default:
1527 		goto error;
1528 	}
1529 
1530 	dcminit(dcm, DCMCONSPORT, dcmdefaultrate);
1531 	dcmconsinit = 1;
1532 	dcmconscode = scode;
1533 	dcm_cn = dcm;
1534 
1535 	/* locate the major number */
1536 	maj = cdevsw_lookup_major(&dcm_cdevsw);
1537 
1538 	/* initialize required fields */
1539 	cn_tab = &dcm_cons;
1540 	cn_tab->cn_dev = makedev(maj, 0);
1541 
1542 #ifdef KGDB_CHEAT
1543 	/* XXX this needs to be fixed. */
1544 	/*
1545 	 * This doesn't currently work, at least not with ite consoles;
1546 	 * the console hasn't been initialized yet.
1547 	 */
1548 	if (major(kgdb_dev) == maj &&
1549 	    DCMBOARD(DCMUNIT(kgdb_dev)) == DCMBOARD(unit)) {
1550 		dcminit(dcm_cn, DCMPORT(DCMUNIT(kgdb_dev)), kgdb_rate);
1551 		if (kgdb_debug_init) {
1552 			/*
1553 			 * We assume that console is ready for us...
1554 			 * this assumes that a dca or ite console
1555 			 * has been selected already and will init
1556 			 * on the first putc.
1557 			 */
1558 			printf("dcm%d: ", DCMUNIT(kgdb_dev));
1559 			kgdb_connect(1);
1560 		}
1561 	}
1562 #endif
1563 
1564 
1565 	return 0;
1566 
1567 error:
1568 	bus_space_unmap(bst, bsh, DIOCSIZE);
1569 	return 1;
1570 }
1571 
1572 /* ARGSUSED */
1573 static int
1574 dcmcngetc(dev_t dev)
1575 {
1576 	struct dcmrfifo *fifo;
1577 	struct dcmpreg *pp;
1578 	u_int head;
1579 	int s, c, stat;
1580 
1581 	pp = dcm_preg(dcm_cn, DCMCONSPORT);
1582 
1583 	s = splhigh();
1584 	head = pp->r_head & RX_MASK;
1585 	fifo = &dcm_cn->dcm_rfifos[3-DCMCONSPORT][head>>1];
1586 	while (head == (pp->r_tail & RX_MASK))
1587 		;
1588 	/*
1589 	 * If board interrupts are enabled, just let our received char
1590 	 * interrupt through in case some other port on the board was
1591 	 * busy.  Otherwise we must clear the interrupt.
1592 	 */
1593 	SEM_LOCK(dcm_cn);
1594 	if ((dcm_cn->dcm_ic & IC_IE) == 0)
1595 		stat = dcm_cn->dcm_iir;
1596 	SEM_UNLOCK(dcm_cn);
1597 	c = fifo->data_char;
1598 	stat = fifo->data_stat;
1599 	pp->r_head = (head + 2) & RX_MASK;
1600 	__USE(stat);
1601 	splx(s);
1602 	return c;
1603 }
1604 
1605 /*
1606  * Console kernel output character routine.
1607  */
1608 /* ARGSUSED */
1609 static void
1610 dcmcnputc(dev_t dev, int c)
1611 {
1612 	struct dcmpreg *pp;
1613 	unsigned tail;
1614 	int s, stat;
1615 
1616 	pp = dcm_preg(dcm_cn, DCMCONSPORT);
1617 
1618 	s = splhigh();
1619 #ifdef KGDB
1620 	if (dev != kgdb_dev)
1621 #endif
1622 	if (dcmconsinit == 0) {
1623 		dcminit(dcm_cn, DCMCONSPORT, dcmdefaultrate);
1624 		dcmconsinit = 1;
1625 	}
1626 	tail = pp->t_tail & TX_MASK;
1627 	while (tail != (pp->t_head & TX_MASK))
1628 		continue;
1629 	dcm_cn->dcm_tfifos[3-DCMCONSPORT][tail].data_char = c;
1630 	pp->t_tail = tail = (tail + 1) & TX_MASK;
1631 	SEM_LOCK(dcm_cn);
1632 	dcm_cn->dcm_cmdtab[DCMCONSPORT].dcm_data |= CT_TX;
1633 	dcm_cn->dcm_cr |= (1 << DCMCONSPORT);
1634 	SEM_UNLOCK(dcm_cn);
1635 	while (tail != (pp->t_head & TX_MASK))
1636 		continue;
1637 	/*
1638 	 * If board interrupts are enabled, just let our completion
1639 	 * interrupt through in case some other port on the board
1640 	 * was busy.  Otherwise we must clear the interrupt.
1641 	 */
1642 	if ((dcm_cn->dcm_ic & IC_IE) == 0) {
1643 		SEM_LOCK(dcm_cn);
1644 		stat = dcm_cn->dcm_iir;
1645 		SEM_UNLOCK(dcm_cn);
1646 	}
1647 	__USE(stat);
1648 	splx(s);
1649 }
1650