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 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 * 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 * 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 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__ 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*/ 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 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 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*/ 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 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 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 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 430 siomctl() 431 { 432 return (0); 433 } 434 435 436 /* 437 * Interrupt handling 438 */ 439 440 void 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 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 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 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 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 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 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 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 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 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 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