xref: /original-bsd/sys/hp/dev/dca.c (revision 8fbb78b3)
1 /*
2  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)dca.c	7.11 (Berkeley) 05/16/91
8  */
9 
10 #include "dca.h"
11 #if NDCA > 0
12 /*
13  *  98626/98644/internal serial interface
14  *  uses National Semiconductor INS8250/NS16550AF UART
15  */
16 #include "sys/param.h"
17 #include "sys/systm.h"
18 #include "sys/ioctl.h"
19 #include "sys/tty.h"
20 #include "sys/proc.h"
21 #include "sys/conf.h"
22 #include "sys/file.h"
23 #include "sys/uio.h"
24 #include "sys/kernel.h"
25 #include "sys/syslog.h"
26 
27 #include "device.h"
28 #include "dcareg.h"
29 #include "machine/cpu.h"
30 #include "../hp300/isr.h"
31 
32 int	dcaprobe();
33 struct	driver dcadriver = {
34 	dcaprobe, "dca",
35 };
36 
37 int	dcastart(), dcaparam(), dcaintr();
38 int	dcasoftCAR;
39 int	dca_active;
40 int	dca_hasfifo;
41 int	ndca = NDCA;
42 #ifdef DCACONSOLE
43 int	dcaconsole = DCACONSOLE;
44 #else
45 int	dcaconsole = -1;
46 #endif
47 int	dcaconsinit;
48 int	dcadefaultrate = TTYDEF_SPEED;
49 int	dcamajor;
50 struct	dcadevice *dca_addr[NDCA];
51 struct	tty dca_tty[NDCA];
52 struct	isr dcaisr[NDCA];
53 
54 struct speedtab dcaspeedtab[] = {
55 	0,	0,
56 	50,	DCABRD(50),
57 	75,	DCABRD(75),
58 	110,	DCABRD(110),
59 	134,	DCABRD(134),
60 	150,	DCABRD(150),
61 	200,	DCABRD(200),
62 	300,	DCABRD(300),
63 	600,	DCABRD(600),
64 	1200,	DCABRD(1200),
65 	1800,	DCABRD(1800),
66 	2400,	DCABRD(2400),
67 	4800,	DCABRD(4800),
68 	9600,	DCABRD(9600),
69 	19200,	DCABRD(19200),
70 	38400,	DCABRD(38400),
71 	-1,	-1
72 };
73 
74 extern	struct tty *constty;
75 #ifdef KGDB
76 #include "machine/remote-sl.h"
77 
78 extern int kgdb_dev;
79 extern int kgdb_rate;
80 extern int kgdb_debug_init;
81 #endif
82 
83 #define	UNIT(x)		minor(x)
84 
85 #ifdef DEBUG
86 long	fifoin[17];
87 long	fifoout[17];
88 long	dcaintrcount[16];
89 long	dcamintcount[16];
90 #endif
91 
92 dcaprobe(hd)
93 	register struct hp_device *hd;
94 {
95 	register struct dcadevice *dca;
96 	register int unit;
97 
98 	dca = (struct dcadevice *)hd->hp_addr;
99 	if (dca->dca_irid != DCAID0 &&
100 	    dca->dca_irid != DCAREMID0 &&
101 	    dca->dca_irid != DCAID1 &&
102 	    dca->dca_irid != DCAREMID1)
103 		return (0);
104 	unit = hd->hp_unit;
105 	if (unit == dcaconsole)
106 		DELAY(100000);
107 	dca->dca_irid = 0xFF;
108 	DELAY(100);
109 
110 	/* look for a NS 16550AF UART with FIFOs */
111 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
112 	DELAY(100);
113 	if ((dca->dca_iir & IIR_FIFO_MASK) == IIR_FIFO_MASK)
114 		dca_hasfifo |= 1 << unit;
115 
116 	hd->hp_ipl = DCAIPL(dca->dca_ic);
117 	dcaisr[unit].isr_ipl = hd->hp_ipl;
118 	dcaisr[unit].isr_arg = unit;
119 	dcaisr[unit].isr_intr = dcaintr;
120 	dca_addr[unit] = dca;
121 	dca_active |= 1 << unit;
122 	dcasoftCAR = hd->hp_flags;
123 	isrlink(&dcaisr[unit]);
124 #ifdef KGDB
125 	if (kgdb_dev == makedev(dcamajor, unit)) {
126 		if (dcaconsole == unit)
127 			kgdb_dev = -1;	/* can't debug over console port */
128 		else {
129 			(void) dcainit(unit, kgdb_rate);
130 			if (kgdb_debug_init) {
131 				/*
132 				 * Print prefix of device name,
133 				 * let kgdb_connect print the rest.
134 				 */
135 				printf("dca%d: ", unit);
136 				kgdb_connect(1);
137 			} else
138 				printf("dca%d: kgdb enabled\n", unit);
139 		}
140 	}
141 #endif
142 	dca->dca_ic = IC_IE;
143 	/*
144 	 * Need to reset baud rate, etc. of next print so reset dcaconsinit.
145 	 * Also make sure console is always "hardwired."
146 	 */
147 	if (unit == dcaconsole) {
148 		dcaconsinit = 0;
149 		dcasoftCAR |= (1 << unit);
150 	}
151 	return (1);
152 }
153 
154 /* ARGSUSED */
155 #ifdef __STDC__
156 dcaopen(dev_t dev, int flag, int mode, struct proc *p)
157 #else
158 dcaopen(dev, flag, mode, p)
159 	dev_t dev;
160 	int flag, mode;
161 	struct proc *p;
162 #endif
163 {
164 	register struct tty *tp;
165 	register int unit;
166 	int error = 0;
167 
168 	unit = UNIT(dev);
169 	if (unit >= NDCA || (dca_active & (1 << unit)) == 0)
170 		return (ENXIO);
171 	tp = &dca_tty[unit];
172 	tp->t_oproc = dcastart;
173 	tp->t_param = dcaparam;
174 	tp->t_dev = dev;
175 	if ((tp->t_state & TS_ISOPEN) == 0) {
176 		tp->t_state |= TS_WOPEN;
177 		ttychars(tp);
178 		if (tp->t_ispeed == 0) {
179 			tp->t_iflag = TTYDEF_IFLAG;
180 			tp->t_oflag = TTYDEF_OFLAG;
181 			tp->t_cflag = TTYDEF_CFLAG;
182 			tp->t_lflag = TTYDEF_LFLAG;
183 			tp->t_ispeed = tp->t_ospeed = dcadefaultrate;
184 		}
185 		dcaparam(tp, &tp->t_termios);
186 		ttsetwater(tp);
187 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
188 		return (EBUSY);
189 	(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMSET);
190 	if ((dcasoftCAR & (1 << unit)) || (dcamctl(dev, 0, DMGET) & MSR_DCD))
191 		tp->t_state |= TS_CARR_ON;
192 	(void) spltty();
193 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
194 	       (tp->t_state & TS_CARR_ON) == 0) {
195 		tp->t_state |= TS_WOPEN;
196 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
197 		    ttopen, 0))
198 			break;
199 	}
200 	(void) spl0();
201 	if (error == 0)
202 		error = (*linesw[tp->t_line].l_open)(dev, tp);
203 	return (error);
204 }
205 
206 /*ARGSUSED*/
207 dcaclose(dev, flag, mode, p)
208 	dev_t dev;
209 	int flag, mode;
210 	struct proc *p;
211 {
212 	register struct tty *tp;
213 	register struct dcadevice *dca;
214 	register int unit;
215 
216 	unit = UNIT(dev);
217 	dca = dca_addr[unit];
218 	tp = &dca_tty[unit];
219 	(*linesw[tp->t_line].l_close)(tp, flag);
220 	dca->dca_cfcr &= ~CFCR_SBREAK;
221 #ifdef KGDB
222 	/* do not disable interrupts if debugging */
223 	if (dev != kgdb_dev)
224 #endif
225 	dca->dca_ier = 0;
226 	(void) dcamctl(dev, 0, DMSET);
227 	if (tp->t_state & TS_HUPCLS)
228 		(*linesw[tp->t_line].l_modem)(tp, 0);
229 	ttyclose(tp);
230 	return(0);
231 }
232 
233 dcaread(dev, uio, flag)
234 	dev_t dev;
235 	struct uio *uio;
236 {
237 	register struct tty *tp = &dca_tty[UNIT(dev)];
238 
239 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
240 }
241 
242 dcawrite(dev, uio, flag)
243 	dev_t dev;
244 	struct uio *uio;
245 {
246 	int unit = UNIT(dev);
247 	register struct tty *tp = &dca_tty[unit];
248 
249 	/*
250 	 * (XXX) We disallow virtual consoles if the physical console is
251 	 * a serial port.  This is in case there is a display attached that
252 	 * is not the console.  In that situation we don't need/want the X
253 	 * server taking over the console.
254 	 */
255 	if (constty && unit == dcaconsole)
256 		constty = NULL;
257 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
258 }
259 
260 dcaintr(unit)
261 	register int unit;
262 {
263 	register struct dcadevice *dca;
264 	register u_char code;
265 	register struct tty *tp;
266 
267 	dca = dca_addr[unit];
268 	if ((dca->dca_ic & IC_IR) == 0)
269 		return(0);
270 	while (1) {
271 		code = dca->dca_iir;
272 #ifdef DEBUG
273 		dcaintrcount[code & IIR_IMASK]++;
274 #endif
275 		switch (code & IIR_IMASK) {
276 		case IIR_NOPEND:
277 			return (1);
278 		case IIR_RXTOUT:
279 		case IIR_RXRDY:
280 			/* do time-critical read in-line */
281 			tp = &dca_tty[unit];
282 /*
283  * Process a received byte.  Inline for speed...
284  */
285 #ifdef KGDB
286 #define	RCVBYTE() \
287 			code = dca->dca_data; \
288 			if ((tp->t_state & TS_ISOPEN) == 0) { \
289 				if (kgdb_dev == makedev(dcamajor, unit) && \
290 				    code == FRAME_END) \
291 					kgdb_connect(0); /* trap into kgdb */ \
292 			} else \
293 				(*linesw[tp->t_line].l_rint)(code, tp)
294 #else
295 #define	RCVBYTE() \
296 			code = dca->dca_data; \
297 			if ((tp->t_state & TS_ISOPEN) != 0) \
298 				(*linesw[tp->t_line].l_rint)(code, tp)
299 #endif
300 			RCVBYTE();
301 			if (dca_hasfifo & (1 << unit)) {
302 #ifdef DEBUG
303 				register int fifocnt = 1;
304 #endif
305 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
306 					if (code == LSR_RXRDY) {
307 						RCVBYTE();
308 					} else
309 						dcaeint(unit, code, dca);
310 #ifdef DEBUG
311 					fifocnt++;
312 #endif
313 				}
314 #ifdef DEBUG
315 				if (fifocnt > 16)
316 					fifoin[0]++;
317 				else
318 					fifoin[fifocnt]++;
319 #endif
320 			}
321 			break;
322 		case IIR_TXRDY:
323 			tp = &dca_tty[unit];
324 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
325 			if (tp->t_line)
326 				(*linesw[tp->t_line].l_start)(tp);
327 			else
328 				dcastart(tp);
329 			break;
330 		case IIR_RLS:
331 			dcaeint(unit, dca->dca_lsr, dca);
332 			break;
333 		default:
334 			if (code & IIR_NOPEND)
335 				return (1);
336 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
337 			    unit, code);
338 			/* fall through */
339 		case IIR_MLSC:
340 			dcamint(unit, dca);
341 			break;
342 		}
343 	}
344 }
345 
346 dcaeint(unit, stat, dca)
347 	register int unit, stat;
348 	register struct dcadevice *dca;
349 {
350 	register struct tty *tp;
351 	register int c;
352 
353 	tp = &dca_tty[unit];
354 	c = dca->dca_data;
355 	if ((tp->t_state & TS_ISOPEN) == 0) {
356 #ifdef KGDB
357 		/* we don't care about parity errors */
358 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
359 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
360 			kgdb_connect(0); /* trap into kgdb */
361 #endif
362 		return;
363 	}
364 	if (stat & (LSR_BI | LSR_FE))
365 		c |= TTY_FE;
366 	else if (stat & LSR_PE)
367 		c |= TTY_PE;
368 	else if (stat & LSR_OE)
369 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
370 	(*linesw[tp->t_line].l_rint)(c, tp);
371 }
372 
373 dcamint(unit, dca)
374 	register int unit;
375 	register struct dcadevice *dca;
376 {
377 	register struct tty *tp;
378 	register int stat;
379 
380 	tp = &dca_tty[unit];
381 	stat = dca->dca_msr;
382 #ifdef DEBUG
383 	dcamintcount[stat & 0xf]++;
384 #endif
385 	if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
386 		if (stat & MSR_DCD)
387 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
388 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
389 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
390 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
391 		   (tp->t_flags & CRTSCTS)) {
392 		/* the line is up and we want to do rts/cts flow control */
393 		if (stat & MSR_CTS) {
394 			tp->t_state &=~ TS_TTSTOP;
395 			ttstart(tp);
396 		} else
397 			tp->t_state |= TS_TTSTOP;
398 	}
399 }
400 
401 dcaioctl(dev, cmd, data, flag)
402 	dev_t dev;
403 	caddr_t data;
404 {
405 	register struct tty *tp;
406 	register int unit = UNIT(dev);
407 	register struct dcadevice *dca;
408 	register int error;
409 
410 	tp = &dca_tty[unit];
411 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
412 	if (error >= 0)
413 		return (error);
414 	error = ttioctl(tp, cmd, data, flag);
415 	if (error >= 0)
416 		return (error);
417 
418 	dca = dca_addr[unit];
419 	switch (cmd) {
420 
421 	case TIOCSBRK:
422 		dca->dca_cfcr |= CFCR_SBREAK;
423 		break;
424 
425 	case TIOCCBRK:
426 		dca->dca_cfcr &= ~CFCR_SBREAK;
427 		break;
428 
429 	case TIOCSDTR:
430 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
431 		break;
432 
433 	case TIOCCDTR:
434 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
435 		break;
436 
437 	case TIOCMSET:
438 		(void) dcamctl(dev, *(int *)data, DMSET);
439 		break;
440 
441 	case TIOCMBIS:
442 		(void) dcamctl(dev, *(int *)data, DMBIS);
443 		break;
444 
445 	case TIOCMBIC:
446 		(void) dcamctl(dev, *(int *)data, DMBIC);
447 		break;
448 
449 	case TIOCMGET:
450 		*(int *)data = dcamctl(dev, 0, DMGET);
451 		break;
452 
453 	default:
454 		return (ENOTTY);
455 	}
456 	return (0);
457 }
458 
459 dcaparam(tp, t)
460 	register struct tty *tp;
461 	register struct termios *t;
462 {
463 	register struct dcadevice *dca;
464 	register int cfcr, cflag = t->c_cflag;
465 	int unit = UNIT(tp->t_dev);
466 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
467 
468 	/* check requested parameters */
469         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
470                 return(EINVAL);
471         /* and copy to tty */
472         tp->t_ispeed = t->c_ispeed;
473         tp->t_ospeed = t->c_ospeed;
474         tp->t_cflag = cflag;
475 
476 	dca = dca_addr[unit];
477 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
478 	if (ospeed == 0) {
479 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
480 		return(0);
481 	}
482 	dca->dca_cfcr |= CFCR_DLAB;
483 	dca->dca_data = ospeed & 0xFF;
484 	dca->dca_ier = ospeed >> 8;
485 	switch (cflag&CSIZE) {
486 	case CS5:
487 		cfcr = CFCR_5BITS; break;
488 	case CS6:
489 		cfcr = CFCR_6BITS; break;
490 	case CS7:
491 		cfcr = CFCR_7BITS; break;
492 	case CS8:
493 		cfcr = CFCR_8BITS; break;
494 	}
495 	if (cflag&PARENB) {
496 		cfcr |= CFCR_PENAB;
497 		if ((cflag&PARODD) == 0)
498 			cfcr |= CFCR_PEVEN;
499 	}
500 	if (cflag&CSTOPB)
501 		cfcr |= CFCR_STOPB;
502 	dca->dca_cfcr = cfcr;
503 	if (dca_hasfifo & (1 << unit))
504 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
505 	return(0);
506 }
507 
508 dcastart(tp)
509 	register struct tty *tp;
510 {
511 	register struct dcadevice *dca;
512 	int s, unit, c;
513 
514 	unit = UNIT(tp->t_dev);
515 	dca = dca_addr[unit];
516 	s = spltty();
517 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
518 		goto out;
519 	if (tp->t_outq.c_cc <= tp->t_lowat) {
520 		if (tp->t_state&TS_ASLEEP) {
521 			tp->t_state &= ~TS_ASLEEP;
522 			wakeup((caddr_t)&tp->t_outq);
523 		}
524 		if (tp->t_wsel) {
525 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
526 			tp->t_wsel = 0;
527 			tp->t_state &= ~TS_WCOLL;
528 		}
529 	}
530 	if (tp->t_outq.c_cc == 0)
531 		goto out;
532 	if (dca->dca_lsr & LSR_TXRDY) {
533 		c = getc(&tp->t_outq);
534 		tp->t_state |= TS_BUSY;
535 		dca->dca_data = c;
536 		if (dca_hasfifo & (1 << unit)) {
537 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
538 				dca->dca_data = getc(&tp->t_outq);
539 #ifdef DEBUG
540 			if (c > 16)
541 				fifoout[0]++;
542 			else
543 				fifoout[c]++;
544 #endif
545 		}
546 	}
547 out:
548 	splx(s);
549 }
550 
551 /*
552  * Stop output on a line.
553  */
554 /*ARGSUSED*/
555 dcastop(tp, flag)
556 	register struct tty *tp;
557 {
558 	register int s;
559 
560 	s = spltty();
561 	if (tp->t_state & TS_BUSY) {
562 		if ((tp->t_state&TS_TTSTOP)==0)
563 			tp->t_state |= TS_FLUSH;
564 	}
565 	splx(s);
566 }
567 
568 dcamctl(dev, bits, how)
569 	dev_t dev;
570 	int bits, how;
571 {
572 	register struct dcadevice *dca;
573 	register int unit;
574 	int s;
575 
576 	unit = UNIT(dev);
577 	dca = dca_addr[unit];
578 	s = spltty();
579 	switch (how) {
580 
581 	case DMSET:
582 		dca->dca_mcr = bits;
583 		break;
584 
585 	case DMBIS:
586 		dca->dca_mcr |= bits;
587 		break;
588 
589 	case DMBIC:
590 		dca->dca_mcr &= ~bits;
591 		break;
592 
593 	case DMGET:
594 		bits = dca->dca_msr;
595 		break;
596 	}
597 	(void) splx(s);
598 	return(bits);
599 }
600 
601 /*
602  * Following are all routines needed for DCA to act as console
603  */
604 #include "../hp300/cons.h"
605 
606 dcacnprobe(cp)
607 	struct consdev *cp;
608 {
609 	int unit;
610 
611 	/* locate the major number */
612 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
613 		if (cdevsw[dcamajor].d_open == dcaopen)
614 			break;
615 
616 	/* XXX: ick */
617 	unit = CONUNIT;
618 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
619 
620 	/* make sure hardware exists */
621 	if (badaddr((short *)dca_addr[unit])) {
622 		cp->cn_pri = CN_DEAD;
623 		return;
624 	}
625 
626 	/* initialize required fields */
627 	cp->cn_dev = makedev(dcamajor, unit);
628 	cp->cn_tp = &dca_tty[unit];
629 	switch (dca_addr[unit]->dca_irid) {
630 	case DCAID0:
631 	case DCAID1:
632 		cp->cn_pri = CN_NORMAL;
633 		break;
634 	case DCAREMID0:
635 	case DCAREMID1:
636 		cp->cn_pri = CN_REMOTE;
637 		break;
638 	default:
639 		cp->cn_pri = CN_DEAD;
640 		break;
641 	}
642 	/*
643 	 * If dcaconsole is initialized, raise our priority.
644 	 */
645 	if (dcaconsole == unit)
646 		cp->cn_pri = CN_REMOTE;
647 #ifdef KGDB
648 	if (major(kgdb_dev) == 1)			/* XXX */
649 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
650 #endif
651 }
652 
653 dcacninit(cp)
654 	struct consdev *cp;
655 {
656 	int unit = UNIT(cp->cn_dev);
657 
658 	dcainit(unit, dcadefaultrate);
659 	dcaconsole = unit;
660 	dcaconsinit = 1;
661 }
662 
663 dcainit(unit, rate)
664 	int unit, rate;
665 {
666 	register struct dcadevice *dca;
667 	int s;
668 	short stat;
669 
670 #ifdef lint
671 	stat = unit; if (stat) return;
672 #endif
673 	dca = dca_addr[unit];
674 	s = splhigh();
675 	dca->dca_irid = 0xFF;
676 	DELAY(100);
677 	dca->dca_ic = IC_IE;
678 	dca->dca_cfcr = CFCR_DLAB;
679 	rate = ttspeedtab(rate, dcaspeedtab);
680 	dca->dca_data = rate & 0xFF;
681 	dca->dca_ier = rate >> 8;
682 	dca->dca_cfcr = CFCR_8BITS;
683 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
684 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
685 	stat = dca->dca_iir;
686 	splx(s);
687 }
688 
689 dcacngetc(dev)
690 {
691 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
692 	short stat;
693 	int c, s;
694 
695 #ifdef lint
696 	stat = dev; if (stat) return(0);
697 #endif
698 	s = splhigh();
699 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
700 		;
701 	c = dca->dca_data;
702 	stat = dca->dca_iir;
703 	splx(s);
704 	return(c);
705 }
706 
707 /*
708  * Console kernel output character routine.
709  */
710 dcacnputc(dev, c)
711 	dev_t dev;
712 	register int c;
713 {
714 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
715 	register int timo;
716 	short stat;
717 	int s = splhigh();
718 
719 #ifdef lint
720 	stat = dev; if (stat) return;
721 #endif
722 #ifdef KGDB
723 	if (dev != kgdb_dev)
724 #endif
725 	if (dcaconsinit == 0) {
726 		(void) dcainit(UNIT(dev), dcadefaultrate);
727 		dcaconsinit = 1;
728 	}
729 	/* wait for any pending transmission to finish */
730 	timo = 50000;
731 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
732 		;
733 	dca->dca_data = c;
734 	/* wait for this transmission to complete */
735 	timo = 1500000;
736 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
737 		;
738 	/* clear any interrupts generated by this transmission */
739 	stat = dca->dca_iir;
740 	splx(s);
741 }
742 #endif
743