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