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