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