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