xref: /original-bsd/sys/luna68k/dev/sio.c (revision 3705696b)
1 /*
2  * Copyright (c) 1992 OMRON Corporation.
3  * Copyright (c) 1992, 1993
4  *	The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * OMRON Corporation.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)sio.c	8.1 (Berkeley) 06/10/93
12  */
13 
14 /*
15  * sio.c -- NEC uPD7201A UART Device Driver
16  *    remaked by A.Fujita, NOV-5-1992
17  */
18 
19 #include "sio.h"
20 #if NSIO > 0
21 
22 #include "bmc.h"
23 
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/ioctl.h>
27 #include <sys/proc.h>
28 #include <sys/tty.h>
29 #include <sys/conf.h>
30 #include <sys/file.h>
31 #include <sys/uio.h>
32 #include <sys/kernel.h>
33 #include <sys/syslog.h>
34 
35 #include <luna68k/dev/device.h>
36 #include <luna68k/dev/sioreg.h>
37 #include <luna68k/dev/siovar.h>
38 
39 struct sio_portc *sio_port_assign();
40 struct sio_portc *sio_port_get();
41 
42 int	sioprobe();
43 int	sioopen();
44 void	siostart();
45 int	sioparam();
46 int	siointr();
47 
48 struct	driver siodriver = {
49 	sioprobe, "sio",
50 };
51 
52 struct	sio_portc sio_portc[NPORT] = {
53 	{ -1, -1, 0, (struct siodevice *) 0x51000000, (int (*)()) 0 },
54 	{ -1, -1, 1, (struct siodevice *) 0x51000004, (int (*)()) 0 }
55 };
56 
57 struct	sio_softc sio_softc[NSIO];
58 
59 int	sio_init_done = 0;
60 
61 int	siosoftCAR;
62 int	sio_active;
63 int	sioconsole = -1;
64 int	siodefaultrate = TTYDEF_SPEED;
65 int	siomajor = 12;
66 
67 struct	tty sio_tty[NSIO];
68 
69 struct speedtab siospeedtab[] = {
70 	2400,	WR4_BAUD24,
71 	4800,	WR4_BAUD48,
72 	9600,	WR4_BAUD96,
73 };
74 
75 #define	siounit(x)		minor(x)
76 
77 extern	struct tty *constty;
78 
79 #ifdef KGDB
80 /*
81  * Kernel GDB support
82  */
83 #include <machine/remote-sl.h>
84 
85 extern dev_t kgdb_dev;
86 extern int kgdb_rate;
87 extern int kgdb_debug_init;
88 #endif
89 
90 /*
91  *  probe routines
92  */
93 
94 sioprobe(hd)
95 	register struct hp_device *hd;
96 {
97 	int unit = hd->hp_unit;
98 	register struct sio_softc *sc = &sio_softc[unit];
99 	register struct sio_portc *pc;
100 
101 	if (sc->sc_pc != 0) {
102 		pc = sc->sc_pc;
103 		printf("sio%d: port %d, address 0x%x, intr 0x%x (console)\n",
104 		       pc->pc_unit, pc->pc_port, pc->pc_addr, pc->pc_intr);
105 		return(1);
106 	}
107 
108 	sc->sc_pc = pc = sio_port_assign(unit, siomajor, unit, siointr);
109 
110 	printf("sio%d: port %d, address 0x%x, intr 0x%x\n",
111 	       pc->pc_unit, pc->pc_port, pc->pc_addr, pc->pc_intr);
112 
113 	sio_active |= 1 << unit;
114 
115 #ifdef KGDB
116 	if (major(kgdb_dev) == siomajor) {
117 #ifdef	notdef
118 		if (sioconsole == siounit(kgdb_dev)) {
119 			kgdb_dev = NODEV; /* can't debug over console port */
120 		} else {
121 #endif
122 		/*
123 		 * The following could potentially be replaced
124 		 * by the corresponding code in dcmcnprobe.
125 		 */
126 			if (kgdb_debug_init) {
127 				printf("sio%d: ", siounit(kgdb_dev));
128 				kgdb_connect(1);
129 			} else
130 				printf("sio%d: kgdb enabled\n", siounit(kgdb_dev));
131 #ifdef	notdef
132 		}
133 #endif
134 		/* end could be replaced */
135 	}
136 #endif
137 
138 	siosoftCAR |= 1 << unit;
139 	return(1);
140 }
141 
142 struct sio_portc *
143 sio_port_assign(port, major, unit, intr)
144 	int	port, major, unit;
145 	int	(*intr)();
146 {
147 	register struct sio_portc *pc;
148 
149 	pc = &sio_portc[port];
150 
151 	pc->pc_major = major;
152 	pc->pc_intr  = intr;
153 	pc->pc_unit  = unit;
154 
155 	return(pc);
156 }
157 
158 struct sio_portc *
159 sio_port_get(port)
160 	int port;
161 {
162 	register struct sio_portc *pc;
163 
164 	pc = &sio_portc[port];
165 
166 	return(pc);
167 }
168 
169 int
170 sio_port_info()
171 {
172 	printf("sio_port_info[sio.c]:\t{%d}       major = %d, unit = %d, intr = 0x%x\n",
173 		0, sio_portc[0].pc_major, sio_portc[0].pc_unit, sio_portc[0].pc_intr);
174 	printf("sio_port_info[sio.c]:\t{%d}       major = %d, unit = %d, intr = 0x%x\n",
175 		1, sio_portc[1].pc_major, sio_portc[1].pc_unit, sio_portc[1].pc_intr);
176 }
177 
178 
179 /*
180  *  entry routines
181  */
182 
183 /* ARGSUSED */
184 #ifdef __STDC__
185 sioopen(dev_t dev, int flag, int mode, struct proc *p)
186 #else
187 sioopen(dev, flag, mode, p)
188 	dev_t dev;
189 	int flag, mode;
190 	struct proc *p;
191 #endif
192 {
193 	register struct tty *tp;
194 	register int unit;
195 	int error = 0;
196 
197 	unit = siounit(dev);
198 	if (unit >= NSIO || (sio_active & (1 << unit)) == 0)
199 		return (ENXIO);
200 	tp = &sio_tty[unit];
201 	tp->t_oproc = siostart;
202 	tp->t_param = sioparam;
203 	tp->t_dev = dev;
204 	if ((tp->t_state & TS_ISOPEN) == 0) {
205 		tp->t_state |= TS_WOPEN;
206 		ttychars(tp);
207 		if (tp->t_ispeed == 0) {
208 			tp->t_iflag = TTYDEF_IFLAG;
209 			tp->t_oflag = TTYDEF_OFLAG;
210 /*			tp->t_cflag = TTYDEF_CFLAG;		*/
211 			tp->t_cflag = (CREAD | CS8 | HUPCL);
212 			tp->t_lflag = TTYDEF_LFLAG;
213 			tp->t_ispeed = tp->t_ospeed = siodefaultrate;
214 		}
215 		sioparam(tp, &tp->t_termios);
216 		ttsetwater(tp);
217 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
218 		return (EBUSY);
219 	(void) siomctl(dev, WR5_DTR | WR5_RTS, DMSET);
220 	if ((siosoftCAR & (1 << unit)) || (siomctl(dev, 0, DMGET) & RR0_DCD))
221 		tp->t_state |= TS_CARR_ON;
222 	(void) spltty();
223 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
224 	       (tp->t_state & TS_CARR_ON) == 0) {
225 		tp->t_state |= TS_WOPEN;
226 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
227 		    ttopen, 0))
228 			break;
229 	}
230 	(void) spl0();
231 	if (error == 0)
232 		error = (*linesw[tp->t_line].l_open)(dev, tp);
233 	return (error);
234 }
235 
236 /*ARGSUSED*/
237 sioclose(dev, flag, mode, p)
238 	dev_t dev;
239 	int flag, mode;
240 	struct proc *p;
241 {
242 	register struct tty *tp;
243 	register int unit;
244 
245 	unit = siounit(dev);
246 	tp = &sio_tty[unit];
247 	(*linesw[tp->t_line].l_close)(tp, flag);
248 	(void) siomctl(dev, WR5_BREAK, DMBIS);
249 	if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN ||
250 	    (tp->t_state&TS_ISOPEN) == 0)
251 		(void) siomctl(dev, 0, DMSET);
252 	ttyclose(tp);
253 	return (0);
254 }
255 
256 sioread(dev, uio, flag)
257 	dev_t dev;
258 	struct uio *uio;
259 {
260 	register struct tty *tp = &sio_tty[siounit(dev)];
261 
262 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
263 }
264 
265 siowrite(dev, uio, flag)
266 	dev_t dev;
267 	struct uio *uio;
268 {
269 	register int unit = siounit(dev);
270 	register struct tty *tp = &sio_tty[unit];
271 
272 	if ((unit == sioconsole) && constty &&
273 	    (constty->t_state&(TS_CARR_ON|TS_ISOPEN))==(TS_CARR_ON|TS_ISOPEN))
274 		tp = constty;
275 
276 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
277 }
278 
279 /*
280  * Stop output on a line.
281  */
282 /*ARGSUSED*/
283 siostop(tp, flag)
284 	register struct tty *tp;
285 {
286 	register int s;
287 
288 	s = spltty();
289 	if (tp->t_state & TS_BUSY) {
290 		if ((tp->t_state&TS_TTSTOP)==0)
291 			tp->t_state |= TS_FLUSH;
292 	}
293 	splx(s);
294 }
295 
296 sioioctl(dev, cmd, data, flag, p)
297 	dev_t dev;
298 	int cmd;
299 	caddr_t data;
300 	int flag;
301 	struct proc *p;
302 {
303 	register struct tty *tp;
304 	register int unit = siounit(dev);
305 	register int error;
306 
307 	tp = &sio_tty[unit];
308 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
309 	if (error >= 0)
310 		return (error);
311 	error = ttioctl(tp, cmd, data, flag);
312 	if (error >= 0)
313 		return (error);
314 
315 	switch (cmd) {
316 
317 	case TIOCSBRK:
318 		(void) siomctl(dev, WR5_BREAK, DMBIS);
319 		break;
320 
321 	case TIOCCBRK:
322 		(void) siomctl(dev, WR5_BREAK, DMBIC);
323 		break;
324 
325 	case TIOCSDTR:
326 		(void) siomctl(dev, WR5_DTR | WR5_RTS, DMBIS);
327 		break;
328 
329 	case TIOCCDTR:
330 		(void) siomctl(dev, WR5_DTR | WR5_RTS, DMBIC);
331 		break;
332 
333 	case TIOCMSET:
334 		(void) siomctl(dev, *(int *)data, DMSET);
335 		break;
336 
337 	case TIOCMBIS:
338 		(void) siomctl(dev, *(int *)data, DMBIS);
339 		break;
340 
341 	case TIOCMBIC:
342 		(void) siomctl(dev, *(int *)data, DMBIC);
343 		break;
344 
345 	case TIOCMGET:
346 		*(int *)data = siomctl(dev, 0, DMGET);
347 		break;
348 
349 	default:
350 		return (ENOTTY);
351 	}
352 	return (0);
353 }
354 
355 
356 /*
357  *
358  */
359 
360 void
361 siostart(tp)
362 	register struct tty *tp;
363 {
364 	register struct siodevice *sio;
365 	register int rr;
366 	int s, unit, c;
367 
368 	unit = siounit(tp->t_dev);
369 	sio = sio_softc[unit].sc_pc->pc_addr;
370 	s = spltty();
371 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
372 		goto out;
373 	if (tp->t_outq.c_cc <= tp->t_lowat) {
374 		if (tp->t_state&TS_ASLEEP) {
375 			tp->t_state &= ~TS_ASLEEP;
376 			wakeup((caddr_t)&tp->t_outq);
377 		}
378 		selwakeup(&tp->t_wsel);
379 	}
380 	if (tp->t_outq.c_cc == 0)
381 		goto out;
382 	rr = siogetreg(sio);
383 	if (rr & RR_TXRDY) {
384 		c = getc(&tp->t_outq);
385 		tp->t_state |= TS_BUSY;
386 		sio->sio_data = c;
387 	}
388 out:
389 	splx(s);
390 }
391 
392 sioparam(tp, t)
393 	register struct tty *tp;
394 	register struct termios *t;
395 {
396 	int unit = siounit(tp->t_dev);
397 	register struct siodevice *sio;
398 	register cflag = t->c_cflag;
399 	register u_char wr;
400 	int ospeed = ttspeedtab(t->c_ospeed, siospeedtab);
401 
402 	sio = sio_softc[unit].sc_pc->pc_addr;
403 
404 	switch (cflag & CSIZE) {
405 	case CS5:
406 	case CS6:
407 	case CS7:
408 	case CS8:
409 		break;
410 	}
411 
412 	wr = ospeed;
413 
414 	if (cflag & PARENB) {
415 		wr |= WR4_PARENAB;
416 		if ((cflag&PARODD) == 0)
417 			wr |= WR4_EPARITY;
418 	}
419 
420 	if (cflag & CSTOPB)
421 		wr |= WR4_STOP2;			/* 2 stop bit */
422 	else
423 		wr |= WR4_STOP1;			/* 1 stop bit */
424 
425 	(void) sioreg(sio, WR4, wr);
426 
427 	return (0);
428 }
429 
430 siomctl()
431 {
432 	return (0);
433 }
434 
435 
436 /*
437  *  Interrupt handling
438  */
439 
440 void
441 _siointr()
442 {
443 	register int port;
444 	register struct sio_portc *pc;
445 
446 	for (port = 0; port < NPORT; port++) {
447 		pc = &sio_portc[port];
448 
449 		if (pc->pc_major != -1)
450 			(pc->pc_intr)(pc->pc_unit);
451 	}
452 }
453 
454 siointr(unit)
455 	register int unit;
456 {
457 	register struct siodevice *sio = sio_softc[unit].sc_pc->pc_addr;
458 	register u_char code;
459 	register struct tty *tp;
460 	int s, rr;
461 
462 	tp = &sio_tty[unit];
463 
464 start:
465 	rr = siogetreg(sio);
466 	if (rr & RR_RXRDY) {
467 		if (rr & (RR_FRAMING | RR_OVERRUN | RR_PARITY)) {
468 			sioeint(unit, rr, sio);
469 			goto start;
470 		}
471 
472 		code = sio->sio_data;
473 		if ((tp->t_state & TS_ISOPEN) != 0)
474 			(*linesw[tp->t_line].l_rint)(code, tp);
475 #ifdef KGDB
476 		else {
477 			if (code == FRAME_END &&
478 			    kgdb_dev == makedev(siomajor, unit))
479 				kgdb_connect(0); /* trap into kgdb */
480 		}
481 #endif
482 		while ((rr = siogetreg(sio)) & RR_RXRDY) {
483 			code = sio->sio_data;
484 			if ((tp->t_state & TS_ISOPEN) != 0)
485 				(*linesw[tp->t_line].l_rint)(code, tp);
486 #ifdef KGDB
487 			else {
488 				if (code == FRAME_END &&
489 				    kgdb_dev == makedev(siomajor, unit))
490 					kgdb_connect(0); /* trap into kgdb */
491 			}
492 #endif
493 		}
494 	}
495 
496 	if (rr & RR_TXRDY) {
497 		sio->sio_cmd = WR0_RSTPEND;
498 		tp->t_state &= ~(TS_BUSY|TS_FLUSH);
499 		if (tp->t_line)
500 			(*linesw[tp->t_line].l_start)(tp);
501 		else
502 			siostart(tp);
503 	}
504 }
505 
506 sioeint(unit, stat, sio)
507 	register int unit, stat;
508 	register struct siodevice *sio;
509 {
510 	register struct tty *tp;
511 	register int code;
512 
513 	tp = &sio_tty[unit];
514 
515 	code = sio->sio_data;
516 
517 	sio->sio_cmd = WR0_ERRRST;
518 
519 	if ((tp->t_state & TS_ISOPEN) == 0) {
520 #ifdef KGDB
521 		/* we don't care about parity errors */
522 		if (((stat & (RR_FRAMING|RR_PARITY)) == RR_PARITY) &&
523 		    kgdb_dev == makedev(siomajor, unit) && code == FRAME_END)
524 			kgdb_connect(0); /* trap into kgdb */
525 #endif
526 		return;
527 	}
528 
529 	if (stat & RR_FRAMING)
530 		code |= TTY_FE;
531 	else if (stat & RR_PARITY)
532 		code |= TTY_PE;
533 
534 	(*linesw[tp->t_line].l_rint)(code, tp);
535 }
536 
537 /*
538  * Following are all routines needed for SIO to act as console
539  */
540 #include <luna68k/luna68k/cons.h>
541 
542 siocnprobe(cp)
543 	register struct consdev *cp;
544 {
545 	register int unit = 0;
546 
547 	/* locate the major number */
548 	for (siomajor = 0; siomajor < nchrdev; siomajor++)
549 		if (cdevsw[siomajor].d_open == sioopen)
550 			break;
551 
552 	/* initialize required fields */
553 	cp->cn_dev = makedev(siomajor, unit);
554 	cp->cn_tp  = &sio_tty[unit];
555 	cp->cn_pri = CN_NORMAL;
556 }
557 
558 siocninit(cp)
559 	struct consdev *cp;
560 {
561 	int unit = siounit(cp->cn_dev);
562 	register struct sio_softc *sc = &sio_softc[unit];
563 
564 	sioinit((struct siodevice *) SIO_HARDADDR, siodefaultrate);
565 
566 	/* port assign */
567 	sc->sc_pc = sio_port_assign(SIO_PORT, siomajor, unit, siointr);
568 
569 	sioconsole = unit;
570 	sio_active |= 1 << unit;
571 	siosoftCAR |= 1 << unit;
572 }
573 
574 siocngetc(dev)
575 	dev_t dev;
576 {
577 	struct sio_softc *sc = &sio_softc[siounit(dev)];
578 	struct sio_portc *pc = sc->sc_pc;
579 
580 	return(sio_imgetc(pc->pc_addr));
581 }
582 
583 siocnputc(dev, c)
584 	dev_t dev;
585 	int c;
586 {
587 	struct sio_softc *sc = &sio_softc[siounit(dev)];
588 	struct sio_portc *pc = sc->sc_pc;
589 
590 	sio_imputc(pc->pc_addr, c);
591 }
592 
593 
594 /*
595  *  sio raw-level routines
596  */
597 
598 sioinit(sio0, rate)
599 	register struct siodevice *sio0;
600 	register int rate;
601 {
602 	register struct siodevice *sio1;
603 	int s;
604 
605 	rate = ttspeedtab(rate, siospeedtab);
606 
607 	if (sio_init_done)
608 		return;
609 
610 	sio1 = (struct siodevice *) ((u_long) sio0 + sizeof(struct siodevice));
611 
612 	s = splhigh();
613 
614 	sioreg(sio0, WR0,  WR0_CHANRST);		/* Channel-A Reset */
615 
616 	sioreg(sio0, WR2, (WR2_VEC86  | WR2_INTR_1));	/* Set CPU BUS Interface Mode */
617 	sioreg(sio1, WR2,  0);				/* Set Interrupt Vector */
618 
619 	sioreg(sio0, WR0,  WR0_RSTINT);		/* Reset E/S Interrupt */
620 	sioreg(sio0, WR4, (rate | WR4_STOP1 | WR4_NPARITY));	/* Tx/Rx */
621 	sioreg(sio0, WR3, (WR3_RX8BIT | WR3_RXENBL));		/* Rx */
622 	sioreg(sio0, WR5, (WR5_TX8BIT | WR5_TXENBL));		/* Tx */
623 	sioreg(sio0, WR0,  WR0_RSTINT);		/* Reset E/S Interrupt */
624 	sioreg(sio0, WR1, (WR1_RXALLS | WR1_TXENBL));
625 
626 	sioreg(sio1, WR0,  WR0_CHANRST);		/* Channel-B Reset */
627 
628 	sioreg(sio1, WR0,  WR0_RSTINT);		/* Reset E/S Interrupt */
629 	sioreg(sio1, WR4, (rate | WR4_STOP1 | WR4_NPARITY));	/* Tx/Rx */
630 	sioreg(sio1, WR3, (WR3_RX8BIT | WR3_RXENBL));		/* Rx */
631 	sioreg(sio1, WR5, (WR5_TX8BIT | WR5_TXENBL));		/* Tx */
632 	sioreg(sio1, WR0,  WR0_RSTINT);		/* Reset E/S Interrupt */
633 	sioreg(sio1, WR1, (WR1_RXALLS | WR1_TXENBL));
634 
635 	splx(s);
636 
637 	sio_init_done = 1;
638 }
639 
640 sio_imgetc(sio)
641 	register struct siodevice *sio;
642 {
643 	register int rr0, rr1;
644 	int c, s;
645 
646 	s = splhigh();
647 	while (((rr0 = sioreg(sio, RR0, 0)) & RR0_RXAVAIL) == 0)
648 		;
649 	c = sio->sio_data;
650 	sioreg(sio, WR0, WR0_RSTPEND);
651 	splx(s);
652 	return (c);
653 }
654 
655 sio_imputc(sio, c)
656 	register struct siodevice *sio;
657 	int c;
658 {
659 	register u_char code;
660 	register int rr;
661 	int s;
662 
663 	s = splhigh();
664 
665 	sioreg(sio, WR1, WR1_RXALLS);
666 
667 	do {
668 		DELAY(1);
669 		rr = siogetreg(sio);
670 	} while (!(rr & RR_TXRDY));
671 
672 	code = (c & 0xFF);
673 	sio->sio_data = code;
674 
675 	do {
676 		DELAY(1);
677 		rr = siogetreg(sio);
678 	} while (!(rr & RR_TXRDY));
679 
680 	sioreg(sio, WR1, (WR1_RXALLS | WR1_TXENBL));
681 
682 	splx(s);
683 }
684 
685 /*
686  *  uPD7201A register operation
687  */
688 
689 int
690 siogetreg(sio)
691 	register struct siodevice *sio;
692 {
693 	register int rr = 0;
694 
695 	rr = sio->sio_stat;
696 	rr <<= 8;
697 	sio->sio_cmd = 1;	/* Select RR1 */
698 	rr |= sio->sio_stat;
699 
700 	return(rr);
701 }
702 
703 int
704 sioreg(sio, reg, val)
705 	register struct siodevice *sio;
706 	register int reg, val;
707 {
708 	if (isStatusReg(reg)) {
709 		if (reg != 0)
710 		    sio->sio_cmd = reg;
711 		val = sio->sio_stat;
712 	} else {
713 		if (reg != 0)
714 		    sio->sio_cmd = reg;
715 		sio->sio_cmd = val;
716 	}
717 
718 	return(val);
719 }
720 #endif
721