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