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