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