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