xref: /original-bsd/sys/hp/dev/dca.c (revision 237fdba6)
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.4 (Berkeley) 06/06/90
8  */
9 
10 #include "dca.h"
11 #if NDCA > 0
12 /*
13  *  98626/98644/internal serial interface
14  */
15 #include "param.h"
16 #include "systm.h"
17 #include "ioctl.h"
18 #include "tty.h"
19 #include "user.h"
20 #include "conf.h"
21 #include "file.h"
22 #include "uio.h"
23 #include "kernel.h"
24 #include "syslog.h"
25 
26 #include "device.h"
27 #include "dcareg.h"
28 #include "machine/cpu.h"
29 #include "machine/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;
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) && !(tp->t_cflag&CLOCAL) &&
161 	       (tp->t_state & TS_CARR_ON) == 0) {
162 		tp->t_state |= TS_WOPEN;
163 		if ((error = tsleep((caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
164 				   ttopen, 0)) ||
165 		    (error = ttclosed(tp))) {
166 			tp->t_state &= ~TS_WOPEN;
167 			(void) spl0();
168 			return (error);
169 		}
170 	}
171 	(void) spl0();
172 	return ((*linesw[tp->t_line].l_open)(dev, tp));
173 }
174 
175 /*ARGSUSED*/
176 dcaclose(dev, flag)
177 	dev_t dev;
178 {
179 	register struct tty *tp;
180 	register struct dcadevice *dca;
181 	register int unit;
182 
183 	unit = UNIT(dev);
184 	dca = dca_addr[unit];
185 	tp = &dca_tty[unit];
186 	(*linesw[tp->t_line].l_close)(tp);
187 	dca->dca_cfcr &= ~CFCR_SBREAK;
188 #ifdef KGDB
189 	/* do not disable interrupts if debugging */
190 	if (kgdb_dev != makedev(1, unit))
191 #endif
192 	dca->dca_ier = 0;
193 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
194 	    (tp->t_state&TS_ISOPEN) == 0)
195 		(void) dcamctl(dev, 0, DMSET);
196 	ttyclose(tp);
197 	return(0);
198 }
199 
200 dcaread(dev, uio, flag)
201 	dev_t dev;
202 	struct uio *uio;
203 {
204 	register struct tty *tp = &dca_tty[UNIT(dev)];
205 
206 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
207 }
208 
209 dcawrite(dev, uio, flag)
210 	dev_t dev;
211 	struct uio *uio;
212 {
213 	int unit = UNIT(dev);
214 	register struct tty *tp = &dca_tty[unit];
215 
216 	/*
217 	 * (XXX) We disallow virtual consoles if the physical console is
218 	 * a serial port.  This is in case there is a display attached that
219 	 * is not the console.  In that situation we don't need/want the X
220 	 * server taking over the console.
221 	 */
222 	if (constty && unit == dcaconsole)
223 		constty = NULL;
224 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
225 }
226 
227 dcaintr(unit)
228 	register int unit;
229 {
230 	register struct dcadevice *dca;
231 	register int code;
232 
233 	dca = dca_addr[unit];
234 	if ((dca->dca_ic & IC_IR) == 0)
235 		return(0);
236 	while (((code = dca->dca_iir) & IIR_NOPEND) == 0) {
237 		code &= IIR_IMASK;
238 		if (code == IIR_RLS)
239 			dcaeint(unit, dca);
240 		else if (code == IIR_RXRDY)
241 			dcarint(unit, dca);
242 		else if (code == IIR_TXRDY)
243 			dcaxint(unit, dca);
244 		else
245 			dcamint(unit, dca);
246 	}
247 	return(1);
248 }
249 
250 dcaeint(unit, dca)
251 	register int unit;
252 	register struct dcadevice *dca;
253 {
254 	register struct tty *tp;
255 	register int stat, c;
256 
257 	tp = &dca_tty[unit];
258 	stat = dca->dca_lsr;
259 	c = dca->dca_data & 0xff;
260 	if ((tp->t_state & TS_ISOPEN) == 0) {
261 #ifdef KGDB
262 		/* we don't care about parity errors */
263 		if (((stat & (LSR_BI|LSR_FE|LSR_PE)) == LSR_PE) &&
264 		    kgdb_dev == makedev(1, unit) && c == '!') {
265 			printf("kgdb trap from dca%d\n", unit);
266 			/* trap into kgdb */
267 			asm("trap #15;");
268 		}
269 #endif
270 		return;
271 	}
272 	if (stat & (LSR_BI | LSR_FE))
273 		c |= TTY_FE;
274 	else if (stat & LSR_PE)
275 		c |= TTY_PE;
276 	else if (stat & LSR_OE)
277 		log(LOG_WARNING, "dca%d: silo overflow\n", unit);
278 	(*linesw[tp->t_line].l_rint)(c, tp);
279 }
280 
281 dcarint(unit, dca)
282 	int unit;
283 	register struct dcadevice *dca;
284 {
285 	register struct tty *tp;
286 	register int c;
287 
288 	tp = &dca_tty[unit];
289 	c = dca->dca_data;
290 	if ((tp->t_state & TS_ISOPEN) == 0) {
291 #ifdef KGDB
292 		if (kgdb_dev == makedev(1, unit) && c == '!') {
293 			printf("kgdb trap from dca%d\n", unit);
294 			/* trap into kgdb */
295 			asm("trap #15;");
296 		}
297 #endif
298 		return;
299 	}
300 	(*linesw[tp->t_line].l_rint)(c, tp);
301 }
302 
303 /*ARGSUSED*/
304 dcaxint(unit, dca)
305 	int unit;
306 	struct dcadevice *dca;
307 {
308 	register struct tty *tp;
309 
310 	tp = &dca_tty[unit];
311 	tp->t_state &= ~TS_BUSY;
312 	if (tp->t_state & TS_FLUSH)
313 		tp->t_state &= ~TS_FLUSH;
314 	if (tp->t_line)
315 		(*linesw[tp->t_line].l_start)(tp);
316 	else
317 		dcastart(tp);
318 }
319 
320 dcamint(unit, dca)
321 	register int unit;
322 	register struct dcadevice *dca;
323 {
324 	register struct tty *tp;
325 	register int stat;
326 
327 	tp = &dca_tty[unit];
328 	stat = dca->dca_msr;
329 	if ((stat & MSR_CCD) && (dcasoftCAR & (1 << unit)) == 0) {
330 		if (stat & MSR_DCD)
331 			(void) (*linesw[tp->t_line].l_modem)(tp, 1);
332 		else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0)
333 			dca->dca_mcr &= ~(MCR_DTR | MCR_RTS);
334 	}
335 }
336 
337 dcaioctl(dev, cmd, data, flag)
338 	dev_t dev;
339 	caddr_t data;
340 {
341 	register struct tty *tp;
342 	register int unit = UNIT(dev);
343 	register struct dcadevice *dca;
344 	register int error;
345 
346 	tp = &dca_tty[unit];
347 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
348 	if (error >= 0)
349 		return (error);
350 	error = ttioctl(tp, cmd, data, flag);
351 	if (error >= 0)
352 		return (error);
353 
354 	dca = dca_addr[unit];
355 	switch (cmd) {
356 
357 	case TIOCSBRK:
358 		dca->dca_cfcr |= CFCR_SBREAK;
359 		break;
360 
361 	case TIOCCBRK:
362 		dca->dca_cfcr &= ~CFCR_SBREAK;
363 		break;
364 
365 	case TIOCSDTR:
366 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIS);
367 		break;
368 
369 	case TIOCCDTR:
370 		(void) dcamctl(dev, MCR_DTR | MCR_RTS, DMBIC);
371 		break;
372 
373 	case TIOCMSET:
374 		(void) dcamctl(dev, *(int *)data, DMSET);
375 		break;
376 
377 	case TIOCMBIS:
378 		(void) dcamctl(dev, *(int *)data, DMBIS);
379 		break;
380 
381 	case TIOCMBIC:
382 		(void) dcamctl(dev, *(int *)data, DMBIC);
383 		break;
384 
385 	case TIOCMGET:
386 		*(int *)data = dcamctl(dev, 0, DMGET);
387 		break;
388 
389 	default:
390 		return (ENOTTY);
391 	}
392 	return (0);
393 }
394 
395 dcaparam(tp, t)
396 	register struct tty *tp;
397 	register struct termios *t;
398 {
399 	register struct dcadevice *dca;
400 	register int cfcr, cflag = t->c_cflag;
401 	int unit = UNIT(tp->t_dev);
402 	int ospeed = ttspeedtab(t->c_ospeed, dcaspeedtab);
403 
404 	/* check requested parameters */
405         if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
406                 return(EINVAL);
407         /* and copy to tty */
408         tp->t_ispeed = t->c_ispeed;
409         tp->t_ospeed = t->c_ospeed;
410         tp->t_cflag = cflag;
411 
412 	dca = dca_addr[unit];
413 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY | IER_ERLS | IER_EMSC;
414 	if (ospeed == 0) {
415 		(void) dcamctl(unit, 0, DMSET);	/* hang up line */
416 		return(0);
417 	}
418 	dca->dca_cfcr |= CFCR_DLAB;
419 	dca->dca_data = ospeed & 0xFF;
420 	dca->dca_ier = ospeed >> 8;
421 	switch (cflag&CSIZE) {
422 	case CS5:
423 		cfcr = CFCR_5BITS; break;
424 	case CS6:
425 		cfcr = CFCR_6BITS; break;
426 	case CS7:
427 		cfcr = CFCR_7BITS; break;
428 	case CS8:
429 		cfcr = CFCR_8BITS; break;
430 	}
431 	if (cflag&PARENB) {
432 		cfcr |= CFCR_PENAB;
433 		if ((cflag&PARODD) == 0)
434 			cfcr |= CFCR_PEVEN;
435 	}
436 	if (cflag&CSTOPB)
437 		cfcr |= CFCR_STOPB;
438 	dca->dca_cfcr = cfcr;
439 	return(0);
440 }
441 
442 dcastart(tp)
443 	register struct tty *tp;
444 {
445 	register struct dcadevice *dca;
446 	int s, unit, c;
447 
448 	unit = UNIT(tp->t_dev);
449 	dca = dca_addr[unit];
450 	s = spltty();
451 	if (tp->t_state & (TS_TIMEOUT|TS_BUSY|TS_TTSTOP))
452 		goto out;
453 	if (tp->t_outq.c_cc <= tp->t_lowat) {
454 		if (tp->t_state&TS_ASLEEP) {
455 			tp->t_state &= ~TS_ASLEEP;
456 			wakeup((caddr_t)&tp->t_outq);
457 		}
458 		if (tp->t_wsel) {
459 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
460 			tp->t_wsel = 0;
461 			tp->t_state &= ~TS_WCOLL;
462 		}
463 	}
464 	if (tp->t_outq.c_cc == 0)
465 		goto out;
466 	c = getc(&tp->t_outq);
467 	tp->t_state |= TS_BUSY;
468 	dca->dca_data = c;
469 out:
470 	splx(s);
471 }
472 
473 /*
474  * Stop output on a line.
475  */
476 /*ARGSUSED*/
477 dcastop(tp, flag)
478 	register struct tty *tp;
479 {
480 	register int s;
481 
482 	s = spltty();
483 	if (tp->t_state & TS_BUSY) {
484 		if ((tp->t_state&TS_TTSTOP)==0)
485 			tp->t_state |= TS_FLUSH;
486 	}
487 	splx(s);
488 }
489 
490 dcamctl(dev, bits, how)
491 	dev_t dev;
492 	int bits, how;
493 {
494 	register struct dcadevice *dca;
495 	register int unit;
496 	int s;
497 
498 	unit = UNIT(dev);
499 	dca = dca_addr[unit];
500 	s = spltty();
501 	switch (how) {
502 
503 	case DMSET:
504 		dca->dca_mcr = bits;
505 		break;
506 
507 	case DMBIS:
508 		dca->dca_mcr |= bits;
509 		break;
510 
511 	case DMBIC:
512 		dca->dca_mcr &= ~bits;
513 		break;
514 
515 	case DMGET:
516 		bits = dca->dca_msr;
517 		break;
518 	}
519 	(void) splx(s);
520 	return(bits);
521 }
522 
523 /*
524  * Following are all routines needed for DCA to act as console
525  */
526 #include "machine/cons.h"
527 
528 dcacnprobe(cp)
529 	struct consdev *cp;
530 {
531 	int unit, i;
532 	extern int dcaopen();
533 
534 	/* XXX: ick */
535 	unit = CONUNIT;
536 	dca_addr[CONUNIT] = CONADDR;
537 
538 	/* make sure hardware exists */
539 	if (badaddr((short *)dca_addr[unit])) {
540 		cp->cn_pri = CN_DEAD;
541 		return;
542 	}
543 
544 	/* locate the major number */
545 	for (i = 0; i < nchrdev; i++)
546 		if (cdevsw[i].d_open == dcaopen)
547 			break;
548 
549 	/* initialize required fields */
550 	cp->cn_dev = makedev(i, unit);
551 	cp->cn_tp = &dca_tty[unit];
552 	switch (dca_addr[unit]->dca_irid) {
553 	case DCAID0:
554 	case DCAID1:
555 		cp->cn_pri = CN_NORMAL;
556 		break;
557 	case DCAREMID0:
558 	case DCAREMID1:
559 		cp->cn_pri = CN_REMOTE;
560 		break;
561 	default:
562 		cp->cn_pri = CN_DEAD;
563 		break;
564 	}
565 }
566 
567 dcacninit(cp)
568 	struct consdev *cp;
569 {
570 	int unit = UNIT(cp->cn_dev);
571 
572 	dcainit(unit);
573 	dcaconsole = unit;
574 }
575 
576 dcainit(unit)
577 	int unit;
578 {
579 	register struct dcadevice *dca;
580 	int s, rate;
581 	short stat;
582 
583 #ifdef lint
584 	stat = unit; if (stat) return;
585 #endif
586 	dca = dca_addr[unit];
587 	s = splhigh();
588 	dca->dca_irid = 0xFF;
589 	DELAY(100);
590 	dca->dca_ic = IC_IE;
591 	dca->dca_cfcr = CFCR_DLAB;
592 	rate = ttspeedtab(dcadefaultrate, dcaspeedtab);
593 	dca->dca_data = rate & 0xFF;
594 	dca->dca_ier = rate >> 8;
595 	dca->dca_cfcr = CFCR_8BITS;
596 	dca->dca_ier = IER_ERXRDY | IER_ETXRDY;
597 	stat = dca->dca_iir;
598 	splx(s);
599 }
600 
601 dcacngetc(dev)
602 {
603 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
604 	short stat;
605 	int c, s;
606 
607 #ifdef lint
608 	stat = dev; if (stat) return(0);
609 #endif
610 	s = splhigh();
611 	while (((stat = dca->dca_lsr) & LSR_RXRDY) == 0)
612 		;
613 	c = dca->dca_data;
614 	stat = dca->dca_iir;
615 	splx(s);
616 	return(c);
617 }
618 
619 /*
620  * Console kernel output character routine.
621  */
622 dcacnputc(dev, c)
623 	dev_t dev;
624 	register int c;
625 {
626 	register struct dcadevice *dca = dca_addr[UNIT(dev)];
627 	register int timo;
628 	short stat;
629 	int s = splhigh();
630 
631 #ifdef lint
632 	stat = dev; if (stat) return;
633 #endif
634 	if (dcaconsole == -1) {
635 		(void) dcainit(UNIT(dev));
636 		dcaconsole = UNIT(dev);
637 	}
638 	/* wait for any pending transmission to finish */
639 	timo = 50000;
640 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
641 		;
642 	dca->dca_data = c;
643 	/* wait for this transmission to complete */
644 	timo = 1500000;
645 	while (((stat = dca->dca_lsr) & LSR_TXRDY) == 0 && --timo)
646 		;
647 	/* clear any interrupts generated by this transmission */
648 	stat = dca->dca_iir;
649 	splx(s);
650 }
651 #endif
652