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