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