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