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