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