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