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