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