xref: /csrg-svn/sys/hp/dev/dca.c (revision 49300)
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.10 (Berkeley) 05/07/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)
208 	dev_t dev;
209 {
210 	register struct tty *tp;
211 	register struct dcadevice *dca;
212 	register int unit;
213 
214 	unit = UNIT(dev);
215 	dca = dca_addr[unit];
216 	tp = &dca_tty[unit];
217 	(*linesw[tp->t_line].l_close)(tp);
218 	dca->dca_cfcr &= ~CFCR_SBREAK;
219 #ifdef KGDB
220 	/* do not disable interrupts if debugging */
221 	if (dev != kgdb_dev)
222 #endif
223 	dca->dca_ier = 0;
224 	(void) dcamctl(dev, 0, DMSET);
225 	if (tp->t_state & TS_HUPCLS)
226 		(*linesw[tp->t_line].l_modem)(tp, 0);
227 	ttyclose(tp);
228 	return(0);
229 }
230 
231 dcaread(dev, uio, flag)
232 	dev_t dev;
233 	struct uio *uio;
234 {
235 	register struct tty *tp = &dca_tty[UNIT(dev)];
236 
237 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
238 }
239 
240 dcawrite(dev, uio, flag)
241 	dev_t dev;
242 	struct uio *uio;
243 {
244 	int unit = UNIT(dev);
245 	register struct tty *tp = &dca_tty[unit];
246 
247 	/*
248 	 * (XXX) We disallow virtual consoles if the physical console is
249 	 * a serial port.  This is in case there is a display attached that
250 	 * is not the console.  In that situation we don't need/want the X
251 	 * server taking over the console.
252 	 */
253 	if (constty && unit == dcaconsole)
254 		constty = NULL;
255 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
256 }
257 
258 dcaintr(unit)
259 	register int unit;
260 {
261 	register struct dcadevice *dca;
262 	register u_char code;
263 	register struct tty *tp;
264 
265 	dca = dca_addr[unit];
266 	if ((dca->dca_ic & IC_IR) == 0)
267 		return(0);
268 	while (1) {
269 		code = dca->dca_iir;
270 #ifdef DEBUG
271 		dcaintrcount[code & IIR_IMASK]++;
272 #endif
273 		switch (code & IIR_IMASK) {
274 		case IIR_NOPEND:
275 			return (1);
276 		case IIR_RXTOUT:
277 		case IIR_RXRDY:
278 			/* do time-critical read in-line */
279 			tp = &dca_tty[unit];
280 /*
281  * Process a received byte.  Inline for speed...
282  */
283 #ifdef KGDB
284 #define	RCVBYTE() \
285 			code = dca->dca_data; \
286 			if ((tp->t_state & TS_ISOPEN) == 0) { \
287 				if (kgdb_dev == makedev(dcamajor, unit) && \
288 				    code == FRAME_END) \
289 					kgdb_connect(0); /* trap into kgdb */ \
290 			} else \
291 				(*linesw[tp->t_line].l_rint)(code, tp)
292 #else
293 #define	RCVBYTE() \
294 			code = dca->dca_data; \
295 			if ((tp->t_state & TS_ISOPEN) != 0) \
296 				(*linesw[tp->t_line].l_rint)(code, tp)
297 #endif
298 			RCVBYTE();
299 			if (dca_hasfifo & (1 << unit)) {
300 #ifdef DEBUG
301 				register int fifocnt = 1;
302 #endif
303 				while ((code = dca->dca_lsr) & LSR_RCV_MASK) {
304 					if (code == LSR_RXRDY) {
305 						RCVBYTE();
306 					} else
307 						dcaeint(unit, code, dca);
308 #ifdef DEBUG
309 					fifocnt++;
310 #endif
311 				}
312 #ifdef DEBUG
313 				if (fifocnt > 16)
314 					fifoin[0]++;
315 				else
316 					fifoin[fifocnt]++;
317 #endif
318 			}
319 			break;
320 		case IIR_TXRDY:
321 			tp = &dca_tty[unit];
322 			tp->t_state &=~ (TS_BUSY|TS_FLUSH);
323 			if (tp->t_line)
324 				(*linesw[tp->t_line].l_start)(tp);
325 			else
326 				dcastart(tp);
327 			break;
328 		case IIR_RLS:
329 			dcaeint(unit, dca->dca_lsr, dca);
330 			break;
331 		default:
332 			if (code & IIR_NOPEND)
333 				return (1);
334 			log(LOG_WARNING, "dca%d: weird interrupt: 0x%x\n",
335 			    unit, code);
336 			/* fall through */
337 		case IIR_MLSC:
338 			dcamint(unit, dca);
339 			break;
340 		}
341 	}
342 }
343 
344 dcaeint(unit, stat, dca)
345 	register int unit, stat;
346 	register struct dcadevice *dca;
347 {
348 	register struct tty *tp;
349 	register int c;
350 
351 	tp = &dca_tty[unit];
352 	c = dca->dca_data;
353 	if ((tp->t_state & TS_ISOPEN) == 0) {
354 #ifdef KGDB
355 		/* we don't care about parity errors */
356 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
357 		    kgdb_dev == makedev(dcamajor, unit) && c == FRAME_END)
358 			kgdb_connect(0); /* trap into kgdb */
359 #endif
360 		return;
361 	}
362 	if (stat & (LSR_BI | LSR_FE))
363 		c |= TTY_FE;
364 	else if (stat & LSR_PE)
365 		c |= TTY_PE;
366 	else if (stat & LSR_OE)
367 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
368 	(*linesw[tp->t_line].l_rint)(c, tp);
369 }
370 
371 dcamint(unit, dca)
372 	register int unit;
373 	register struct dcadevice *dca;
374 {
375 	register struct tty *tp;
376 	register int stat;
377 
378 	tp = &dca_tty[unit];
379 	stat = dca->dca_msr;
380 #ifdef DEBUG
381 	dcamintcount[stat & 0xf]++;
382 #endif
383 	if ((stat & MSR_DDCD) && (dcasoftCAR & (1 << unit)) == 0) {
384 		if (stat & MSR_DCD)
385 			(void)(*linesw[tp->t_line].l_modem)(tp, 1);
386 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
387 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
388 	} else if ((stat & MSR_DCTS) && (tp->t_state & TS_ISOPEN) &&
389 		   (tp->t_flags & CRTSCTS)) {
390 		/* the line is up and we want to do rts/cts flow control */
391 		if (stat & MSR_CTS) {
392 			tp->t_state &=~ TS_TTSTOP;
393 			ttstart(tp);
394 		} else
395 			tp->t_state |= TS_TTSTOP;
396 	}
397 }
398 
399 dcaioctl(dev, cmd, data, flag)
400 	dev_t dev;
401 	caddr_t data;
402 {
403 	register struct tty *tp;
404 	register int unit = UNIT(dev);
405 	register struct dcadevice *dca;
406 	register int error;
407 
408 	tp = &dca_tty[unit];
409 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
410 	if (error >= 0)
411 		return (error);
412 	error = ttioctl(tp, cmd, data, flag);
413 	if (error >= 0)
414 		return (error);
415 
416 	dca = dca_addr[unit];
417 	switch (cmd) {
418 
419 	case TIOCSBRK:
420 		dca->dca_cfcr |= CFCR_SBREAK;
421 		break;
422 
423 	case TIOCCBRK:
424 		dca->dca_cfcr &= ~CFCR_SBREAK;
425 		break;
426 
427 	case TIOCSDTR:
428 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
429 		break;
430 
431 	case TIOCCDTR:
432 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
433 		break;
434 
435 	case TIOCMSET:
436 		(void) dcamctl(dev, *(int *)data, DMSET);
437 		break;
438 
439 	case TIOCMBIS:
440 		(void) dcamctl(dev, *(int *)data, DMBIS);
441 		break;
442 
443 	case TIOCMBIC:
444 		(void) dcamctl(dev, *(int *)data, DMBIC);
445 		break;
446 
447 	case TIOCMGET:
448 		*(int *)data = dcamctl(dev, 0, DMGET);
449 		break;
450 
451 	default:
452 		return (ENOTTY);
453 	}
454 	return (0);
455 }
456 
457 dcaparam(tp, t)
458 	register struct tty *tp;
459 	register struct termios *t;
460 {
461 	register struct dcadevice *dca;
462 	register int cfcr, cflag = t->c_cflag;
463 	int unit = UNIT(tp->t_dev);
464 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
465 
466 	/* check requested parameters */
467         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
468                 return(EINVAL);
469         /* and copy to tty */
470         tp->t_ispeed = t->c_ispeed;
471         tp->t_ospeed = t->c_ospeed;
472         tp->t_cflag = cflag;
473 
474 	dca = dca_addr[unit];
475 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
476 	if (ospeed == 0) {
477 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
478 		return(0);
479 	}
480 	dca->dca_cfcr |= CFCR_DLAB;
481 	dca->dca_data = ospeed & 0xFF;
482 	dca->dca_ier = ospeed >> 8;
483 	switch (cflag&CSIZE) {
484 	case CS5:
485 		cfcr = CFCR_5BITS; break;
486 	case CS6:
487 		cfcr = CFCR_6BITS; break;
488 	case CS7:
489 		cfcr = CFCR_7BITS; break;
490 	case CS8:
491 		cfcr = CFCR_8BITS; break;
492 	}
493 	if (cflag&PARENB) {
494 		cfcr |= CFCR_PENAB;
495 		if ((cflag&PARODD) == 0)
496 			cfcr |= CFCR_PEVEN;
497 	}
498 	if (cflag&CSTOPB)
499 		cfcr |= CFCR_STOPB;
500 	dca->dca_cfcr = cfcr;
501 	if (dca_hasfifo & (1 << unit))
502 		dca->dca_fifo = FIFO_ENABLE | FIFO_TRIGGER_14;
503 	return(0);
504 }
505 
506 dcastart(tp)
507 	register struct tty *tp;
508 {
509 	register struct dcadevice *dca;
510 	int s, unit, c;
511 
512 	unit = UNIT(tp->t_dev);
513 	dca = dca_addr[unit];
514 	s = spltty();
515 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
516 		goto out;
517 	if (tp->t_outq.c_cc <= tp->t_lowat) {
518 		if (tp->t_state&TS_ASLEEP) {
519 			tp->t_state &= ~TS_ASLEEP;
520 			wakeup((caddr_t)&tp->t_outq);
521 		}
522 		if (tp->t_wsel) {
523 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
524 			tp->t_wsel = 0;
525 			tp->t_state &= ~TS_WCOLL;
526 		}
527 	}
528 	if (tp->t_outq.c_cc == 0)
529 		goto out;
530 	if (dca->dca_lsr & LSR_TXRDY) {
531 		c = getc(&tp->t_outq);
532 		tp->t_state |= TS_BUSY;
533 		dca->dca_data = c;
534 		if (dca_hasfifo & (1 << unit)) {
535 			for (c = 1; c < 16 && tp->t_outq.c_cc; ++c)
536 				dca->dca_data = getc(&tp->t_outq);
537 #ifdef DEBUG
538 			if (c > 16)
539 				fifoout[0]++;
540 			else
541 				fifoout[c]++;
542 #endif
543 		}
544 	}
545 out:
546 	splx(s);
547 }
548 
549 /*
550  * Stop output on a line.
551  */
552 /*ARGSUSED*/
553 dcastop(tp, flag)
554 	register struct tty *tp;
555 {
556 	register int s;
557 
558 	s = spltty();
559 	if (tp->t_state & TS_BUSY) {
560 		if ((tp->t_state&TS_TTSTOP)==0)
561 			tp->t_state |= TS_FLUSH;
562 	}
563 	splx(s);
564 }
565 
566 dcamctl(dev, bits, how)
567 	dev_t dev;
568 	int bits, how;
569 {
570 	register struct dcadevice *dca;
571 	register int unit;
572 	int s;
573 
574 	unit = UNIT(dev);
575 	dca = dca_addr[unit];
576 	s = spltty();
577 	switch (how) {
578 
579 	case DMSET:
580 		dca->dca_mcr = bits;
581 		break;
582 
583 	case DMBIS:
584 		dca->dca_mcr |= bits;
585 		break;
586 
587 	case DMBIC:
588 		dca->dca_mcr &= ~bits;
589 		break;
590 
591 	case DMGET:
592 		bits = dca->dca_msr;
593 		break;
594 	}
595 	(void) splx(s);
596 	return(bits);
597 }
598 
599 /*
600  * Following are all routines needed for DCA to act as console
601  */
602 #include "../hp300/cons.h"
603 
604 dcacnprobe(cp)
605 	struct consdev *cp;
606 {
607 	int unit;
608 
609 	/* locate the major number */
610 	for (dcamajor = 0; dcamajor < nchrdev; dcamajor++)
611 		if (cdevsw[dcamajor].d_open == dcaopen)
612 			break;
613 
614 	/* XXX: ick */
615 	unit = CONUNIT;
616 	dca_addr[CONUNIT] = (struct dcadevice *) sctova(CONSCODE);
617 
618 	/* make sure hardware exists */
619 	if (badaddr((short *)dca_addr[unit])) {
620 		cp->cn_pri = CN_DEAD;
621 		return;
622 	}
623 
624 	/* initialize required fields */
625 	cp->cn_dev = makedev(dcamajor, unit);
626 	cp->cn_tp = &dca_tty[unit];
627 	switch (dca_addr[unit]->dca_irid) {
628 	case DCAID0:
629 	case DCAID1:
630 		cp->cn_pri = CN_NORMAL;
631 		break;
632 	case DCAREMID0:
633 	case DCAREMID1:
634 		cp->cn_pri = CN_REMOTE;
635 		break;
636 	default:
637 		cp->cn_pri = CN_DEAD;
638 		break;
639 	}
640 	/*
641 	 * If dcaconsole is initialized, raise our priority.
642 	 */
643 	if (dcaconsole == unit)
644 		cp->cn_pri = CN_REMOTE;
645 #ifdef KGDB
646 	if (major(kgdb_dev) == 1)			/* XXX */
647 		kgdb_dev = makedev(dcamajor, minor(kgdb_dev));
648 #endif
649 }
650 
651 dcacninit(cp)
652 	struct consdev *cp;
653 {
654 	int unit = UNIT(cp->cn_dev);
655 
656 	dcainit(unit, dcadefaultrate);
657 	dcaconsole = unit;
658 	dcaconsinit = 1;
659 }
660 
661 dcainit(unit, rate)
662 	int unit, rate;
663 {
664 	register struct dcadevice *dca;
665 	int s;
666 	short stat;
667 
668 #ifdef lint
669 	stat = unit; if (stat) return;
670 #endif
671 	dca = dca_addr[unit];
672 	s = splhigh();
673 	dca->dca_irid = 0xFF;
674 	DELAY(100);
675 	dca->dca_ic = IC_IE;
676 	dca->dca_cfcr = CFCR_DLAB;
677 	rate = ttspeedtab(rate, dcaspeedtab);
678 	dca->dca_data = rate & 0xFF;
679 	dca->dca_ier = rate >> 8;
680 	dca->dca_cfcr = CFCR_8BITS;
681 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
682 	dca->dca_fifo = FIFO_ENABLE|FIFO_RCV_RST|FIFO_XMT_RST|FIFO_TRIGGER_14;
683 	stat = dca->dca_iir;
684 	splx(s);
685 }
686 
687 dcacngetc(dev)
688 {
689 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
690 	short stat;
691 	int c, s;
692 
693 #ifdef lint
694 	stat = dev; if (stat) return(0);
695 #endif
696 	s = splhigh();
697 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
698 		;
699 	c = dca->dca_data;
700 	stat = dca->dca_iir;
701 	splx(s);
702 	return(c);
703 }
704 
705 /*
706  * Console kernel output character routine.
707  */
708 dcacnputc(dev, c)
709 	dev_t dev;
710 	register int c;
711 {
712 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
713 	register int timo;
714 	short stat;
715 	int s = splhigh();
716 
717 #ifdef lint
718 	stat = dev; if (stat) return;
719 #endif
720 #ifdef KGDB
721 	if (dev != kgdb_dev)
722 #endif
723 	if (dcaconsinit == 0) {
724 		(void) dcainit(UNIT(dev), dcadefaultrate);
725 		dcaconsinit = 1;
726 	}
727 	/* wait for any pending transmission to finish */
728 	timo = 50000;
729 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
730 		;
731 	dca->dca_data = c;
732 	/* wait for this transmission to complete */
733 	timo = 1500000;
734 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
735 		;
736 	/* clear any interrupts generated by this transmission */
737 	stat = dca->dca_iir;
738 	splx(s);
739 }
740 #endif
741