xref: /original-bsd/sys/hp300/dev/dcm.c (revision 95ecee29)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1982, 1986, 1990, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from Utah: $Hdr: dcm.c 1.29 92/01/21$
13  *
14  *	@(#)dcm.c	8.2 (Berkeley) 09/04/93
15  */
16 
17 /*
18  * TODO:
19  *	Timeouts
20  *	Test console support.
21  */
22 
23 #include "dcm.h"
24 #if NDCM > 0
25 /*
26  *  98642/MUX
27  */
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/ioctl.h>
31 #include <sys/proc.h>
32 #include <sys/tty.h>
33 #include <sys/conf.h>
34 #include <sys/file.h>
35 #include <sys/uio.h>
36 #include <sys/kernel.h>
37 #include <sys/syslog.h>
38 #include <sys/time.h>
39 
40 #include <hp/dev/device.h>
41 
42 #include <hp300/dev/dcmreg.h>
43 #include <machine/cpu.h>
44 #include <hp300/hp300/isr.h>
45 
46 #ifndef DEFAULT_BAUD_RATE
47 #define DEFAULT_BAUD_RATE 9600
48 #endif
49 
50 int	dcmprobe(), dcmintr(), dcmparam();
51 void	dcmstart();
52 struct	driver dcmdriver = {
53 	dcmprobe, "dcm",
54 };
55 
56 #define NDCMLINE (NDCM*4)
57 
58 struct	tty dcm_tty[NDCMLINE];
59 struct	modemreg *dcm_modem[NDCMLINE];
60 char	mcndlast[NDCMLINE];	/* XXX last modem status for line */
61 int	ndcm = NDCMLINE;
62 
63 int	dcm_active;
64 int	dcmsoftCAR[NDCM];
65 struct	dcmdevice *dcm_addr[NDCM];
66 struct	isr dcmisr[NDCM];
67 
68 struct speedtab dcmspeedtab[] = {
69 	0,	BR_0,
70 	50,	BR_50,
71 	75,	BR_75,
72 	110,	BR_110,
73 	134,	BR_134,
74 	150,	BR_150,
75 	300,	BR_300,
76 	600,	BR_600,
77 	1200,	BR_1200,
78 	1800,	BR_1800,
79 	2400,	BR_2400,
80 	4800,	BR_4800,
81 	9600,	BR_9600,
82 	19200,	BR_19200,
83 	38400,	BR_38400,
84 	-1,	-1
85 };
86 
87 /* u-sec per character based on baudrate (assumes 1 start/8 data/1 stop bit) */
88 #define	DCM_USPERCH(s)	(10000000 / (s))
89 
90 /*
91  * Per board interrupt scheme.  16.7ms is the polling interrupt rate
92  * (16.7ms is about 550 baud, 38.4k is 72 chars in 16.7ms).
93  */
94 #define DIS_TIMER	0
95 #define DIS_PERCHAR	1
96 #define DIS_RESET	2
97 
98 int	dcmistype = -1;		/* -1 == dynamic, 0 == timer, 1 == perchar */
99 int     dcminterval = 5;	/* interval (secs) between checks */
100 struct	dcmischeme {
101 	int	dis_perchar;	/* non-zero if interrupting per char */
102 	long	dis_time;	/* last time examined */
103 	int	dis_intr;	/* recv interrupts during last interval */
104 	int	dis_char;	/* characters read during last interval */
105 } dcmischeme[NDCM];
106 
107 /*
108  * Console support
109  */
110 #ifdef DCMCONSOLE
111 int	dcmconsole = DCMCONSOLE;
112 #else
113 int	dcmconsole = -1;
114 #endif
115 int	dcmconsinit;
116 int	dcmdefaultrate = DEFAULT_BAUD_RATE;
117 int	dcmconbrdbusy = 0;
118 int	dcmmajor;
119 extern	struct tty *constty;
120 
121 #ifdef KGDB
122 /*
123  * Kernel GDB support
124  */
125 #include <machine/remote-sl.h>
126 
127 extern dev_t kgdb_dev;
128 extern int kgdb_rate;
129 extern int kgdb_debug_init;
130 #endif
131 
132 /* #define DCMSTATS */
133 
134 #ifdef DEBUG
135 int	dcmdebug = 0x0;
136 #define DDB_SIOERR	0x01
137 #define DDB_PARAM	0x02
138 #define DDB_INPUT	0x04
139 #define DDB_OUTPUT	0x08
140 #define DDB_INTR	0x10
141 #define DDB_IOCTL	0x20
142 #define DDB_INTSCHM	0x40
143 #define DDB_MODEM	0x80
144 #define DDB_OPENCLOSE	0x100
145 #endif
146 
147 #ifdef DCMSTATS
148 #define	DCMRBSIZE	94
149 #define DCMXBSIZE	24
150 
151 struct	dcmstats {
152 	long	xints;		    /* # of xmit ints */
153 	long	xchars;		    /* # of xmit chars */
154 	long	xempty;		    /* times outq is empty in dcmstart */
155 	long	xrestarts;	    /* times completed while xmitting */
156 	long	rints;		    /* # of recv ints */
157 	long	rchars;		    /* # of recv chars */
158 	long	xsilo[DCMXBSIZE+2]; /* times this many chars xmit on one int */
159 	long	rsilo[DCMRBSIZE+2]; /* times this many chars read on one int */
160 } dcmstats[NDCM];
161 #endif
162 
163 #define UNIT(x)		minor(x)
164 #define	BOARD(x)	(((x) >> 2) & 0x3f)
165 #define PORT(x)		((x) & 3)
166 #define MKUNIT(b,p)	(((b) << 2) | (p))
167 
168 /*
169  * Conversion from "HP DCE" to almost-normal DCE: on the 638 8-port mux,
170  * the distribution panel uses "HP DCE" conventions.  If requested via
171  * the device flags, we swap the inputs to something closer to normal DCE,
172  * allowing a straight-through cable to a DTE or a reversed cable
173  * to a DCE (reversing 2-3, 4-5, 8-20 and leaving 6 unconnected;
174  * this gets "DCD" on pin 20 and "CTS" on 4, but doesn't connect
175  * DSR or make RTS work, though).  The following gives the full
176  * details of a cable from this mux panel to a modem:
177  *
178  *		     HP		    modem
179  *		name	pin	pin	name
180  * HP inputs:
181  *		"Rx"	 2	 3	Tx
182  *		CTS	 4	 5	CTS	(only needed for CCTS_OFLOW)
183  *		DCD	20	 8	DCD
184  *		"DSR"	 9	 6	DSR	(unneeded)
185  *		RI	22	22	RI	(unneeded)
186  *
187  * HP outputs:
188  *		"Tx"	 3	 2	Rx
189  *		"DTR"	 6	not connected
190  *		"RTS"	 8	20	DTR
191  *		"SR"	23	 4	RTS	(often not needed)
192  */
193 #define	FLAG_STDDCE	0x10	/* map inputs if this bit is set in flags */
194 #define hp2dce_in(ibits)	(iconv[(ibits) & 0xf])
195 static char iconv[16] = {
196 	0,		MI_DM,		MI_CTS,		MI_CTS|MI_DM,
197 	MI_CD,		MI_CD|MI_DM,	MI_CD|MI_CTS,	MI_CD|MI_CTS|MI_DM,
198 	MI_RI,		MI_RI|MI_DM,	MI_RI|MI_CTS,	MI_RI|MI_CTS|MI_DM,
199 	MI_RI|MI_CD,	MI_RI|MI_CD|MI_DM, MI_RI|MI_CD|MI_CTS,
200 	MI_RI|MI_CD|MI_CTS|MI_DM
201 };
202 
203 dcmprobe(hd)
204 	register struct hp_device *hd;
205 {
206 	register struct dcmdevice *dcm;
207 	register int i;
208 	register int timo = 0;
209 	int s, brd, isconsole, mbits;
210 
211 	dcm = (struct dcmdevice *)hd->hp_addr;
212 	if ((dcm->dcm_rsid & 0x1f) != DCMID)
213 		return (0);
214 	brd = hd->hp_unit;
215 	isconsole = (brd == BOARD(dcmconsole));
216 	/*
217 	 * XXX selected console device (CONSUNIT) as determined by
218 	 * dcmcnprobe does not agree with logical numbering imposed
219 	 * by the config file (i.e. lowest address DCM is not unit
220 	 * CONSUNIT).  Don't recognize this card.
221 	 */
222 	if (isconsole && dcm != dcm_addr[BOARD(dcmconsole)])
223 		return (0);
224 
225 	/*
226 	 * Empirically derived self-test magic
227 	 */
228 	s = spltty();
229 	dcm->dcm_rsid = DCMRS;
230 	DELAY(50000);	/* 5000 is not long enough */
231 	dcm->dcm_rsid = 0;
232 	dcm->dcm_ic = IC_IE;
233 	dcm->dcm_cr = CR_SELFT;
234 	while ((dcm->dcm_ic & IC_IR) == 0)
235 		if (++timo == 20000)
236 			return (0);
237 	DELAY(50000)	/* XXX why is this needed ???? */
238 	while ((dcm->dcm_iir & IIR_SELFT) == 0)
239 		if (++timo == 400000)
240 			return (0);
241 	DELAY(50000)	/* XXX why is this needed ???? */
242 	if (dcm->dcm_stcon != ST_OK) {
243 		if (!isconsole)
244 			printf("dcm%d: self test failed: %x\n",
245 			       brd, dcm->dcm_stcon);
246 		return (0);
247 	}
248 	dcm->dcm_ic = IC_ID;
249 	splx(s);
250 
251 	hd->hp_ipl = DCMIPL(dcm->dcm_ic);
252 	dcm_addr[brd] = dcm;
253 	dcm_active |= 1 << brd;
254 	dcmsoftCAR[brd] = hd->hp_flags;
255 	dcmisr[brd].isr_ipl = hd->hp_ipl;
256 	dcmisr[brd].isr_arg = brd;
257 	dcmisr[brd].isr_intr = dcmintr;
258 	isrlink(&dcmisr[brd]);
259 #ifdef KGDB
260 	if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == brd) {
261 		if (dcmconsole == UNIT(kgdb_dev))
262 			kgdb_dev = NODEV; /* can't debug over console port */
263 #ifndef KGDB_CHEAT
264 		/*
265 		 * The following could potentially be replaced
266 		 * by the corresponding code in dcmcnprobe.
267 		 */
268 		else {
269 			(void) dcminit(kgdb_dev, kgdb_rate);
270 			if (kgdb_debug_init) {
271 				printf("dcm%d: ", UNIT(kgdb_dev));
272 				kgdb_connect(1);
273 			} else
274 				printf("dcm%d: kgdb enabled\n", UNIT(kgdb_dev));
275 		}
276 		/* end could be replaced */
277 #endif
278 	}
279 #endif
280 	if (dcmistype == DIS_TIMER)
281 		dcmsetischeme(brd, DIS_RESET|DIS_TIMER);
282 	else
283 		dcmsetischeme(brd, DIS_RESET|DIS_PERCHAR);
284 
285 	/* load pointers to modem control */
286 	dcm_modem[MKUNIT(brd, 0)] = &dcm->dcm_modem0;
287 	dcm_modem[MKUNIT(brd, 1)] = &dcm->dcm_modem1;
288 	dcm_modem[MKUNIT(brd, 2)] = &dcm->dcm_modem2;
289 	dcm_modem[MKUNIT(brd, 3)] = &dcm->dcm_modem3;
290 	/* set DCD (modem) and CTS (flow control) on all ports */
291 	if (dcmsoftCAR[brd] & FLAG_STDDCE)
292 		mbits = hp2dce_in(MI_CD|MI_CTS);
293 	else
294 		mbits = MI_CD|MI_CTS;
295 	for (i = 0; i < 4; i++)
296 		dcm_modem[MKUNIT(brd, i)]->mdmmsk = mbits;
297 
298 	dcm->dcm_ic = IC_IE;		/* turn all interrupts on */
299 	/*
300 	 * Need to reset baud rate, etc. of next print so reset dcmconsole.
301 	 * Also make sure console is always "hardwired"
302 	 */
303 	if (isconsole) {
304 		dcmconsinit = 0;
305 		dcmsoftCAR[brd] |= (1 << PORT(dcmconsole));
306 	}
307 	return (1);
308 }
309 
310 /* ARGSUSED */
311 #ifdef __STDC__
312 dcmopen(dev_t dev, int flag, int mode, struct proc *p)
313 #else
314 dcmopen(dev, flag, mode, p)
315 	dev_t dev;
316 	int flag, mode;
317 	struct proc *p;
318 #endif
319 {
320 	register struct tty *tp;
321 	register int unit, brd;
322 	int error = 0, mbits;
323 
324 	unit = UNIT(dev);
325 	brd = BOARD(unit);
326 	if (unit >= NDCMLINE || (dcm_active & (1 << brd)) == 0)
327 		return (ENXIO);
328 	tp = &dcm_tty[unit];
329 	tp->t_oproc = dcmstart;
330 	tp->t_param = dcmparam;
331 	tp->t_dev = dev;
332 	if ((tp->t_state & TS_ISOPEN) == 0) {
333 		tp->t_state |= TS_WOPEN;
334 		ttychars(tp);
335 		if (tp->t_ispeed == 0) {
336 			tp->t_iflag = TTYDEF_IFLAG;
337 			tp->t_oflag = TTYDEF_OFLAG;
338 			tp->t_cflag = TTYDEF_CFLAG;
339 			tp->t_lflag = TTYDEF_LFLAG;
340 			tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
341 		}
342 		(void) dcmparam(tp, &tp->t_termios);
343 		ttsetwater(tp);
344 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
345 		return (EBUSY);
346 	mbits = MO_ON;
347 	if (dcmsoftCAR[brd] & FLAG_STDDCE)
348 		mbits |= MO_SR;		/* pin 23, could be used as RTS */
349 	(void) dcmmctl(dev, mbits, DMSET);	/* enable port */
350 	if ((dcmsoftCAR[brd] & (1 << PORT(unit))) ||
351 	    (dcmmctl(dev, MO_OFF, DMGET) & MI_CD))
352 		tp->t_state |= TS_CARR_ON;
353 #ifdef DEBUG
354 	if (dcmdebug & DDB_MODEM)
355 		printf("dcm%d: dcmopen port %d softcarr %c\n",
356 		       brd, unit, (tp->t_state & TS_CARR_ON) ? '1' : '0');
357 #endif
358 	(void) spltty();
359 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
360 	    (tp->t_state & TS_CARR_ON) == 0) {
361 		tp->t_state |= TS_WOPEN;
362 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
363 		    ttopen, 0))
364 			break;
365 	}
366 	(void) spl0();
367 
368 #ifdef DEBUG
369 	if (dcmdebug & DDB_OPENCLOSE)
370 		printf("dcmopen: u %x st %x fl %x\n",
371 			unit, tp->t_state, tp->t_flags);
372 #endif
373 	if (error == 0)
374 		error = (*linesw[tp->t_line].l_open)(dev, tp);
375 	return (error);
376 }
377 
378 /*ARGSUSED*/
379 dcmclose(dev, flag, mode, p)
380 	dev_t dev;
381 	int flag, mode;
382 	struct proc *p;
383 {
384 	register struct tty *tp;
385 	int unit;
386 
387 	unit = UNIT(dev);
388 	tp = &dcm_tty[unit];
389 	(*linesw[tp->t_line].l_close)(tp, flag);
390 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
391 	    (tp->t_state&TS_ISOPEN) == 0)
392 		(void) dcmmctl(dev, MO_OFF, DMSET);
393 #ifdef DEBUG
394 	if (dcmdebug & DDB_OPENCLOSE)
395 		printf("dcmclose: u %x st %x fl %x\n",
396 			unit, tp->t_state, tp->t_flags);
397 #endif
398 	ttyclose(tp);
399 	return (0);
400 }
401 
402 dcmread(dev, uio, flag)
403 	dev_t dev;
404 	struct uio *uio;
405 {
406 	register struct tty *tp;
407 
408 	tp = &dcm_tty[UNIT(dev)];
409 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
410 }
411 
412 dcmwrite(dev, uio, flag)
413 	dev_t dev;
414 	struct uio *uio;
415 {
416 	int unit = UNIT(dev);
417 	register struct tty *tp;
418 
419 	tp = &dcm_tty[unit];
420 	/*
421 	 * XXX we disallow virtual consoles if the physical console is
422 	 * a serial port.  This is in case there is a display attached that
423 	 * is not the console.  In that situation we don't need/want the X
424 	 * server taking over the console.
425 	 */
426 	if (constty && unit == dcmconsole)
427 		constty = NULL;
428 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
429 }
430 
431 dcmintr(brd)
432 	register int brd;
433 {
434 	register struct dcmdevice *dcm = dcm_addr[brd];
435 	register struct dcmischeme *dis;
436 	register int unit = MKUNIT(brd, 0);
437 	register int code, i;
438 	int pcnd[4], mcode, mcnd[4];
439 
440 	/*
441 	 * Do all guarded register accesses right off to minimize
442 	 * block out of hardware.
443 	 */
444 	SEM_LOCK(dcm);
445 	if ((dcm->dcm_ic & IC_IR) == 0) {
446 		SEM_UNLOCK(dcm);
447 		return (0);
448 	}
449 	for (i = 0; i < 4; i++) {
450 		pcnd[i] = dcm->dcm_icrtab[i].dcm_data;
451 		dcm->dcm_icrtab[i].dcm_data = 0;
452 		code = dcm_modem[unit+i]->mdmin;
453 		if (dcmsoftCAR[brd] & FLAG_STDDCE)
454 			code = hp2dce_in(code);
455 		mcnd[i] = code;
456 	}
457 	code = dcm->dcm_iir & IIR_MASK;
458 	dcm->dcm_iir = 0;	/* XXX doc claims read clears interrupt?! */
459 	mcode = dcm->dcm_modemintr;
460 	dcm->dcm_modemintr = 0;
461 	SEM_UNLOCK(dcm);
462 
463 #ifdef DEBUG
464 	if (dcmdebug & DDB_INTR) {
465 		printf("dcmintr(%d): iir %x pc %x/%x/%x/%x ",
466 		       brd, code, pcnd[0], pcnd[1], pcnd[2], pcnd[3]);
467 		printf("miir %x mc %x/%x/%x/%x\n",
468 		       mcode, mcnd[0], mcnd[1], mcnd[2], mcnd[3]);
469 	}
470 #endif
471 	if (code & IIR_TIMEO)
472 		dcmrint(brd, dcm);
473 	if (code & IIR_PORT0)
474 		dcmpint(unit+0, pcnd[0], dcm);
475 	if (code & IIR_PORT1)
476 		dcmpint(unit+1, pcnd[1], dcm);
477 	if (code & IIR_PORT2)
478 		dcmpint(unit+2, pcnd[2], dcm);
479 	if (code & IIR_PORT3)
480 		dcmpint(unit+3, pcnd[3], dcm);
481 	if (code & IIR_MODM) {
482 		if (mcode == 0 || mcode & 0x1)	/* mcode==0 -> 98642 board */
483 			dcmmint(unit+0, mcnd[0], dcm);
484 		if (mcode & 0x2)
485 			dcmmint(unit+1, mcnd[1], dcm);
486 		if (mcode & 0x4)
487 			dcmmint(unit+2, mcnd[2], dcm);
488 		if (mcode & 0x8)
489 			dcmmint(unit+3, mcnd[3], dcm);
490 	}
491 
492 	dis = &dcmischeme[brd];
493 	/*
494 	 * Chalk up a receiver interrupt if the timer running or one of
495 	 * the ports reports a special character interrupt.
496 	 */
497 	if ((code & IIR_TIMEO) ||
498 	    ((pcnd[0]|pcnd[1]|pcnd[2]|pcnd[3]) & IT_SPEC))
499 		dis->dis_intr++;
500 	/*
501 	 * See if it is time to check/change the interrupt rate.
502 	 */
503 	if (dcmistype < 0 &&
504 	    (i = time.tv_sec - dis->dis_time) >= dcminterval) {
505 		/*
506 		 * If currently per-character and averaged over 70 interrupts
507 		 * per-second (66 is threshold of 600 baud) in last interval,
508 		 * switch to timer mode.
509 		 *
510 		 * XXX decay counts ala load average to avoid spikes?
511 		 */
512 		if (dis->dis_perchar && dis->dis_intr > 70 * i)
513 			dcmsetischeme(brd, DIS_TIMER);
514 		/*
515 		 * If currently using timer and had more interrupts than
516 		 * received characters in the last interval, switch back
517 		 * to per-character.  Note that after changing to per-char
518 		 * we must process any characters already in the queue
519 		 * since they may have arrived before the bitmap was setup.
520 		 *
521 		 * XXX decay counts?
522 		 */
523 		else if (!dis->dis_perchar && dis->dis_intr > dis->dis_char) {
524 			dcmsetischeme(brd, DIS_PERCHAR);
525 			dcmrint(brd, dcm);
526 		}
527 		dis->dis_intr = dis->dis_char = 0;
528 		dis->dis_time = time.tv_sec;
529 	}
530 	return (1);
531 }
532 
533 /*
534  *  Port interrupt.  Can be two things:
535  *	First, it might be a special character (exception interrupt);
536  *	Second, it may be a buffer empty (transmit interrupt);
537  */
538 dcmpint(unit, code, dcm)
539 	int unit, code;
540 	struct dcmdevice *dcm;
541 {
542 	struct tty *tp = &dcm_tty[unit];
543 
544 	if (code & IT_SPEC)
545 		dcmreadbuf(unit, dcm, tp);
546 	if (code & IT_TX)
547 		dcmxint(unit, dcm, tp);
548 }
549 
550 dcmrint(brd, dcm)
551 	int brd;
552 	register struct dcmdevice *dcm;
553 {
554 	register int i, unit;
555 	register struct tty *tp;
556 
557 	unit = MKUNIT(brd, 0);
558 	tp = &dcm_tty[unit];
559 	for (i = 0; i < 4; i++, tp++, unit++)
560 		dcmreadbuf(unit, dcm, tp);
561 }
562 
563 dcmreadbuf(unit, dcm, tp)
564 	int unit;
565 	register struct dcmdevice *dcm;
566 	register struct tty *tp;
567 {
568 	int port = PORT(unit);
569 	register struct dcmpreg *pp = dcm_preg(dcm, port);
570 	register struct dcmrfifo *fifo;
571 	register int c, stat;
572 	register unsigned head;
573 	int nch = 0;
574 #ifdef DCMSTATS
575 	struct dcmstats *dsp = &dcmstats[BOARD(unit)];
576 
577 	dsp->rints++;
578 #endif
579 	if ((tp->t_state & TS_ISOPEN) == 0) {
580 #ifdef KGDB
581 		if ((makedev(dcmmajor, unit) == kgdb_dev) &&
582 		    (head = pp->r_head & RX_MASK) != (pp->r_tail & RX_MASK) &&
583 		    dcm->dcm_rfifos[3-port][head>>1].data_char == FRAME_START) {
584 			pp->r_head = (head + 2) & RX_MASK;
585 			kgdb_connect(0);	/* trap into kgdb */
586 			return;
587 		}
588 #endif /* KGDB */
589 		pp->r_head = pp->r_tail & RX_MASK;
590 		return;
591 	}
592 
593 	head = pp->r_head & RX_MASK;
594 	fifo = &dcm->dcm_rfifos[3-port][head>>1];
595 	/*
596 	 * XXX upper bound on how many chars we will take in one swallow?
597 	 */
598 	while (head != (pp->r_tail & RX_MASK)) {
599 		/*
600 		 * Get character/status and update head pointer as fast
601 		 * as possible to make room for more characters.
602 		 */
603 		c = fifo->data_char;
604 		stat = fifo->data_stat;
605 		head = (head + 2) & RX_MASK;
606 		pp->r_head = head;
607 		fifo = head ? fifo+1 : &dcm->dcm_rfifos[3-port][0];
608 		nch++;
609 
610 #ifdef DEBUG
611 		if (dcmdebug & DDB_INPUT)
612 			printf("dcmreadbuf(%d): c%x('%c') s%x f%x h%x t%x\n",
613 			       unit, c&0xFF, c, stat&0xFF,
614 			       tp->t_flags, head, pp->r_tail);
615 #endif
616 		/*
617 		 * Check for and handle errors
618 		 */
619 		if (stat & RD_MASK) {
620 #ifdef DEBUG
621 			if (dcmdebug & (DDB_INPUT|DDB_SIOERR))
622 				printf("dcmreadbuf(%d): err: c%x('%c') s%x\n",
623 				       unit, stat, c&0xFF, c);
624 #endif
625 			if (stat & (RD_BD | RD_FE))
626 				c |= TTY_FE;
627 			else if (stat & RD_PE)
628 				c |= TTY_PE;
629 			else if (stat & RD_OVF)
630 				log(LOG_WARNING,
631 				    "dcm%d: silo overflow\n", unit);
632 			else if (stat & RD_OE)
633 				log(LOG_WARNING,
634 				    "dcm%d: uart overflow\n", unit);
635 		}
636 		(*linesw[tp->t_line].l_rint)(c, tp);
637 	}
638 	dcmischeme[BOARD(unit)].dis_char += nch;
639 #ifdef DCMSTATS
640 	dsp->rchars += nch;
641 	if (nch <= DCMRBSIZE)
642 		dsp->rsilo[nch]++;
643 	else
644 		dsp->rsilo[DCMRBSIZE+1]++;
645 #endif
646 }
647 
648 dcmxint(unit, dcm, tp)
649 	int unit;
650 	struct dcmdevice *dcm;
651 	register struct tty *tp;
652 {
653 	tp->t_state &= ~TS_BUSY;
654 	if (tp->t_state & TS_FLUSH)
655 		tp->t_state &= ~TS_FLUSH;
656 	(*linesw[tp->t_line].l_start)(tp);
657 }
658 
659 dcmmint(unit, mcnd, dcm)
660 	register int unit;
661 	register struct dcmdevice *dcm;
662         int mcnd;
663 {
664 	register struct tty *tp;
665 	int delta;
666 
667 #ifdef DEBUG
668 	if (dcmdebug & DDB_MODEM)
669 		printf("dcmmint: port %d mcnd %x mcndlast %x\n",
670 		       unit, mcnd, mcndlast[unit]);
671 #endif
672 	tp = &dcm_tty[unit];
673 	delta = mcnd ^ mcndlast[unit];
674 	mcndlast[unit] = mcnd;
675 	if ((delta & MI_CTS) && (tp->t_state & TS_ISOPEN) &&
676 	    (tp->t_flags & CCTS_OFLOW)) {
677 		if (mcnd & MI_CTS) {
678 			tp->t_state &= ~TS_TTSTOP;
679 			ttstart(tp);
680 		} else
681 			tp->t_state |= TS_TTSTOP;	/* inline dcmstop */
682 	}
683 	if (delta & MI_CD) {
684 		if (mcnd & MI_CD)
685 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
686 		else if ((dcmsoftCAR[BOARD(unit)] & (1 << PORT(unit))) == 0 &&
687 		    (*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
688 			dcm_modem[unit]->mdmout = MO_OFF;
689 			SEM_LOCK(dcm);
690 			dcm->dcm_modemchng |= 1<<(unit & 3);
691 			dcm->dcm_cr |= CR_MODM;
692 			SEM_UNLOCK(dcm);
693 			DELAY(10); /* time to change lines */
694 		}
695 	}
696 }
697 
698 dcmioctl(dev, cmd, data, flag, p)
699 	dev_t dev;
700 	int cmd;
701 	caddr_t data;
702 	int flag;
703 	struct proc *p;
704 {
705 	register struct tty *tp;
706 	register int unit = UNIT(dev);
707 	register struct dcmdevice *dcm;
708 	register int port;
709 	int error, s;
710 
711 #ifdef DEBUG
712 	if (dcmdebug & DDB_IOCTL)
713 		printf("dcmioctl: unit %d cmd %x data %x flag %x\n",
714 		       unit, cmd, *data, flag);
715 #endif
716 	tp = &dcm_tty[unit];
717 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
718 	if (error >= 0)
719 		return (error);
720 	error = ttioctl(tp, cmd, data, flag);
721 	if (error >= 0)
722 		return (error);
723 
724 	port = PORT(unit);
725 	dcm = dcm_addr[BOARD(unit)];
726 	switch (cmd) {
727 	case TIOCSBRK:
728 		/*
729 		 * Wait for transmitter buffer to empty
730 		 */
731 		s = spltty();
732 		while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
733 			DELAY(DCM_USPERCH(tp->t_ospeed));
734 		SEM_LOCK(dcm);
735 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
736 		dcm->dcm_cr |= (1 << port);	/* start break */
737 		SEM_UNLOCK(dcm);
738 		splx(s);
739 		break;
740 
741 	case TIOCCBRK:
742 		SEM_LOCK(dcm);
743 		dcm->dcm_cmdtab[port].dcm_data |= CT_BRK;
744 		dcm->dcm_cr |= (1 << port);	/* end break */
745 		SEM_UNLOCK(dcm);
746 		break;
747 
748 	case TIOCSDTR:
749 		(void) dcmmctl(dev, MO_ON, DMBIS);
750 		break;
751 
752 	case TIOCCDTR:
753 		(void) dcmmctl(dev, MO_ON, DMBIC);
754 		break;
755 
756 	case TIOCMSET:
757 		(void) dcmmctl(dev, *(int *)data, DMSET);
758 		break;
759 
760 	case TIOCMBIS:
761 		(void) dcmmctl(dev, *(int *)data, DMBIS);
762 		break;
763 
764 	case TIOCMBIC:
765 		(void) dcmmctl(dev, *(int *)data, DMBIC);
766 		break;
767 
768 	case TIOCMGET:
769 		*(int *)data = dcmmctl(dev, 0, DMGET);
770 		break;
771 
772 	default:
773 		return (ENOTTY);
774 	}
775 	return (0);
776 }
777 
778 dcmparam(tp, t)
779 	register struct tty *tp;
780 	register struct termios *t;
781 {
782 	register struct dcmdevice *dcm;
783 	register int port, mode, cflag = t->c_cflag;
784 	int ospeed = ttspeedtab(t->c_ospeed, dcmspeedtab);
785 
786 	/* check requested parameters */
787         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
788                 return (EINVAL);
789         /* and copy to tty */
790         tp->t_ispeed = t->c_ispeed;
791         tp->t_ospeed = t->c_ospeed;
792         tp->t_cflag = cflag;
793 	if (ospeed == 0) {
794 		(void) dcmmctl(UNIT(tp->t_dev), MO_OFF, DMSET);
795 		return (0);
796 	}
797 
798 	mode = 0;
799 	switch (cflag&CSIZE) {
800 	case CS5:
801 		mode = LC_5BITS; break;
802 	case CS6:
803 		mode = LC_6BITS; break;
804 	case CS7:
805 		mode = LC_7BITS; break;
806 	case CS8:
807 		mode = LC_8BITS; break;
808 	}
809 	if (cflag&PARENB) {
810 		if (cflag&PARODD)
811 			mode |= LC_PODD;
812 		else
813 			mode |= LC_PEVEN;
814 	}
815 	if (cflag&CSTOPB)
816 		mode |= LC_2STOP;
817 	else
818 		mode |= LC_1STOP;
819 #ifdef DEBUG
820 	if (dcmdebug & DDB_PARAM)
821 		printf("dcmparam(%d): cflag %x mode %x speed %d uperch %d\n",
822 		       UNIT(tp->t_dev), cflag, mode, tp->t_ospeed,
823 		       DCM_USPERCH(tp->t_ospeed));
824 #endif
825 
826 	port = PORT(tp->t_dev);
827 	dcm = dcm_addr[BOARD(tp->t_dev)];
828 	/*
829 	 * Wait for transmitter buffer to empty.
830 	 */
831 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
832 		DELAY(DCM_USPERCH(tp->t_ospeed));
833 	/*
834 	 * Make changes known to hardware.
835 	 */
836 	dcm->dcm_data[port].dcm_baud = ospeed;
837 	dcm->dcm_data[port].dcm_conf = mode;
838 	SEM_LOCK(dcm);
839 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
840 	dcm->dcm_cr |= (1 << port);
841 	SEM_UNLOCK(dcm);
842 	/*
843 	 * Delay for config change to take place. Weighted by baud.
844 	 * XXX why do we do this?
845 	 */
846 	DELAY(16 * DCM_USPERCH(tp->t_ospeed));
847 	return (0);
848 }
849 
850 void
851 dcmstart(tp)
852 	register struct tty *tp;
853 {
854 	register struct dcmdevice *dcm;
855 	register struct dcmpreg *pp;
856 	register struct dcmtfifo *fifo;
857 	register char *bp;
858 	register unsigned tail, next;
859 	register int port, nch;
860 	unsigned head;
861 	char buf[16];
862 	int s;
863 #ifdef DCMSTATS
864 	struct dcmstats *dsp = &dcmstats[BOARD(tp->t_dev)];
865 	int tch = 0;
866 #endif
867 
868 	s = spltty();
869 #ifdef DCMSTATS
870 	dsp->xints++;
871 #endif
872 #ifdef DEBUG
873 	if (dcmdebug & DDB_OUTPUT)
874 		printf("dcmstart(%d): state %x flags %x outcc %d\n",
875 		       UNIT(tp->t_dev), tp->t_state, tp->t_flags,
876 		       tp->t_outq.c_cc);
877 #endif
878 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
879 		goto out;
880 	if (tp->t_outq.c_cc <= tp->t_lowat) {
881 		if (tp->t_state&TS_ASLEEP) {
882 			tp->t_state &= ~TS_ASLEEP;
883 			wakeup((caddr_t)&tp->t_outq);
884 		}
885 		selwakeup(&tp->t_wsel);
886 	}
887 	if (tp->t_outq.c_cc == 0) {
888 #ifdef DCMSTATS
889 		dsp->xempty++;
890 #endif
891 		goto out;
892 	}
893 
894 	dcm = dcm_addr[BOARD(tp->t_dev)];
895 	port = PORT(tp->t_dev);
896 	pp = dcm_preg(dcm, port);
897 	tail = pp->t_tail & TX_MASK;
898 	next = (tail + 1) & TX_MASK;
899 	head = pp->t_head & TX_MASK;
900 	if (head == next)
901 		goto out;
902 	fifo = &dcm->dcm_tfifos[3-port][tail];
903 again:
904 	nch = q_to_b(&tp->t_outq, buf, (head - next) & TX_MASK);
905 #ifdef DCMSTATS
906 	tch += nch;
907 #endif
908 #ifdef DEBUG
909 	if (dcmdebug & DDB_OUTPUT)
910 		printf("\thead %x tail %x nch %d\n", head, tail, nch);
911 #endif
912 	/*
913 	 * Loop transmitting all the characters we can.
914 	 */
915 	for (bp = buf; --nch >= 0; bp++) {
916 		fifo->data_char = *bp;
917 		pp->t_tail = next;
918 		/*
919 		 * If this is the first character,
920 		 * get the hardware moving right now.
921 		 */
922 		if (bp == buf) {
923 			tp->t_state |= TS_BUSY;
924 			SEM_LOCK(dcm);
925 			dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
926 			dcm->dcm_cr |= (1 << port);
927 			SEM_UNLOCK(dcm);
928 		}
929 		tail = next;
930 		fifo = tail ? fifo+1 : &dcm->dcm_tfifos[3-port][0];
931 		next = (next + 1) & TX_MASK;
932 	}
933 	/*
934 	 * Head changed while we were loading the buffer,
935 	 * go back and load some more if we can.
936 	 */
937 	if (tp->t_outq.c_cc && head != (pp->t_head & TX_MASK)) {
938 #ifdef DCMSTATS
939 		dsp->xrestarts++;
940 #endif
941 		head = pp->t_head & TX_MASK;
942 		goto again;
943 	}
944 
945 	/*
946 	 * Kick it one last time in case it finished while we were
947 	 * loading the last bunch.
948 	 */
949 	if (bp > &buf[1]) {
950 		tp->t_state |= TS_BUSY;
951 		SEM_LOCK(dcm);
952 		dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
953 		dcm->dcm_cr |= (1 << port);
954 		SEM_UNLOCK(dcm);
955 	}
956 #ifdef DEBUG
957 	if (dcmdebug & DDB_INTR)
958 		printf("dcmstart(%d): head %x tail %x outqcc %d\n",
959 		       UNIT(tp->t_dev), head, tail, tp->t_outq.c_cc);
960 #endif
961 out:
962 #ifdef DCMSTATS
963 	dsp->xchars += tch;
964 	if (tch <= DCMXBSIZE)
965 		dsp->xsilo[tch]++;
966 	else
967 		dsp->xsilo[DCMXBSIZE+1]++;
968 #endif
969 	splx(s);
970 }
971 
972 /*
973  * Stop output on a line.
974  */
975 dcmstop(tp, flag)
976 	register struct tty *tp;
977 {
978 	int s;
979 
980 	s = spltty();
981 	if (tp->t_state & TS_BUSY) {
982 		/* XXX is there some way to safely stop transmission? */
983 		if ((tp->t_state&TS_TTSTOP) == 0)
984 			tp->t_state |= TS_FLUSH;
985 	}
986 	splx(s);
987 }
988 
989 /*
990  * Modem control
991  */
992 dcmmctl(dev, bits, how)
993 	dev_t dev;
994 	int bits, how;
995 {
996 	register struct dcmdevice *dcm;
997 	int s, unit, brd, hit = 0;
998 
999 	unit = UNIT(dev);
1000 #ifdef DEBUG
1001 	if (dcmdebug & DDB_MODEM)
1002 		printf("dcmmctl(%d) unit %d  bits 0x%x how %x\n",
1003 		       BOARD(unit), unit, bits, how);
1004 #endif
1005 
1006 	brd = BOARD(unit);
1007 	dcm = dcm_addr[brd];
1008 	s = spltty();
1009 	switch (how) {
1010 
1011 	case DMSET:
1012 		dcm_modem[unit]->mdmout = bits;
1013 		hit++;
1014 		break;
1015 
1016 	case DMBIS:
1017 		dcm_modem[unit]->mdmout |= bits;
1018 		hit++;
1019 		break;
1020 
1021 	case DMBIC:
1022 		dcm_modem[unit]->mdmout &= ~bits;
1023 		hit++;
1024 		break;
1025 
1026 	case DMGET:
1027 		bits = dcm_modem[unit]->mdmin;
1028 		if (dcmsoftCAR[brd] & FLAG_STDDCE)
1029 			bits = hp2dce_in(bits);
1030 		break;
1031 	}
1032 	if (hit) {
1033 		SEM_LOCK(dcm);
1034 		dcm->dcm_modemchng |= 1<<(unit & 3);
1035 		dcm->dcm_cr |= CR_MODM;
1036 		SEM_UNLOCK(dcm);
1037 		DELAY(10); /* delay until done */
1038 		(void) splx(s);
1039 	}
1040 	return (bits);
1041 }
1042 
1043 /*
1044  * Set board to either interrupt per-character or at a fixed interval.
1045  */
1046 dcmsetischeme(brd, flags)
1047 	int brd, flags;
1048 {
1049 	register struct dcmdevice *dcm = dcm_addr[brd];
1050 	register struct dcmischeme *dis = &dcmischeme[brd];
1051 	register int i;
1052 	u_char mask;
1053 	int perchar = flags & DIS_PERCHAR;
1054 
1055 #ifdef DEBUG
1056 	if (dcmdebug & DDB_INTSCHM)
1057 		printf("dcmsetischeme(%d, %d): cur %d, ints %d, chars %d\n",
1058 		       brd, perchar, dis->dis_perchar,
1059 		       dis->dis_intr, dis->dis_char);
1060 	if ((flags & DIS_RESET) == 0 && perchar == dis->dis_perchar) {
1061 		printf("dcmsetischeme(%d):  redundent request %d\n",
1062 		       brd, perchar);
1063 		return;
1064 	}
1065 #endif
1066 	/*
1067 	 * If perchar is non-zero, we enable interrupts on all characters
1068 	 * otherwise we disable perchar interrupts and use periodic
1069 	 * polling interrupts.
1070 	 */
1071 	dis->dis_perchar = perchar;
1072 	mask = perchar ? 0xf : 0x0;
1073 	for (i = 0; i < 256; i++)
1074 		dcm->dcm_bmap[i].data_data = mask;
1075 	/*
1076 	 * Don't slow down tandem mode, interrupt on flow control
1077 	 * chars for any port on the board.
1078 	 */
1079 	if (!perchar) {
1080 		register struct tty *tp = &dcm_tty[MKUNIT(brd, 0)];
1081 		int c;
1082 
1083 		for (i = 0; i < 4; i++, tp++) {
1084 			if ((c = tp->t_cc[VSTART]) != _POSIX_VDISABLE)
1085 				dcm->dcm_bmap[c].data_data |= (1 << i);
1086 			if ((c = tp->t_cc[VSTOP]) != _POSIX_VDISABLE)
1087 				dcm->dcm_bmap[c].data_data |= (1 << i);
1088 		}
1089 	}
1090 	/*
1091 	 * Board starts with timer disabled so if first call is to
1092 	 * set perchar mode then we don't want to toggle the timer.
1093 	 */
1094 	if (flags == (DIS_RESET|DIS_PERCHAR))
1095 		return;
1096 	/*
1097 	 * Toggle card 16.7ms interrupts (we first make sure that card
1098 	 * has cleared the bit so it will see the toggle).
1099 	 */
1100 	while (dcm->dcm_cr & CR_TIMER)
1101 		;
1102 	SEM_LOCK(dcm);
1103 	dcm->dcm_cr |= CR_TIMER;
1104 	SEM_UNLOCK(dcm);
1105 }
1106 
1107 /*
1108  * Following are all routines needed for DCM to act as console
1109  */
1110 #include <hp/dev/cons.h>
1111 
1112 dcmcnprobe(cp)
1113 	struct consdev *cp;
1114 {
1115 	register struct hp_hw *hw;
1116 	int unit;
1117 
1118 	/* locate the major number */
1119 	for (dcmmajor = 0; dcmmajor < nchrdev; dcmmajor++)
1120 		if (cdevsw[dcmmajor].d_open == dcmopen)
1121 			break;
1122 
1123 	/*
1124 	 * Implicitly assigns the lowest select code DCM card found to be
1125 	 * logical unit 0 (actually CONUNIT).  If your config file does
1126 	 * anything different, you're screwed.
1127 	 */
1128 	for (hw = sc_table; hw->hw_type; hw++)
1129 		if (HW_ISDEV(hw, D_COMMDCM) && !badaddr((short *)hw->hw_kva))
1130 			break;
1131 	if (!HW_ISDEV(hw, D_COMMDCM)) {
1132 		cp->cn_pri = CN_DEAD;
1133 		return;
1134 	}
1135 	unit = CONUNIT;
1136 	dcm_addr[BOARD(CONUNIT)] = (struct dcmdevice *)hw->hw_kva;
1137 
1138 	/* initialize required fields */
1139 	cp->cn_dev = makedev(dcmmajor, unit);
1140 	cp->cn_tp = &dcm_tty[unit];
1141 	switch (dcm_addr[BOARD(unit)]->dcm_rsid) {
1142 	case DCMID:
1143 		cp->cn_pri = CN_NORMAL;
1144 		break;
1145 	case DCMID|DCMCON:
1146 		cp->cn_pri = CN_REMOTE;
1147 		break;
1148 	default:
1149 		cp->cn_pri = CN_DEAD;
1150 		return;
1151 	}
1152 	/*
1153 	 * If dcmconsole is initialized, raise our priority.
1154 	 */
1155 	if (dcmconsole == UNIT(unit))
1156 		cp->cn_pri = CN_REMOTE;
1157 #ifdef KGDB_CHEAT
1158 	/*
1159 	 * This doesn't currently work, at least not with ite consoles;
1160 	 * the console hasn't been initialized yet.
1161 	 */
1162 	if (major(kgdb_dev) == dcmmajor && BOARD(kgdb_dev) == BOARD(unit)) {
1163 		(void) dcminit(kgdb_dev, kgdb_rate);
1164 		if (kgdb_debug_init) {
1165 			/*
1166 			 * We assume that console is ready for us...
1167 			 * this assumes that a dca or ite console
1168 			 * has been selected already and will init
1169 			 * on the first putc.
1170 			 */
1171 			printf("dcm%d: ", UNIT(kgdb_dev));
1172 			kgdb_connect(1);
1173 		}
1174 	}
1175 #endif
1176 }
1177 
1178 dcmcninit(cp)
1179 	struct consdev *cp;
1180 {
1181 	dcminit(cp->cn_dev, dcmdefaultrate);
1182 	dcmconsinit = 1;
1183 	dcmconsole = UNIT(cp->cn_dev);
1184 }
1185 
1186 dcminit(dev, rate)
1187 	dev_t dev;
1188 	int rate;
1189 {
1190 	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1191 	int s, mode, port;
1192 
1193 	port = PORT(dev);
1194 	mode = LC_8BITS | LC_1STOP;
1195 	s = splhigh();
1196 	/*
1197 	 * Wait for transmitter buffer to empty.
1198 	 */
1199 	while (dcm->dcm_thead[port].ptr != dcm->dcm_ttail[port].ptr)
1200 		DELAY(DCM_USPERCH(rate));
1201 	/*
1202 	 * Make changes known to hardware.
1203 	 */
1204 	dcm->dcm_data[port].dcm_baud = ttspeedtab(rate, dcmspeedtab);
1205 	dcm->dcm_data[port].dcm_conf = mode;
1206 	SEM_LOCK(dcm);
1207 	dcm->dcm_cmdtab[port].dcm_data |= CT_CON;
1208 	dcm->dcm_cr |= (1 << port);
1209 	SEM_UNLOCK(dcm);
1210 	/*
1211 	 * Delay for config change to take place. Weighted by baud.
1212 	 * XXX why do we do this?
1213 	 */
1214 	DELAY(16 * DCM_USPERCH(rate));
1215 	splx(s);
1216 }
1217 
1218 dcmcngetc(dev)
1219 	dev_t dev;
1220 {
1221 	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1222 	register struct dcmrfifo *fifo;
1223 	register struct dcmpreg *pp;
1224 	register unsigned head;
1225 	int s, c, stat, port;
1226 
1227 	port = PORT(dev);
1228 	pp = dcm_preg(dcm, port);
1229 	s = splhigh();
1230 	head = pp->r_head & RX_MASK;
1231 	fifo = &dcm->dcm_rfifos[3-port][head>>1];
1232 	while (head == (pp->r_tail & RX_MASK))
1233 		;
1234 	/*
1235 	 * If board interrupts are enabled, just let our received char
1236 	 * interrupt through in case some other port on the board was
1237 	 * busy.  Otherwise we must clear the interrupt.
1238 	 */
1239 	SEM_LOCK(dcm);
1240 	if ((dcm->dcm_ic & IC_IE) == 0)
1241 		stat = dcm->dcm_iir;
1242 	SEM_UNLOCK(dcm);
1243 	c = fifo->data_char;
1244 	stat = fifo->data_stat;
1245 	pp->r_head = (head + 2) & RX_MASK;
1246 	splx(s);
1247 	return (c);
1248 }
1249 
1250 /*
1251  * Console kernel output character routine.
1252  */
1253 dcmcnputc(dev, c)
1254 	dev_t dev;
1255 	int c;
1256 {
1257 	register struct dcmdevice *dcm = dcm_addr[BOARD(dev)];
1258 	register struct dcmpreg *pp;
1259 	unsigned tail;
1260 	int s, port, stat;
1261 
1262 	port = PORT(dev);
1263 	pp = dcm_preg(dcm, port);
1264 	s = splhigh();
1265 #ifdef KGDB
1266 	if (dev != kgdb_dev)
1267 #endif
1268 	if (dcmconsinit == 0) {
1269 		(void) dcminit(dev, dcmdefaultrate);
1270 		dcmconsinit = 1;
1271 	}
1272 	tail = pp->t_tail & TX_MASK;
1273 	while (tail != (pp->t_head & TX_MASK))
1274 		;
1275 	dcm->dcm_tfifos[3-port][tail].data_char = c;
1276 	pp->t_tail = tail = (tail + 1) & TX_MASK;
1277 	SEM_LOCK(dcm);
1278 	dcm->dcm_cmdtab[port].dcm_data |= CT_TX;
1279 	dcm->dcm_cr |= (1 << port);
1280 	SEM_UNLOCK(dcm);
1281 	while (tail != (pp->t_head & TX_MASK))
1282 		;
1283 	/*
1284 	 * If board interrupts are enabled, just let our completion
1285 	 * interrupt through in case some other port on the board
1286 	 * was busy.  Otherwise we must clear the interrupt.
1287 	 */
1288 	if ((dcm->dcm_ic & IC_IE) == 0) {
1289 		SEM_LOCK(dcm);
1290 		stat = dcm->dcm_iir;
1291 		SEM_UNLOCK(dcm);
1292 	}
1293 	splx(s);
1294 }
1295 #endif
1296