xref: /original-bsd/sys/luna68k/dev/sio.c (revision 088910ec)
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.1 (Berkeley) 06/15/92
12  */
13 
14 /*
15  * sio.c -- NEC uPD7201A UART Device Driver
16  * by A.Fujita, NOV-25-1991
17  */
18 
19 #include "sio.h"
20 #if NSIO > 0
21 
22 #undef LOCAL_CONSOLE
23 
24 /*
25  *  OMRON LUNA internal serial interface
26  *  uese NEC uPD7201A SIO
27  */
28 
29 #include "sys/param.h"
30 #include "sys/systm.h"
31 #include "sys/ioctl.h"
32 #include "sys/proc.h"
33 #include "sys/tty.h"
34 #include "sys/conf.h"
35 #include "sys/file.h"
36 #include "sys/uio.h"
37 #include "sys/kernel.h"
38 #include "sys/syslog.h"
39 
40 #include "device.h"
41 #include "sioreg.h"
42 
43 #define SIO_IPL		6
44 
45 int	sioprobe();
46 struct	driver siodriver = {
47 	sioprobe, "sio",
48 };
49 
50 void	siostart();
51 int	sioparam(), siointr();
52 int	sio_active;
53 int	sioconsole = -1;
54 int	sioconsinit;
55 int	siodefaultrate = TTYDEF_SPEED;
56 int	siomajor;
57 struct	siodevice *sio_addr[2];
58 struct	tty sio_tty[NSIO];
59 
60 #define	siounit(x)		minor(x)
61 
62 
63 #ifndef	LOCAL_CONSOLE
64 
65 /*
66  * local buffering
67  */
68 
69 #define LOCAL_BUFSIZ	128
70 
71 struct local_buf {
72 	u_char	*push;
73 	u_char	*pop;
74 	u_char	buf[LOCAL_BUFSIZ+4];
75 };
76 
77 struct local_buf rbuf, *rbp = &rbuf;
78 
79 
80 siolbufinit(bp)
81 	register struct local_buf *bp;
82 {
83 	bp->push = bp->pop = &(bp->buf[LOCAL_BUFSIZ]);
84 }
85 
86 siolbufpush(bp, c)
87 	register struct local_buf *bp;
88 	register int c;
89 {
90 
91 	*(--bp->push) = c;
92 
93 	if (bp->push == &(bp->buf[0]))
94 		bp->push = &(bp->buf[LOCAL_BUFSIZ]);
95 
96 	if (bp->push == bp->pop)
97 		bp->pop == (u_char *) 0;
98 }
99 
100 int
101 siolbufpop(bp)
102 	register struct local_buf *bp;
103 {
104 	register int c;
105 
106 	if (bp->pop == (u_char *) 0)
107 		bp->pop = bp->push;
108 
109 	c = *(--bp->pop);
110 
111 	if (bp->pop == &(bp->buf[0]))
112 		bp->pop = &(bp->buf[LOCAL_BUFSIZ]);
113 
114 	return(c);
115 }
116 
117 int
118 siolbufempty(bp)
119 	register struct local_buf *bp;
120 {
121 	if (bp->push == bp->pop)
122 		return(1);
123 	else
124 		return(0);
125 }
126 #endif
127 
128 /*
129  * probing
130  */
131 
132 sioprobe(hd)
133 	register struct hp_device *hd;
134 {
135 	register struct siodevice *sio;
136 	register int unit;
137 
138 	sio = (struct siodevice *)hd->hp_addr;
139 	unit = hd->hp_unit;
140 
141 	hd->hp_ipl = SIO_IPL;
142 
143 	/*
144 	 *  We must set hardware address here.
145 	 *  but now already it's done.
146 
147 	sio_addr[unit] = sio;
148 
149 	*/
150 
151 	sio_active |= 1 << unit;
152 
153 	/*
154 	 *  We must pick up information from hd->hp_flags here.
155 	 *  It should be used instead of TTYDEF_CFLAG or like something.
156 	 *
157 	 */
158 
159 #ifdef LOCAL_CONSOLE
160 
161 	/*
162 	 *  Enable Interrupt
163 	 *    I must rewirte basic handlers of console support,
164 	 *    Because it does not work, if interrupt occar.
165 	 *    Now using LOCAL_CONSOLE, so the problem isn't happend.
166 	 *
167 	 */
168 
169 	sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL);
170 
171 #endif
172 	if (unit == sioconsole) {
173 		sioconsinit = 0;
174 	}
175 
176 	return (1);
177 }
178 
179 int
180 /* ARGSUSED */
181 #ifdef __STDC__
182 sioopen(dev_t dev, int flag, int mode, struct proc *p)
183 #else
184 sioopen(dev, flag, mode, p)
185 	dev_t dev;
186 	int flag, mode;
187 	struct proc *p;
188 #endif
189 {
190 	register struct tty *tp;
191 	register int unit;
192 	int error = 0;
193 
194 	unit = siounit(dev);
195 	if (unit >= NSIO || (sio_active & (1 << unit)) == 0)
196 		return (ENXIO);
197 
198 	tp = &sio_tty[unit];
199 	tp->t_oproc = siostart;
200 	tp->t_param = sioparam;
201 	tp->t_dev = dev;
202 
203 	if ((tp->t_state & TS_ISOPEN) == 0) {
204 		tp->t_state |= TS_WOPEN;
205 		ttychars(tp);
206 		if (tp->t_ispeed == 0) {
207 			tp->t_iflag = TTYDEF_IFLAG;
208 			tp->t_oflag = TTYDEF_OFLAG;
209 			tp->t_cflag = (CREAD | CS8 | HUPCL);
210 			tp->t_lflag = TTYDEF_LFLAG;
211 			tp->t_ispeed = tp->t_ospeed = siodefaultrate;
212 		}
213 		sioparam(tp, &tp->t_termios);
214 		ttsetwater(tp);
215 	} else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
216 		return (EBUSY);
217 
218 	/*
219 	 *  We must set DTR & RTS here.
220 	 *  Need a routine like XXXmctl().
221 	 *
222 	 */
223 
224 	/*
225 	 *  The next statment should be executed, when Carrier Detected
226 	 *  or using special serial line which ignore carrier.
227 	 *
228 	 *  Should be checked out RR0, I think. Omit this time.
229 	 */
230 
231 	 tp->t_state |= TS_CARR_ON;
232 
233 	(void) spltty();
234 
235 	while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 &&
236 	       (tp->t_state & TS_CARR_ON) == 0) {
237 		tp->t_state |= TS_WOPEN;
238 		if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
239 		    ttopen, 0))
240 			break;
241 	}
242 
243 	(void) spl0();
244 
245 	if (error == 0)
246 		error = (*linesw[tp->t_line].l_open)(dev, tp);
247 
248 	return (error);
249 }
250 
251 /*ARGSUSED*/
252 sioclose(dev, flag, mode, p)
253 	dev_t dev;
254 	int flag, mode;
255 	struct proc *p;
256 {
257 	register struct tty *tp;
258 	register struct siodevice *sio;
259 	register int unit;
260 
261 	unit = siounit(dev);
262 	sio = sio_addr[unit];
263 	tp = &sio_tty[unit];
264 
265 	(*linesw[tp->t_line].l_close)(tp, flag);
266 
267 	/*
268 	 *  We must send BREAK to current line here.
269 	 *  Not supported yet.
270 	 */
271 
272 	/*
273 	 *  We must reset DTR & RTS here.
274 	 *  Need a routine like XXXmctl().
275 	 *
276 	 */
277 
278 	ttyclose(tp);
279 	return (0);
280 }
281 
282 sioread(dev, uio, flag)
283 	dev_t dev;
284 	struct uio *uio;
285 	int flag;
286 {
287 	register struct tty *tp = &sio_tty[siounit(dev)];
288 
289 	return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
290 }
291 
292 siowrite(dev, uio, flag)
293 	dev_t dev;
294 	struct uio *uio;
295 	int flag;
296 {
297 	register struct tty *tp = &sio_tty[siounit(dev)];
298 
299 	return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
300 }
301 
302 siointr()
303 {
304 	register int unit = 0;
305 	register struct siodevice *sio = sio_addr[unit];
306 	register u_char code;
307 	register struct tty *tp;
308 	int s, rr;
309 
310 	rr = siogetreg(unit);
311 	tp = &sio_tty[unit];
312 	if (rr & RR_RXRDY) {
313 		code = sio->sio_data;
314 		if ((tp->t_state & TS_ISOPEN) != 0)
315 			(*linesw[tp->t_line].l_rint)(code, tp);
316 #ifndef LOCAL_CONSOLE
317 		else
318 			siolbufpush(rbp, code);
319 #endif
320 	}
321 
322 	if (rr & RR_TXRDY) {
323 		sio->sio_cmd = WR0_RSTPEND;
324 		tp->t_state &= ~(TS_BUSY|TS_FLUSH);
325 		if (tp->t_line)
326 			(*linesw[tp->t_line].l_start)(tp);
327 		else
328 			siostart(tp);
329 	}
330 }
331 
332 sioioctl(dev, cmd, data, flag, p)
333 	dev_t dev;
334 	int cmd;
335 	caddr_t data;
336 	int flag;
337 	struct proc *p;
338 {
339 	register struct tty *tp;
340 	register int unit = siounit(dev);
341 	register struct siodevice *sio;
342 	register int error;
343 
344 	tp = &sio_tty[unit];
345 	error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
346 	if (error >= 0)
347 		return (error);
348 	error = ttioctl(tp, cmd, data, flag);
349 	if (error >= 0)
350 		return (error);
351 
352 	/*
353 	 *  We must support flow control of serial lines.
354 	 *  Not yet.
355 	 */
356 
357 	sio = sio_addr[unit];
358 	switch (cmd) {
359 
360 	case TIOCSBRK:
361 	case TIOCCBRK:
362 	case TIOCSDTR:
363 	case TIOCCDTR:
364 	case TIOCMSET:
365 	case TIOCMBIS:
366 	case TIOCMBIC:
367 	case TIOCMGET:
368 	default:
369 		return (ENOTTY);
370 	}
371 
372 	return (0);
373 }
374 
375 sioparam(tp, t)
376 	register struct tty *tp;
377 	register struct termios *t;
378 {
379 	return (0);
380 }
381 
382 void
383 siostart(tp)
384 	register struct tty *tp;
385 {
386 	register struct siodevice *sio;
387 	int s, unit, c, rr;
388 
389 	unit = siounit(tp->t_dev);
390 	sio = sio_addr[unit];
391 
392 	s = spltty();
393 
394 	if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP))
395 		goto out;
396 
397 	if (tp->t_outq.c_cc <= tp->t_lowat) {
398 		if (tp->t_state&TS_ASLEEP) {
399 			tp->t_state &= ~TS_ASLEEP;
400 			wakeup((caddr_t)&tp->t_outq);
401 		}
402 		selwakeup(&tp->t_wsel);
403 	}
404 
405 	if (tp->t_outq.c_cc == 0)
406 		goto out;
407 
408 	rr = siogetreg(unit);
409 	if (rr & RR_TXRDY) {
410 		c = getc(&tp->t_outq);
411 		tp->t_state |= TS_BUSY;
412 		sio->sio_data = c;
413 	}
414 
415 out:
416 	splx(s);
417 }
418 
419 /*
420  * Stop output on a line.
421  */
422 /*ARGSUSED*/
423 siostop(tp, flag)
424 	register struct tty *tp;
425 	int flag;
426 {
427 	register int s;
428 
429 	s = spltty();
430 	if (tp->t_state & TS_BUSY) {
431 		if ((tp->t_state&TS_TTSTOP)==0)
432 			tp->t_state |= TS_FLUSH;
433 	}
434 	splx(s);
435 }
436 
437 /*
438  * Following are all routines needed for SIO to act as console
439  */
440 #include "../luna68k/cons.h"
441 
442 siocnprobe(cp)
443 	struct consdev *cp;
444 {
445 	int unit;
446 
447 	/* Line Selection: 0: Channel-A (ttya),  1: Channel-B (keyboard) */
448 	unit = 0;
449 
450 	/* locate the major number */
451 	for (siomajor = 0; siomajor < nchrdev; siomajor++)
452 		if (cdevsw[siomajor].d_open == sioopen)
453 			break;
454 
455 	sio_addr[0] = (struct siodevice *) 0x51000000;
456 	sio_addr[1] = (struct siodevice *) 0x51000004;
457 
458 	/* make sure hardware exists */
459 	if (badaddr((short *)sio_addr[0])) {
460 		cp->cn_pri = CN_DEAD;
461 		return;
462 	}
463 
464 	/* locate the major number */
465 
466 	/* initialize required fields */
467 	cp->cn_dev = makedev(siomajor, unit);
468 	cp->cn_tp  = 0;
469 	cp->cn_pri = CN_NORMAL;
470 }
471 
472 siocninit(cp)
473 	struct consdev *cp;
474 {
475 	int unit = siounit(cp->cn_dev);
476 
477 	sioinit(unit);
478 	sioconsole = unit;
479 }
480 
481 /*
482  * Routines for Console Support
483  */
484 
485 
486 #ifdef LOCAL_CONSOLE
487 
488 int local_console;
489 
490 siocngetc(dev)
491 	dev_t dev;
492 {
493 	int c, rr0, rr1;
494 	int unit;
495 	int s;
496 
497 	unit = local_console;
498 
499 	s = splhigh();
500 loop:
501 	while (((rr0 = sioreg(REG(unit, RR0), 0)) & RR0_RXAVAIL) == 0);
502 	rr1 = sioreg(REG(unit, RR1), 0);
503 	c = sio_addr[unit]->sio_data;
504 
505 	if ((rr0 & RR0_BREAK) == RR0_BREAK)		/* Break Detected */
506 		goto loop;
507 
508 	if ((rr1 & RR1_OVERRUN) == RR1_OVERRUN) {	/* Data Over Run */
509 		sioreg(REG(unit, WR0), WR0_ERRRST);
510 		goto loop;
511 	}
512 
513 	if ((rr1 & RR1_PARITY) == RR1_PARITY) {		/* Parity Error */
514 		sioreg(REG(unit, WR0), WR0_ERRRST);
515 		goto loop;
516 	}
517 
518 	if ((rr1 & RR1_FRAMING) == RR1_FRAMING) {	/* Framing Error */
519 		sioreg(REG(unit, WR0), WR0_ERRRST);
520 		goto loop;
521 	}
522 
523 	sioreg(REG(unit, WR0), WR0_RSTPEND);
524 	splx(s);
525 	return(c);
526 }
527 
528 siocnputc(dev, c)
529 	dev_t dev;
530 	int c;
531 {
532 	int unit;
533 	int s;
534 
535 	unit = local_console;
536 
537 	if (sioconsole == -1) {
538 		(void) sioinit(unit);
539 		sioconsole = unit;
540 	}
541 
542 	s = splhigh();
543 
544 	/* wait for any pending transmission to finish */
545 	while ((sioreg(REG(unit, RR0), 0) & RR0_TXEMPTY) == 0);
546 
547 	sio_addr[unit]->sio_data = (c & 0xFF);
548 
549 	/* wait for any pending transmission to finish */
550 	while ((sioreg(REG(unit, RR0), 0) & RR0_TXEMPTY) == 0);
551 
552 	splx(s);
553 }
554 
555 sioinit(unit)
556 	int unit;
557 {
558 	int s;
559 
560 	s = splhigh();
561 
562 	sioreg(REG(unit, WR0), WR0_CHANRST);		/* Channel-A Reset */
563 	sioreg(WR2A, WR2_VEC86  | WR2_INTR_1);		/* Set CPU BUS Interface Mode */
564 	sioreg(WR2B, 0);				/* Set Interrupt Vector */
565 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
566 	sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY);	/* Tx/Rx */
567 	sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL);		/* Rx */
568 	sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL);		/* Tx */
569 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
570 
571 	unit = local_console = 1 - unit;
572 
573 	sioreg(REG(unit, WR0), WR0_CHANRST);		/* Channel-B Reset */
574 
575 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
576 	sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY);	/* Tx/Rx */
577 	sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL);		/* Rx */
578 	sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL);		/* Tx */
579 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
580 
581 	splx(s);
582 }
583 #else
584 
585 /*
586  * console put & get
587  */
588 
589 siocngetc(dev)
590 	dev_t dev;
591 {
592 	while (siolbufempty(rbp))
593 		DELAY(10);
594 
595 	return(siolbufpop(rbp));
596 }
597 
598 siocnputc(dev, c)
599 	dev_t dev;
600 	int c;
601 {
602 	register int unit = siounit(dev);
603 	register struct siodevice *sio = sio_addr[unit];
604 	register u_char code;
605 	int s, rr;
606 
607 	s = splhigh();
608 	sioreg(REG(unit, WR1), WR1_RXALLS);
609 
610 	do {
611 		DELAY(1);
612 		rr = siogetreg(unit);
613 	} while (!(rr & RR_TXRDY));
614 
615 	code = (c & 0xff);
616 	sio->sio_data = code;
617 
618 	do {
619 		DELAY(1);
620 		rr = siogetreg(unit);
621 	} while (!(rr & RR_TXRDY));
622 
623 	sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL);
624 	splx(s);
625 }
626 
627 sioinit(unit)
628 	int unit;
629 {
630 	int s;
631 
632 	siolbufinit(rbp);
633 
634 	s = splhigh();
635 
636 	unit = 0;
637 
638 	sioreg(REG(unit, WR0), WR0_CHANRST);		/* Channel-A Reset */
639 	sioreg(WR2A, WR2_VEC86  | WR2_INTR_1);		/* Set CPU BUS Interface Mode */
640 	sioreg(WR2B, 0);				/* Set Interrupt Vector */
641 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
642 	sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY);	/* Tx/Rx */
643 	sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL);		/* Rx */
644 	sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL);		/* Tx */
645 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
646 	sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL);
647 
648 	unit = 1;
649 
650 	sioreg(REG(unit, WR0), WR0_CHANRST);		/* Channel-A Reset */
651 
652 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
653 	sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY);	/* Tx/Rx */
654 	sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL);		/* Rx */
655 	sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL);		/* Tx */
656 	sioreg(REG(unit, WR0), WR0_RSTINT);		/* Reset E/S Interrupt */
657 	sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL);
658 
659 	splx(s);
660 }
661 #endif
662 
663 int
664 siogetreg(unit)
665 	register int unit;
666 {
667 	register struct siodevice *sio = sio_addr[unit];
668 	register int rr = 0;
669 
670 	rr = sio->sio_stat;
671 	rr <<= 8;
672 	sio->sio_cmd = 1;	/* Select RR1 */
673 	rr |= sio->sio_stat;
674 
675 	return(rr);
676 }
677 
678 int
679 sioreg(reg, val)
680 	register int reg, val;
681 {
682 	register int chan;
683 
684 	chan = CHANNEL(reg);
685 
686 	if (isStatusReg(reg)) {
687 		if (REGNO(reg) != 0)
688 		    sio_addr[chan]->sio_cmd = REGNO(reg);
689 		return(sio_addr[chan]->sio_stat);
690 	} else {
691 		if (REGNO(reg) != 0)
692 		    sio_addr[chan]->sio_cmd = REGNO(reg);
693 		sio_addr[chan]->sio_cmd = val;
694 		return(val);
695 	}
696 }
697 #endif
698