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.1 (Berkeley) 06/15/92 12 */ 13 14 /* 15 * sio.c -- NEC uPD7201A UART Device Driver 16 * by A.Fujita, NOV-25-1991 17 */ 18 19 #include "sio.h" 20 #if NSIO > 0 21 22 #undef LOCAL_CONSOLE 23 24 /* 25 * OMRON LUNA internal serial interface 26 * uese NEC uPD7201A SIO 27 */ 28 29 #include "sys/param.h" 30 #include "sys/systm.h" 31 #include "sys/ioctl.h" 32 #include "sys/proc.h" 33 #include "sys/tty.h" 34 #include "sys/conf.h" 35 #include "sys/file.h" 36 #include "sys/uio.h" 37 #include "sys/kernel.h" 38 #include "sys/syslog.h" 39 40 #include "device.h" 41 #include "sioreg.h" 42 43 #define SIO_IPL 6 44 45 int sioprobe(); 46 struct driver siodriver = { 47 sioprobe, "sio", 48 }; 49 50 void siostart(); 51 int sioparam(), siointr(); 52 int sio_active; 53 int sioconsole = -1; 54 int sioconsinit; 55 int siodefaultrate = TTYDEF_SPEED; 56 int siomajor; 57 struct siodevice *sio_addr[2]; 58 struct tty sio_tty[NSIO]; 59 60 #define siounit(x) minor(x) 61 62 63 #ifndef LOCAL_CONSOLE 64 65 /* 66 * local buffering 67 */ 68 69 #define LOCAL_BUFSIZ 128 70 71 struct local_buf { 72 u_char *push; 73 u_char *pop; 74 u_char buf[LOCAL_BUFSIZ+4]; 75 }; 76 77 struct local_buf rbuf, *rbp = &rbuf; 78 79 80 siolbufinit(bp) 81 register struct local_buf *bp; 82 { 83 bp->push = bp->pop = &(bp->buf[LOCAL_BUFSIZ]); 84 } 85 86 siolbufpush(bp, c) 87 register struct local_buf *bp; 88 register int c; 89 { 90 91 *(--bp->push) = c; 92 93 if (bp->push == &(bp->buf[0])) 94 bp->push = &(bp->buf[LOCAL_BUFSIZ]); 95 96 if (bp->push == bp->pop) 97 bp->pop == (u_char *) 0; 98 } 99 100 int 101 siolbufpop(bp) 102 register struct local_buf *bp; 103 { 104 register int c; 105 106 if (bp->pop == (u_char *) 0) 107 bp->pop = bp->push; 108 109 c = *(--bp->pop); 110 111 if (bp->pop == &(bp->buf[0])) 112 bp->pop = &(bp->buf[LOCAL_BUFSIZ]); 113 114 return(c); 115 } 116 117 int 118 siolbufempty(bp) 119 register struct local_buf *bp; 120 { 121 if (bp->push == bp->pop) 122 return(1); 123 else 124 return(0); 125 } 126 #endif 127 128 /* 129 * probing 130 */ 131 132 sioprobe(hd) 133 register struct hp_device *hd; 134 { 135 register struct siodevice *sio; 136 register int unit; 137 138 sio = (struct siodevice *)hd->hp_addr; 139 unit = hd->hp_unit; 140 141 hd->hp_ipl = SIO_IPL; 142 143 /* 144 * We must set hardware address here. 145 * but now already it's done. 146 147 sio_addr[unit] = sio; 148 149 */ 150 151 sio_active |= 1 << unit; 152 153 /* 154 * We must pick up information from hd->hp_flags here. 155 * It should be used instead of TTYDEF_CFLAG or like something. 156 * 157 */ 158 159 #ifdef LOCAL_CONSOLE 160 161 /* 162 * Enable Interrupt 163 * I must rewirte basic handlers of console support, 164 * Because it does not work, if interrupt occar. 165 * Now using LOCAL_CONSOLE, so the problem isn't happend. 166 * 167 */ 168 169 sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL); 170 171 #endif 172 if (unit == sioconsole) { 173 sioconsinit = 0; 174 } 175 176 return (1); 177 } 178 179 int 180 /* ARGSUSED */ 181 #ifdef __STDC__ 182 sioopen(dev_t dev, int flag, int mode, struct proc *p) 183 #else 184 sioopen(dev, flag, mode, p) 185 dev_t dev; 186 int flag, mode; 187 struct proc *p; 188 #endif 189 { 190 register struct tty *tp; 191 register int unit; 192 int error = 0; 193 194 unit = siounit(dev); 195 if (unit >= NSIO || (sio_active & (1 << unit)) == 0) 196 return (ENXIO); 197 198 tp = &sio_tty[unit]; 199 tp->t_oproc = siostart; 200 tp->t_param = sioparam; 201 tp->t_dev = dev; 202 203 if ((tp->t_state & TS_ISOPEN) == 0) { 204 tp->t_state |= TS_WOPEN; 205 ttychars(tp); 206 if (tp->t_ispeed == 0) { 207 tp->t_iflag = TTYDEF_IFLAG; 208 tp->t_oflag = TTYDEF_OFLAG; 209 tp->t_cflag = (CREAD | CS8 | HUPCL); 210 tp->t_lflag = TTYDEF_LFLAG; 211 tp->t_ispeed = tp->t_ospeed = siodefaultrate; 212 } 213 sioparam(tp, &tp->t_termios); 214 ttsetwater(tp); 215 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 216 return (EBUSY); 217 218 /* 219 * We must set DTR & RTS here. 220 * Need a routine like XXXmctl(). 221 * 222 */ 223 224 /* 225 * The next statment should be executed, when Carrier Detected 226 * or using special serial line which ignore carrier. 227 * 228 * Should be checked out RR0, I think. Omit this time. 229 */ 230 231 tp->t_state |= TS_CARR_ON; 232 233 (void) spltty(); 234 235 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 236 (tp->t_state & TS_CARR_ON) == 0) { 237 tp->t_state |= TS_WOPEN; 238 if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, 239 ttopen, 0)) 240 break; 241 } 242 243 (void) spl0(); 244 245 if (error == 0) 246 error = (*linesw[tp->t_line].l_open)(dev, tp); 247 248 return (error); 249 } 250 251 /*ARGSUSED*/ 252 sioclose(dev, flag, mode, p) 253 dev_t dev; 254 int flag, mode; 255 struct proc *p; 256 { 257 register struct tty *tp; 258 register struct siodevice *sio; 259 register int unit; 260 261 unit = siounit(dev); 262 sio = sio_addr[unit]; 263 tp = &sio_tty[unit]; 264 265 (*linesw[tp->t_line].l_close)(tp, flag); 266 267 /* 268 * We must send BREAK to current line here. 269 * Not supported yet. 270 */ 271 272 /* 273 * We must reset DTR & RTS here. 274 * Need a routine like XXXmctl(). 275 * 276 */ 277 278 ttyclose(tp); 279 return (0); 280 } 281 282 sioread(dev, uio, flag) 283 dev_t dev; 284 struct uio *uio; 285 int flag; 286 { 287 register struct tty *tp = &sio_tty[siounit(dev)]; 288 289 return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); 290 } 291 292 siowrite(dev, uio, flag) 293 dev_t dev; 294 struct uio *uio; 295 int flag; 296 { 297 register struct tty *tp = &sio_tty[siounit(dev)]; 298 299 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 300 } 301 302 siointr() 303 { 304 register int unit = 0; 305 register struct siodevice *sio = sio_addr[unit]; 306 register u_char code; 307 register struct tty *tp; 308 int s, rr; 309 310 rr = siogetreg(unit); 311 tp = &sio_tty[unit]; 312 if (rr & RR_RXRDY) { 313 code = sio->sio_data; 314 if ((tp->t_state & TS_ISOPEN) != 0) 315 (*linesw[tp->t_line].l_rint)(code, tp); 316 #ifndef LOCAL_CONSOLE 317 else 318 siolbufpush(rbp, code); 319 #endif 320 } 321 322 if (rr & RR_TXRDY) { 323 sio->sio_cmd = WR0_RSTPEND; 324 tp->t_state &= ~(TS_BUSY|TS_FLUSH); 325 if (tp->t_line) 326 (*linesw[tp->t_line].l_start)(tp); 327 else 328 siostart(tp); 329 } 330 } 331 332 sioioctl(dev, cmd, data, flag, p) 333 dev_t dev; 334 int cmd; 335 caddr_t data; 336 int flag; 337 struct proc *p; 338 { 339 register struct tty *tp; 340 register int unit = siounit(dev); 341 register struct siodevice *sio; 342 register int error; 343 344 tp = &sio_tty[unit]; 345 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 346 if (error >= 0) 347 return (error); 348 error = ttioctl(tp, cmd, data, flag); 349 if (error >= 0) 350 return (error); 351 352 /* 353 * We must support flow control of serial lines. 354 * Not yet. 355 */ 356 357 sio = sio_addr[unit]; 358 switch (cmd) { 359 360 case TIOCSBRK: 361 case TIOCCBRK: 362 case TIOCSDTR: 363 case TIOCCDTR: 364 case TIOCMSET: 365 case TIOCMBIS: 366 case TIOCMBIC: 367 case TIOCMGET: 368 default: 369 return (ENOTTY); 370 } 371 372 return (0); 373 } 374 375 sioparam(tp, t) 376 register struct tty *tp; 377 register struct termios *t; 378 { 379 return (0); 380 } 381 382 void 383 siostart(tp) 384 register struct tty *tp; 385 { 386 register struct siodevice *sio; 387 int s, unit, c, rr; 388 389 unit = siounit(tp->t_dev); 390 sio = sio_addr[unit]; 391 392 s = spltty(); 393 394 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 395 goto out; 396 397 if (tp->t_outq.c_cc <= tp->t_lowat) { 398 if (tp->t_state&TS_ASLEEP) { 399 tp->t_state &= ~TS_ASLEEP; 400 wakeup((caddr_t)&tp->t_outq); 401 } 402 selwakeup(&tp->t_wsel); 403 } 404 405 if (tp->t_outq.c_cc == 0) 406 goto out; 407 408 rr = siogetreg(unit); 409 if (rr & RR_TXRDY) { 410 c = getc(&tp->t_outq); 411 tp->t_state |= TS_BUSY; 412 sio->sio_data = c; 413 } 414 415 out: 416 splx(s); 417 } 418 419 /* 420 * Stop output on a line. 421 */ 422 /*ARGSUSED*/ 423 siostop(tp, flag) 424 register struct tty *tp; 425 int flag; 426 { 427 register int s; 428 429 s = spltty(); 430 if (tp->t_state & TS_BUSY) { 431 if ((tp->t_state&TS_TTSTOP)==0) 432 tp->t_state |= TS_FLUSH; 433 } 434 splx(s); 435 } 436 437 /* 438 * Following are all routines needed for SIO to act as console 439 */ 440 #include "../luna68k/cons.h" 441 442 siocnprobe(cp) 443 struct consdev *cp; 444 { 445 int unit; 446 447 /* Line Selection: 0: Channel-A (ttya), 1: Channel-B (keyboard) */ 448 unit = 0; 449 450 /* locate the major number */ 451 for (siomajor = 0; siomajor < nchrdev; siomajor++) 452 if (cdevsw[siomajor].d_open == sioopen) 453 break; 454 455 sio_addr[0] = (struct siodevice *) 0x51000000; 456 sio_addr[1] = (struct siodevice *) 0x51000004; 457 458 /* make sure hardware exists */ 459 if (badaddr((short *)sio_addr[0])) { 460 cp->cn_pri = CN_DEAD; 461 return; 462 } 463 464 /* locate the major number */ 465 466 /* initialize required fields */ 467 cp->cn_dev = makedev(siomajor, unit); 468 cp->cn_tp = 0; 469 cp->cn_pri = CN_NORMAL; 470 } 471 472 siocninit(cp) 473 struct consdev *cp; 474 { 475 int unit = siounit(cp->cn_dev); 476 477 sioinit(unit); 478 sioconsole = unit; 479 } 480 481 /* 482 * Routines for Console Support 483 */ 484 485 486 #ifdef LOCAL_CONSOLE 487 488 int local_console; 489 490 siocngetc(dev) 491 dev_t dev; 492 { 493 int c, rr0, rr1; 494 int unit; 495 int s; 496 497 unit = local_console; 498 499 s = splhigh(); 500 loop: 501 while (((rr0 = sioreg(REG(unit, RR0), 0)) & RR0_RXAVAIL) == 0); 502 rr1 = sioreg(REG(unit, RR1), 0); 503 c = sio_addr[unit]->sio_data; 504 505 if ((rr0 & RR0_BREAK) == RR0_BREAK) /* Break Detected */ 506 goto loop; 507 508 if ((rr1 & RR1_OVERRUN) == RR1_OVERRUN) { /* Data Over Run */ 509 sioreg(REG(unit, WR0), WR0_ERRRST); 510 goto loop; 511 } 512 513 if ((rr1 & RR1_PARITY) == RR1_PARITY) { /* Parity Error */ 514 sioreg(REG(unit, WR0), WR0_ERRRST); 515 goto loop; 516 } 517 518 if ((rr1 & RR1_FRAMING) == RR1_FRAMING) { /* Framing Error */ 519 sioreg(REG(unit, WR0), WR0_ERRRST); 520 goto loop; 521 } 522 523 sioreg(REG(unit, WR0), WR0_RSTPEND); 524 splx(s); 525 return(c); 526 } 527 528 siocnputc(dev, c) 529 dev_t dev; 530 int c; 531 { 532 int unit; 533 int s; 534 535 unit = local_console; 536 537 if (sioconsole == -1) { 538 (void) sioinit(unit); 539 sioconsole = unit; 540 } 541 542 s = splhigh(); 543 544 /* wait for any pending transmission to finish */ 545 while ((sioreg(REG(unit, RR0), 0) & RR0_TXEMPTY) == 0); 546 547 sio_addr[unit]->sio_data = (c & 0xFF); 548 549 /* wait for any pending transmission to finish */ 550 while ((sioreg(REG(unit, RR0), 0) & RR0_TXEMPTY) == 0); 551 552 splx(s); 553 } 554 555 sioinit(unit) 556 int unit; 557 { 558 int s; 559 560 s = splhigh(); 561 562 sioreg(REG(unit, WR0), WR0_CHANRST); /* Channel-A Reset */ 563 sioreg(WR2A, WR2_VEC86 | WR2_INTR_1); /* Set CPU BUS Interface Mode */ 564 sioreg(WR2B, 0); /* Set Interrupt Vector */ 565 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 566 sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY); /* Tx/Rx */ 567 sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL); /* Rx */ 568 sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL); /* Tx */ 569 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 570 571 unit = local_console = 1 - unit; 572 573 sioreg(REG(unit, WR0), WR0_CHANRST); /* Channel-B Reset */ 574 575 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 576 sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY); /* Tx/Rx */ 577 sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL); /* Rx */ 578 sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL); /* Tx */ 579 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 580 581 splx(s); 582 } 583 #else 584 585 /* 586 * console put & get 587 */ 588 589 siocngetc(dev) 590 dev_t dev; 591 { 592 while (siolbufempty(rbp)) 593 DELAY(10); 594 595 return(siolbufpop(rbp)); 596 } 597 598 siocnputc(dev, c) 599 dev_t dev; 600 int c; 601 { 602 register int unit = siounit(dev); 603 register struct siodevice *sio = sio_addr[unit]; 604 register u_char code; 605 int s, rr; 606 607 s = splhigh(); 608 sioreg(REG(unit, WR1), WR1_RXALLS); 609 610 do { 611 DELAY(1); 612 rr = siogetreg(unit); 613 } while (!(rr & RR_TXRDY)); 614 615 code = (c & 0xff); 616 sio->sio_data = code; 617 618 do { 619 DELAY(1); 620 rr = siogetreg(unit); 621 } while (!(rr & RR_TXRDY)); 622 623 sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL); 624 splx(s); 625 } 626 627 sioinit(unit) 628 int unit; 629 { 630 int s; 631 632 siolbufinit(rbp); 633 634 s = splhigh(); 635 636 unit = 0; 637 638 sioreg(REG(unit, WR0), WR0_CHANRST); /* Channel-A Reset */ 639 sioreg(WR2A, WR2_VEC86 | WR2_INTR_1); /* Set CPU BUS Interface Mode */ 640 sioreg(WR2B, 0); /* Set Interrupt Vector */ 641 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 642 sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY); /* Tx/Rx */ 643 sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL); /* Rx */ 644 sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL); /* Tx */ 645 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 646 sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL); 647 648 unit = 1; 649 650 sioreg(REG(unit, WR0), WR0_CHANRST); /* Channel-A Reset */ 651 652 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 653 sioreg(REG(unit, WR4), WR4_BAUD96 | WR4_STOP1 | WR4_NPARITY); /* Tx/Rx */ 654 sioreg(REG(unit, WR3), WR3_RX8BIT | WR3_RXENBL); /* Rx */ 655 sioreg(REG(unit, WR5), WR5_TX8BIT | WR5_TXENBL); /* Tx */ 656 sioreg(REG(unit, WR0), WR0_RSTINT); /* Reset E/S Interrupt */ 657 sioreg(REG(unit, WR1), WR1_RXALLS | WR1_TXENBL); 658 659 splx(s); 660 } 661 #endif 662 663 int 664 siogetreg(unit) 665 register int unit; 666 { 667 register struct siodevice *sio = sio_addr[unit]; 668 register int rr = 0; 669 670 rr = sio->sio_stat; 671 rr <<= 8; 672 sio->sio_cmd = 1; /* Select RR1 */ 673 rr |= sio->sio_stat; 674 675 return(rr); 676 } 677 678 int 679 sioreg(reg, val) 680 register int reg, val; 681 { 682 register int chan; 683 684 chan = CHANNEL(reg); 685 686 if (isStatusReg(reg)) { 687 if (REGNO(reg) != 0) 688 sio_addr[chan]->sio_cmd = REGNO(reg); 689 return(sio_addr[chan]->sio_stat); 690 } else { 691 if (REGNO(reg) != 0) 692 sio_addr[chan]->sio_cmd = REGNO(reg); 693 sio_addr[chan]->sio_cmd = val; 694 return(val); 695 } 696 } 697 #endif 698