1 /* $NetBSD: ser.c,v 1.53 2000/04/27 21:11:07 is Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)ser.c 7.12 (Berkeley) 6/27/91 36 */ 37 /* 38 * XXX This file needs major cleanup it will never service more than one 39 * XXX unit. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/ioctl.h> 45 #include <sys/device.h> 46 #include <sys/tty.h> 47 #include <sys/proc.h> 48 #include <sys/file.h> 49 #include <sys/malloc.h> 50 #include <sys/uio.h> 51 #include <sys/kernel.h> 52 #include <sys/syslog.h> 53 #include <sys/queue.h> 54 #include <machine/cpu.h> 55 #include <amiga/amiga/device.h> 56 #include <amiga/dev/serreg.h> 57 #include <amiga/amiga/custom.h> 58 #include <amiga/amiga/cia.h> 59 #include <amiga/amiga/cc.h> 60 61 #include <dev/cons.h> 62 63 #include <sys/conf.h> 64 #include <machine/conf.h> 65 66 #include "ser.h" 67 #if NSER > 0 68 69 void serattach __P((struct device *, struct device *, void *)); 70 int sermatch __P((struct device *, struct cfdata *, void *)); 71 72 struct ser_softc { 73 struct device dev; 74 struct tty *ser_tty; 75 }; 76 77 struct cfattach ser_ca = { 78 sizeof(struct ser_softc), sermatch, serattach 79 }; 80 81 extern struct cfdriver ser_cd; 82 83 #ifndef SEROBUF_SIZE 84 #define SEROBUF_SIZE 32 85 #endif 86 #ifndef SERIBUF_SIZE 87 #define SERIBUF_SIZE 512 88 #endif 89 90 #define splser() spl5() 91 92 void serstart __P((struct tty *)); 93 void ser_shutdown __P((struct ser_softc *)); 94 int serparam __P((struct tty *, struct termios *)); 95 void serintr __P((void)); 96 int serhwiflow __P((struct tty *, int)); 97 int sermctl __P((dev_t dev, int, int)); 98 void ser_fastint __P((void)); 99 void sereint __P((int)); 100 static void ser_putchar __P((struct tty *, u_short)); 101 void ser_outintr __P((void)); 102 void sercnprobe __P((struct consdev *)); 103 void sercninit __P((struct consdev *)); 104 void serinit __P((int)); 105 int sercngetc __P((dev_t dev)); 106 void sercnputc __P((dev_t, int)); 107 void sercnpollc __P((dev_t, int)); 108 109 int nser = NSER; 110 #ifdef SERCONSOLE 111 int serconsole = SERCONSOLE; 112 #else 113 int serconsole = -1; 114 #endif 115 int serconsinit; 116 int serdefaultrate = TTYDEF_SPEED; 117 int sermajor; 118 int serswflags; 119 120 struct vbl_node ser_vbl_node; 121 struct tty ser_cons; 122 struct tty *ser_tty; 123 124 static u_short serbuf[SERIBUF_SIZE]; 125 static u_short *sbrpt = serbuf; 126 static u_short *sbwpt = serbuf; 127 static u_short sbcnt; 128 static u_short sbovfl; 129 static u_char serdcd; 130 131 /* 132 * Since this UART is not particularly bright (to put it nicely), we'll 133 * have to do parity stuff on our own. This table contains the 8th bit 134 * in 7bit character mode, for even parity. If you want odd parity, 135 * flip the bit. (for generation of the table, see genpar.c) 136 */ 137 138 u_char even_parity[] = { 139 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 140 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 141 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 142 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 143 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 144 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 145 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 146 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 147 }; 148 149 /* 150 * Since we don't get interrupts for changes on the modem control line, 151 * we'll have to fake them by comparing current settings to the settings 152 * we remembered on last invocation. 153 */ 154 155 u_char last_ciab_pra; 156 157 extern struct tty *constty; 158 159 extern int ser_open_speed; /* current speed of open serial device */ 160 161 #ifdef KGDB 162 #include <machine/remote-sl.h> 163 164 extern dev_t kgdb_dev; 165 extern int kgdb_rate; 166 extern int kgdb_debug_init; 167 #endif 168 169 #ifdef DEBUG 170 long fifoin[17]; 171 long fifoout[17]; 172 long serintrcount[16]; 173 long sermintcount[16]; 174 #endif 175 176 void sermint __P((register int unit)); 177 178 int 179 sermatch(pdp, cfp, auxp) 180 struct device *pdp; 181 struct cfdata *cfp; 182 void *auxp; 183 { 184 static int ser_matched = 0; 185 static int ser_matched_real = 0; 186 187 /* Allow only once instance. */ 188 if (matchname("ser", (char *)auxp) == 0) 189 return(0); 190 191 if (amiga_realconfig) { 192 if (ser_matched_real) 193 return(0); 194 ser_matched_real = 1; 195 } else { 196 if (serconsole != 0) 197 return(0); 198 199 if (ser_matched != 0) 200 return(0); 201 202 ser_matched = 1; 203 } 204 return(1); 205 } 206 207 208 void 209 serattach(pdp, dp, auxp) 210 struct device *pdp, *dp; 211 void *auxp; 212 { 213 struct ser_softc *sc; 214 struct tty *tp; 215 u_short ir; 216 217 sc = (struct ser_softc *)dp; 218 219 ir = custom.intenar; 220 if (serconsole == 0) 221 DELAY(100000); 222 223 ser_vbl_node.function = (void (*) (void *)) sermint; 224 add_vbl_function(&ser_vbl_node, SER_VBL_PRIORITY, (void *) 0); 225 #ifdef KGDB 226 if (kgdb_dev == makedev(sermajor, 0)) { 227 if (serconsole == 0) 228 kgdb_dev = NODEV; /* can't debug over console port */ 229 else { 230 (void) serinit(kgdb_rate); 231 serconsinit = 1; /* don't re-init in serputc */ 232 if (kgdb_debug_init == 0) 233 printf(" kgdb enabled\n"); 234 else { 235 /* 236 * Print prefix of device name, 237 * let kgdb_connect print the rest. 238 */ 239 printf("ser0: "); 240 kgdb_connect(1); 241 } 242 } 243 } 244 #endif 245 /* 246 * Need to reset baud rate, etc. of next print so reset serconsinit. 247 */ 248 if (0 == serconsole) 249 serconsinit = 0; 250 251 tp = ttymalloc(); 252 tp->t_oproc = (void (*) (struct tty *)) serstart; 253 tp->t_param = serparam; 254 tp->t_hwiflow = serhwiflow; 255 tty_attach(tp); 256 sc->ser_tty = ser_tty = tp; 257 258 if (dp) 259 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE, 260 SEROBUF_SIZE); 261 } 262 263 264 /* ARGSUSED */ 265 int 266 seropen(dev, flag, mode, p) 267 dev_t dev; 268 int flag, mode; 269 struct proc *p; 270 { 271 struct ser_softc *sc; 272 struct tty *tp; 273 int unit, error, s, s2; 274 275 error = 0; 276 unit = SERUNIT(dev); 277 278 if (unit >= ser_cd.cd_ndevs) 279 return (ENXIO); 280 281 sc = ser_cd.cd_devs[unit]; 282 if (sc == 0) 283 return (ENXIO); 284 285 /* XXX com.c: insert KGDB check here */ 286 287 /* XXX ser.c had: s = spltty(); */ 288 289 tp = sc->ser_tty; 290 291 if ((tp->t_state & TS_ISOPEN) && 292 (tp->t_state & TS_XCLUDE) && 293 p->p_ucred->cr_uid != 0) 294 return (EBUSY); 295 296 s = spltty(); 297 298 /* 299 * If this is a first open... 300 */ 301 302 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 303 struct termios t; 304 305 tp->t_dev = dev; 306 307 s2 = splser(); 308 /* 309 * XXX here: hw enable, 310 */ 311 last_ciab_pra = ciab.pra; 312 313 splx(s2); 314 t.c_ispeed = 0; 315 316 /* XXX serconsolerate? */ 317 t.c_ospeed = TTYDEF_SPEED; 318 t.c_cflag = TTYDEF_CFLAG; 319 320 if (serswflags & TIOCFLAG_CLOCAL) 321 t.c_cflag |= CLOCAL; 322 if (serswflags & TIOCFLAG_CRTSCTS) 323 t.c_cflag |= CRTSCTS; 324 if (serswflags & TIOCFLAG_MDMBUF) 325 t.c_cflag |= MDMBUF; 326 327 /* Make sure serparam() will do something. */ 328 tp->t_ospeed = 0; 329 serparam(tp, &t); 330 tp->t_iflag = TTYDEF_IFLAG; 331 tp->t_oflag = TTYDEF_OFLAG; 332 tp->t_lflag = TTYDEF_LFLAG; 333 ttychars(tp); 334 ttsetwater(tp); 335 336 s2 = splser(); 337 (void)sermctl(dev, TIOCM_DTR, DMSET); 338 /* clear input ring */ 339 sbrpt = sbwpt = serbuf; 340 sbcnt = 0; 341 splx(s2); 342 } 343 344 splx(s); 345 346 error = ttyopen(tp, DIALOUT(dev), flag & O_NONBLOCK); 347 if (error) 348 goto bad; 349 350 error = (*linesw[tp->t_line].l_open)(dev, tp); 351 if (error) 352 goto bad; 353 354 return (0); 355 356 bad: 357 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 358 ser_shutdown(sc); 359 } 360 361 return (error); 362 } 363 364 /*ARGSUSED*/ 365 int 366 serclose(dev, flag, mode, p) 367 dev_t dev; 368 int flag, mode; 369 struct proc *p; 370 { 371 struct ser_softc *sc; 372 struct tty *tp; 373 374 sc = ser_cd.cd_devs[0]; 375 tp = ser_tty; 376 377 /* XXX This is for cons.c, according to com.c */ 378 if (!(tp->t_state & TS_ISOPEN)) 379 return (0); 380 381 (*linesw[tp->t_line].l_close)(tp, flag); 382 ttyclose(tp); 383 384 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 385 ser_shutdown(sc); 386 } 387 return (0); 388 } 389 390 void 391 ser_shutdown(sc) 392 struct ser_softc *sc; 393 { 394 struct tty *tp = sc->ser_tty; 395 int s; 396 397 s = splser(); 398 399 custom.adkcon = ADKCONF_UARTBRK; /* clear break */ 400 #if 0 /* XXX fix: #ifdef KGDB */ 401 /* 402 * do not disable interrupts if debugging 403 */ 404 if (dev != kgdb_dev) 405 #endif 406 custom.intena = INTF_RBF | INTF_TBE; /* disable interrupts */ 407 custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */ 408 409 /* 410 * If HUPCL is not set, leave DTR unchanged. 411 */ 412 if (tp->t_cflag & HUPCL) { 413 (void)sermctl(tp->t_dev, TIOCM_DTR, DMBIC); 414 /* 415 * Idea from dev/ic/com.c: 416 * sleep a bit so that other side will notice, even if we 417 * reopen immediately. 418 */ 419 (void) tsleep(tp, TTIPRI, ttclos, hz); 420 } 421 422 #if not_yet 423 if (tp != &ser_cons) { 424 remove_vbl_function(&ser_vbl_node); 425 ttyfree(tp); 426 ser_tty = (struct tty *) NULL; 427 } 428 #endif 429 ser_open_speed = tp->t_ispeed; 430 return; 431 } 432 433 int 434 serread(dev, uio, flag) 435 dev_t dev; 436 struct uio *uio; 437 int flag; 438 { 439 /* ARGSUSED */ 440 441 return((*linesw[ser_tty->t_line].l_read)(ser_tty, uio, flag)); 442 } 443 444 int 445 serwrite(dev, uio, flag) 446 dev_t dev; 447 struct uio *uio; 448 int flag; 449 { 450 /* ARGSUSED */ 451 452 return((*linesw[ser_tty->t_line].l_write)(ser_tty, uio, flag)); 453 } 454 455 struct tty * 456 sertty(dev) 457 dev_t dev; 458 { 459 /* ARGSUSED */ 460 461 return (ser_tty); 462 } 463 464 /* 465 * We don't do any processing of data here, so we store the raw code 466 * obtained from the uart register. In theory, 110kBaud gives you 467 * 11kcps, so 16k buffer should be more than enough, interrupt 468 * latency of 1s should never happen, or something is seriously 469 * wrong.. 470 * buffers moved to above seropen() -is 471 */ 472 473 /* 474 * This is a replacement for the lack of a hardware fifo. 32k should be 475 * enough (there's only one unit anyway, so this is not going to 476 * accumulate). 477 */ 478 void 479 ser_fastint() 480 { 481 /* 482 * We're at RBE-level, which is higher than VBL-level which is used 483 * to periodically transmit contents of this buffer up one layer, 484 * so no spl-raising is necessary. 485 */ 486 u_short code; 487 488 /* 489 * This register contains both data and status bits! 490 */ 491 code = custom.serdatr; 492 493 /* 494 * Use SERDATF_RBF instead of INTF_RBF; they're equivalent, but 495 * we save one (slow) custom chip access. 496 */ 497 if ((code & SERDATRF_RBF) == 0) 498 return; 499 500 /* 501 * clear interrupt 502 */ 503 custom.intreq = INTF_RBF; 504 505 /* 506 * check for buffer overflow. 507 */ 508 if (sbcnt == SERIBUF_SIZE) { 509 ++sbovfl; 510 return; 511 } 512 /* 513 * store in buffer 514 */ 515 *sbwpt++ = code; 516 if (sbwpt == serbuf + SERIBUF_SIZE) 517 sbwpt = serbuf; 518 ++sbcnt; 519 if (sbcnt > SERIBUF_SIZE - 20) 520 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */ 521 } 522 523 524 void 525 serintr() 526 { 527 int s1, s2, ovfl; 528 struct tty *tp = ser_tty; 529 530 /* 531 * Make sure we're not interrupted by another 532 * vbl, but allow level5 ints 533 */ 534 s1 = spltty(); 535 536 /* 537 * pass along any acumulated information 538 */ 539 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) { 540 /* 541 * no collision with ser_fastint() 542 */ 543 sereint(*sbrpt++); 544 545 ovfl = 0; 546 /* lock against ser_fastint() */ 547 s2 = splser(); 548 sbcnt--; 549 if (sbrpt == serbuf + SERIBUF_SIZE) 550 sbrpt = serbuf; 551 if (sbovfl != 0) { 552 ovfl = sbovfl; 553 sbovfl = 0; 554 } 555 splx(s2); 556 if (ovfl != 0) 557 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n", 558 ovfl); 559 } 560 s2 = splser(); 561 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0) 562 SETRTS(ciab.pra); /* start accepting data again */ 563 splx(s2); 564 splx(s1); 565 } 566 567 void 568 sereint(stat) 569 int stat; 570 { 571 struct tty *tp; 572 u_char ch; 573 int c; 574 575 tp = ser_tty; 576 ch = stat & 0xff; 577 c = ch; 578 579 if ((tp->t_state & TS_ISOPEN) == 0) { 580 #ifdef KGDB 581 /* we don't care about parity errors */ 582 if (kgdb_dev == makedev(sermajor, 0) && c == FRAME_END) 583 kgdb_connect(0); /* trap into kgdb */ 584 #endif 585 return; 586 } 587 588 /* 589 * Check for break and (if enabled) parity error. 590 */ 591 if ((stat & 0x1ff) == 0) 592 c |= TTY_FE; 593 else if ((tp->t_cflag & PARENB) && 594 (((ch >> 7) + even_parity[ch & 0x7f] 595 + !!(tp->t_cflag & PARODD)) & 1)) 596 c |= TTY_PE; 597 598 if (stat & SERDATRF_OVRUN) 599 log(LOG_WARNING, "ser0: silo overflow\n"); 600 601 (*linesw[tp->t_line].l_rint)(c, tp); 602 } 603 604 /* 605 * This interrupt is periodically invoked in the vertical blank 606 * interrupt. It's used to keep track of the modem control lines 607 * and (new with the fast_int code) to move accumulated data 608 * up into the tty layer. 609 */ 610 void 611 sermint(unit) 612 int unit; 613 { 614 struct tty *tp; 615 u_char stat, last, istat; 616 617 tp = ser_tty; 618 if (!tp) 619 return; 620 621 /* 622 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) { 623 sbrpt = sbwpt = serbuf; 624 return; 625 } 626 */ 627 /* 628 * empty buffer 629 */ 630 serintr(); 631 632 stat = ciab.pra; 633 last = last_ciab_pra; 634 last_ciab_pra = stat; 635 636 /* 637 * check whether any interesting signal changed state 638 */ 639 istat = stat ^ last; 640 641 if (istat & serdcd) { 642 (*linesw[tp->t_line].l_modem)(tp, ISDCD(stat)); 643 } 644 645 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) && 646 (tp->t_cflag & CRTSCTS)) { 647 #if 0 648 /* the line is up and we want to do rts/cts flow control */ 649 if (ISCTS(stat)) { 650 tp->t_state &= ~TS_TTSTOP; 651 ttstart(tp); 652 /* cause tbe-int if we were stuck there */ 653 custom.intreq = INTF_SETCLR | INTF_TBE; 654 } else 655 tp->t_state |= TS_TTSTOP; 656 #else 657 /* do this on hardware level, not with tty driver */ 658 if (ISCTS(stat)) { 659 tp->t_state &= ~TS_TTSTOP; 660 /* cause TBE interrupt */ 661 custom.intreq = INTF_SETCLR | INTF_TBE; 662 } 663 #endif 664 } 665 } 666 667 int 668 serioctl(dev, cmd, data, flag, p) 669 dev_t dev; 670 u_long cmd; 671 caddr_t data; 672 int flag; 673 struct proc *p; 674 { 675 register struct tty *tp; 676 register int error; 677 678 tp = ser_tty; 679 if (!tp) 680 return ENXIO; 681 682 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 683 if (error >= 0) 684 return(error); 685 686 error = ttioctl(tp, cmd, data, flag, p); 687 if (error >= 0) 688 return(error); 689 690 switch (cmd) { 691 case TIOCSBRK: 692 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK; 693 break; 694 695 case TIOCCBRK: 696 custom.adkcon = ADKCONF_UARTBRK; 697 break; 698 699 case TIOCSDTR: 700 (void) sermctl(dev, TIOCM_DTR, DMBIS); 701 break; 702 703 case TIOCCDTR: 704 (void) sermctl(dev, TIOCM_DTR, DMBIC); 705 break; 706 707 case TIOCMSET: 708 (void) sermctl(dev, *(int *) data, DMSET); 709 break; 710 711 case TIOCMBIS: 712 (void) sermctl(dev, *(int *) data, DMBIS); 713 break; 714 715 case TIOCMBIC: 716 (void) sermctl(dev, *(int *) data, DMBIC); 717 break; 718 719 case TIOCMGET: 720 *(int *)data = sermctl(dev, 0, DMGET); 721 break; 722 case TIOCGFLAGS: 723 *(int *)data = serswflags; 724 break; 725 case TIOCSFLAGS: 726 error = suser(p->p_ucred, &p->p_acflag); 727 if (error != 0) 728 return(EPERM); 729 730 serswflags = *(int *)data; 731 serswflags &= /* only allow valid flags */ 732 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 733 break; 734 default: 735 return(ENOTTY); 736 } 737 738 return(0); 739 } 740 741 int 742 serparam(tp, t) 743 struct tty *tp; 744 struct termios *t; 745 { 746 int cflag, ospeed = 0; 747 748 if (t->c_ospeed > 0) { 749 if (t->c_ospeed < 110) 750 return(EINVAL); 751 ospeed = SERBRD(t->c_ospeed); 752 } 753 754 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 755 return(EINVAL); 756 757 /* XXX missing here: console test */ 758 if (serswflags & TIOCFLAG_SOFTCAR) { 759 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL; 760 } 761 762 /* if no changes, dont do anything. com.c explains why. */ 763 if (tp->t_ospeed == t->c_ospeed && 764 tp->t_cflag == t->c_cflag) 765 return (0); 766 767 cflag = t->c_cflag; 768 769 if (cflag & (CLOCAL | MDMBUF)) 770 serdcd = 0; 771 else 772 serdcd = CIAB_PRA_CD; 773 774 /* TODO: support multiple flow control protocols like com.c */ 775 776 /* 777 * copy to tty 778 */ 779 tp->t_ispeed = t->c_ispeed; 780 tp->t_ospeed = t->c_ospeed; 781 tp->t_cflag = cflag; 782 ser_open_speed = tp->t_ispeed; 783 784 /* 785 * enable interrupts 786 */ 787 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE; 788 last_ciab_pra = ciab.pra; 789 790 if (t->c_ospeed == 0) 791 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */ 792 else { 793 /* 794 * (re)enable DTR 795 * and set baud rate. (8 bit mode) 796 */ 797 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET); 798 custom.serper = (0 << 15) | ospeed; 799 } 800 (void)(*linesw[tp->t_line].l_modem)(tp, ISDCD(last_ciab_pra)); 801 802 return(0); 803 } 804 805 int serhwiflow(tp, flag) 806 struct tty *tp; 807 int flag; 808 { 809 #if 0 810 printf ("serhwiflow %d\n", flag); 811 #endif 812 if (flag) 813 CLRRTS(ciab.pra); 814 else 815 SETRTS(ciab.pra); 816 return 1; 817 } 818 819 static void 820 ser_putchar(tp, c) 821 struct tty *tp; 822 u_short c; 823 { 824 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB)) 825 c &= 0x7f; 826 827 /* 828 * handle parity if necessary 829 */ 830 if (tp->t_cflag & PARENB) { 831 if (even_parity[c]) 832 c |= 0x80; 833 if (tp->t_cflag & PARODD) 834 c ^= 0x80; 835 } 836 /* 837 * add stop bit(s) 838 */ 839 if (tp->t_cflag & CSTOPB) 840 c |= 0x300; 841 else 842 c |= 0x100; 843 844 custom.serdat = c; 845 } 846 847 848 static u_char ser_outbuf[SEROBUF_SIZE]; 849 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf; 850 851 void 852 ser_outintr() 853 { 854 struct tty *tp; 855 int s; 856 857 tp = ser_tty; 858 s = spltty(); 859 860 if (tp == 0) 861 goto out; 862 863 if ((custom.intreqr & INTF_TBE) == 0) 864 goto out; 865 866 /* 867 * clear interrupt 868 */ 869 custom.intreq = INTF_TBE; 870 871 if (sob_ptr == sob_end) { 872 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 873 if (tp->t_line) 874 (*linesw[tp->t_line].l_start)(tp); 875 else 876 serstart(tp); 877 goto out; 878 } 879 880 /* 881 * Do hardware flow control here. if the CTS line goes down, don't 882 * transmit anything. That way, we'll be restarted by the periodic 883 * interrupt when CTS comes back up. 884 */ 885 if (ISCTS(ciab.pra)) 886 ser_putchar(tp, *sob_ptr++); 887 else 888 CLRCTS(last_ciab_pra); /* Remember that CTS is off */ 889 out: 890 splx(s); 891 } 892 893 void 894 serstart(tp) 895 struct tty *tp; 896 { 897 int cc, s, hiwat; 898 #ifdef DIAGNOSTIC 899 int unit; 900 #endif 901 902 hiwat = 0; 903 904 if ((tp->t_state & TS_ISOPEN) == 0) 905 return; 906 907 #ifdef DIAGNOSTIC 908 unit = SERUNIT(tp->t_dev); 909 if (unit) 910 panic("serstart: unit is %d\n", unit); 911 #endif 912 913 s = spltty(); 914 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 915 goto out; 916 917 cc = tp->t_outq.c_cc; 918 if (cc <= tp->t_lowat) { 919 if (tp->t_state & TS_ASLEEP) { 920 tp->t_state &= ~TS_ASLEEP; 921 wakeup((caddr_t) & tp->t_outq); 922 } 923 selwakeup(&tp->t_wsel); 924 } 925 if (cc == 0 || (tp->t_state & TS_BUSY)) 926 goto out; 927 928 /* 929 * We only do bulk transfers if using CTSRTS flow control, not for 930 * (probably sloooow) ixon/ixoff devices. 931 */ 932 if ((tp->t_cflag & CRTSCTS) == 0) 933 cc = 1; 934 935 /* 936 * Limit the amount of output we do in one burst 937 * to prevent hogging the CPU. 938 */ 939 if (cc > SEROBUF_SIZE) { 940 hiwat++; 941 cc = SEROBUF_SIZE; 942 } 943 cc = q_to_b(&tp->t_outq, ser_outbuf, cc); 944 if (cc > 0) { 945 tp->t_state |= TS_BUSY; 946 947 sob_ptr = ser_outbuf; 948 sob_end = ser_outbuf + cc; 949 950 /* 951 * Get first character out, then have TBE-interrupts blow out 952 * further characters, until buffer is empty, and TS_BUSY gets 953 * cleared. 954 */ 955 ser_putchar(tp, *sob_ptr++); 956 } 957 out: 958 splx(s); 959 } 960 961 /* 962 * Stop output on a line. 963 */ 964 /*ARGSUSED*/ 965 void 966 serstop(tp, flag) 967 struct tty *tp; 968 int flag; 969 { 970 int s; 971 972 s = spltty(); 973 if (tp->t_state & TS_BUSY) { 974 if ((tp->t_state & TS_TTSTOP) == 0) 975 tp->t_state |= TS_FLUSH; 976 } 977 splx(s); 978 } 979 980 int 981 sermctl(dev, bits, how) 982 dev_t dev; 983 int bits, how; 984 { 985 int s; 986 u_char ub = 0; 987 988 /* 989 * convert TIOCM* mask into CIA mask 990 * which is active low 991 */ 992 if (how != DMGET) { 993 ub = 0; 994 if (bits & TIOCM_DTR) 995 ub |= CIAB_PRA_DTR; 996 if (bits & TIOCM_RTS) 997 ub |= CIAB_PRA_RTS; 998 if (bits & TIOCM_CTS) 999 ub |= CIAB_PRA_CTS; 1000 if (bits & TIOCM_CD) 1001 ub |= CIAB_PRA_CD; 1002 if (bits & TIOCM_RI) 1003 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */ 1004 if (bits & TIOCM_DSR) 1005 ub |= CIAB_PRA_DSR; 1006 } 1007 s = spltty(); 1008 switch (how) { 1009 case DMSET: 1010 /* invert and set */ 1011 ciab.pra = ~ub; 1012 break; 1013 1014 case DMBIC: 1015 ciab.pra |= ub; 1016 ub = ~ciab.pra; 1017 break; 1018 1019 case DMBIS: 1020 ciab.pra &= ~ub; 1021 ub = ~ciab.pra; 1022 break; 1023 1024 case DMGET: 1025 ub = ~ciab.pra; 1026 break; 1027 } 1028 (void)splx(s); 1029 1030 bits = 0; 1031 if (ub & CIAB_PRA_DTR) 1032 bits |= TIOCM_DTR; 1033 if (ub & CIAB_PRA_RTS) 1034 bits |= TIOCM_RTS; 1035 if (ub & CIAB_PRA_CTS) 1036 bits |= TIOCM_CTS; 1037 if (ub & CIAB_PRA_CD) 1038 bits |= TIOCM_CD; 1039 if (ub & CIAB_PRA_SEL) 1040 bits |= TIOCM_RI; 1041 if (ub & CIAB_PRA_DSR) 1042 bits |= TIOCM_DSR; 1043 1044 return(bits); 1045 } 1046 1047 /* 1048 * Following are all routines needed for SER to act as console 1049 */ 1050 void 1051 sercnprobe(cp) 1052 struct consdev *cp; 1053 { 1054 int unit; 1055 1056 /* locate the major number */ 1057 for (sermajor = 0; sermajor < nchrdev; sermajor++) 1058 if (cdevsw[sermajor].d_open == (void *)seropen) 1059 break; 1060 1061 1062 unit = CONUNIT; /* XXX: ick */ 1063 1064 /* 1065 * initialize required fields 1066 */ 1067 cp->cn_dev = makedev(sermajor, unit); 1068 if (serconsole == unit) 1069 cp->cn_pri = CN_REMOTE; 1070 else 1071 cp->cn_pri = CN_NORMAL; 1072 #ifdef KGDB 1073 if (major(kgdb_dev) == 1) /* XXX */ 1074 kgdb_dev = makedev(sermajor, minor(kgdb_dev)); 1075 #endif 1076 } 1077 1078 void 1079 sercninit(cp) 1080 struct consdev *cp; 1081 { 1082 int unit; 1083 1084 unit = SERUNIT(cp->cn_dev); 1085 1086 serinit(serdefaultrate); 1087 serconsole = unit; 1088 serconsinit = 1; 1089 } 1090 1091 void 1092 serinit(rate) 1093 int rate; 1094 { 1095 int s; 1096 1097 s = splser(); 1098 /* 1099 * might want to fiddle with the CIA later ??? 1100 */ 1101 custom.serper = (rate>=110 ? SERBRD(rate) : 0); 1102 splx(s); 1103 } 1104 1105 int 1106 sercngetc(dev) 1107 dev_t dev; 1108 { 1109 u_short stat; 1110 int c, s; 1111 1112 s = splser(); 1113 /* 1114 * poll 1115 */ 1116 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0) 1117 ; 1118 c = stat & 0xff; 1119 /* 1120 * clear interrupt 1121 */ 1122 custom.intreq = INTF_RBF; 1123 splx(s); 1124 return(c); 1125 } 1126 1127 /* 1128 * Console kernel output character routine. 1129 */ 1130 void 1131 sercnputc(dev, c) 1132 dev_t dev; 1133 int c; 1134 { 1135 register int timo; 1136 int s; 1137 1138 s = splhigh(); 1139 1140 if (serconsinit == 0) { 1141 (void)serinit(serdefaultrate); 1142 serconsinit = 1; 1143 } 1144 1145 /* 1146 * wait for any pending transmission to finish 1147 */ 1148 timo = 50000; 1149 while (!(custom.serdatr & SERDATRF_TBE) && --timo); 1150 1151 /* 1152 * transmit char. 1153 */ 1154 custom.serdat = (c & 0xff) | 0x100; 1155 1156 /* 1157 * wait for this transmission to complete 1158 */ 1159 timo = 1500000; 1160 while (!(custom.serdatr & SERDATRF_TBE) && --timo) 1161 ; 1162 1163 /* 1164 * Wait for the device (my vt100..) to process the data, since we 1165 * don't do flow-control with cnputc 1166 */ 1167 for (timo = 0; timo < 30000; timo++) 1168 ; 1169 1170 /* 1171 * We set TBE so that ser_outintr() is called right after to check 1172 * whether there still are chars to process. 1173 * We used to clear this, but it hung the tty output if the kernel 1174 * output a char while userland did on the same serial port. 1175 */ 1176 custom.intreq = INTF_SETCLR | INTF_TBE; 1177 splx(s); 1178 } 1179 1180 void 1181 sercnpollc(dev, on) 1182 dev_t dev; 1183 int on; 1184 { 1185 } 1186 #endif 1187