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