1 /* $NetBSD: ser.c,v 1.49 1998/07/22 19:13:02 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 185 if (matchname("ser", (char *)auxp) == 0 || cfp->cf_unit != 0) 186 return(0); 187 if (serconsole != 0 && amiga_realconfig == 0) 188 return(0); 189 return(1); 190 } 191 192 193 void 194 serattach(pdp, dp, auxp) 195 struct device *pdp, *dp; 196 void *auxp; 197 { 198 struct ser_softc *sc; 199 struct tty *tp; 200 u_short ir; 201 202 sc = (struct ser_softc *)dp; 203 204 ir = custom.intenar; 205 if (serconsole == 0) 206 DELAY(100000); 207 208 ser_vbl_node.function = (void (*) (void *)) sermint; 209 add_vbl_function(&ser_vbl_node, SER_VBL_PRIORITY, (void *) 0); 210 #ifdef KGDB 211 if (kgdb_dev == makedev(sermajor, 0)) { 212 if (serconsole == 0) 213 kgdb_dev = NODEV; /* can't debug over console port */ 214 else { 215 (void) serinit(kgdb_rate); 216 serconsinit = 1; /* don't re-init in serputc */ 217 if (kgdb_debug_init == 0) 218 printf(" kgdb enabled\n"); 219 else { 220 /* 221 * Print prefix of device name, 222 * let kgdb_connect print the rest. 223 */ 224 printf("ser0: "); 225 kgdb_connect(1); 226 } 227 } 228 } 229 #endif 230 /* 231 * Need to reset baud rate, etc. of next print so reset serconsinit. 232 */ 233 if (0 == serconsole) 234 serconsinit = 0; 235 236 tp = ttymalloc(); 237 tp->t_oproc = (void (*) (struct tty *)) serstart; 238 tp->t_param = serparam; 239 tp->t_hwiflow = serhwiflow; 240 tty_attach(tp); 241 sc->ser_tty = ser_tty = tp; 242 243 if (dp) 244 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE, 245 SEROBUF_SIZE); 246 } 247 248 249 /* ARGSUSED */ 250 int 251 seropen(dev, flag, mode, p) 252 dev_t dev; 253 int flag, mode; 254 struct proc *p; 255 { 256 struct ser_softc *sc; 257 struct tty *tp; 258 int unit, error, s, s2; 259 260 error = 0; 261 unit = SERUNIT(dev); 262 263 if (unit >= ser_cd.cd_ndevs) 264 return (ENXIO); 265 266 sc = ser_cd.cd_devs[unit]; 267 if (sc == 0) 268 return (ENXIO); 269 270 /* XXX com.c: insert KGDB check here */ 271 272 /* XXX ser.c had: s = spltty(); */ 273 274 tp = sc->ser_tty; 275 276 if ((tp->t_state & TS_ISOPEN) && 277 (tp->t_state & TS_XCLUDE) && 278 p->p_ucred->cr_uid != 0) 279 return (EBUSY); 280 281 s = spltty(); 282 283 /* 284 * If this is a first open... 285 */ 286 287 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 288 struct termios t; 289 290 tp->t_dev = dev; 291 292 s2 = splser(); 293 /* 294 * XXX here: hw enable, 295 */ 296 last_ciab_pra = ciab.pra; 297 298 splx(s2); 299 t.c_ispeed = 0; 300 301 /* XXX serconsolerate? */ 302 t.c_ospeed = TTYDEF_SPEED; 303 t.c_cflag = TTYDEF_CFLAG; 304 305 if (serswflags & TIOCFLAG_CLOCAL) 306 t.c_cflag |= CLOCAL; 307 if (serswflags & TIOCFLAG_CRTSCTS) 308 t.c_cflag |= CRTSCTS; 309 if (serswflags & TIOCFLAG_MDMBUF) 310 t.c_cflag |= MDMBUF; 311 312 /* Make sure serparam() will do something. */ 313 tp->t_ospeed = 0; 314 serparam(tp, &t); 315 tp->t_iflag = TTYDEF_IFLAG; 316 tp->t_oflag = TTYDEF_OFLAG; 317 tp->t_lflag = TTYDEF_LFLAG; 318 ttychars(tp); 319 ttsetwater(tp); 320 321 s2 = splser(); 322 (void)sermctl(dev, TIOCM_DTR, DMSET); 323 /* clear input ring */ 324 sbrpt = sbwpt = serbuf; 325 sbcnt = 0; 326 splx(s2); 327 } 328 329 splx(s); 330 331 error = ttyopen(tp, DIALOUT(dev), flag & O_NONBLOCK); 332 if (error) 333 goto bad; 334 335 error = (*linesw[tp->t_line].l_open)(dev, tp); 336 if (error) 337 goto bad; 338 339 return (0); 340 341 bad: 342 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 343 ser_shutdown(sc); 344 } 345 346 return (error); 347 } 348 349 /*ARGSUSED*/ 350 int 351 serclose(dev, flag, mode, p) 352 dev_t dev; 353 int flag, mode; 354 struct proc *p; 355 { 356 struct ser_softc *sc; 357 struct tty *tp; 358 359 sc = ser_cd.cd_devs[0]; 360 tp = ser_tty; 361 362 /* XXX This is for cons.c, according to com.c */ 363 if (!(tp->t_state & TS_ISOPEN)) 364 return (0); 365 366 (*linesw[tp->t_line].l_close)(tp, flag); 367 ttyclose(tp); 368 369 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 370 ser_shutdown(sc); 371 } 372 return (0); 373 } 374 375 void 376 ser_shutdown(sc) 377 struct ser_softc *sc; 378 { 379 struct tty *tp = sc->ser_tty; 380 int s; 381 382 s = splser(); 383 384 custom.adkcon = ADKCONF_UARTBRK; /* clear break */ 385 #if 0 /* XXX fix: #ifdef KGDB */ 386 /* 387 * do not disable interrupts if debugging 388 */ 389 if (dev != kgdb_dev) 390 #endif 391 custom.intena = INTF_RBF | INTF_TBE; /* disable interrupts */ 392 custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */ 393 394 /* 395 * If HUPCL is not set, leave DTR unchanged. 396 */ 397 if (tp->t_cflag & HUPCL) { 398 (void)sermctl(tp->t_dev, TIOCM_DTR, DMBIC); 399 /* 400 * Idea from dev/ic/com.c: 401 * sleep a bit so that other side will notice, even if we 402 * reopen immediately. 403 */ 404 (void) tsleep(tp, TTIPRI, ttclos, hz); 405 } 406 407 #if not_yet 408 if (tp != &ser_cons) { 409 remove_vbl_function(&ser_vbl_node); 410 ttyfree(tp); 411 ser_tty = (struct tty *) NULL; 412 } 413 #endif 414 ser_open_speed = tp->t_ispeed; 415 return; 416 } 417 418 int 419 serread(dev, uio, flag) 420 dev_t dev; 421 struct uio *uio; 422 int flag; 423 { 424 /* ARGSUSED */ 425 426 return((*linesw[ser_tty->t_line].l_read)(ser_tty, uio, flag)); 427 } 428 429 int 430 serwrite(dev, uio, flag) 431 dev_t dev; 432 struct uio *uio; 433 int flag; 434 { 435 /* ARGSUSED */ 436 437 return((*linesw[ser_tty->t_line].l_write)(ser_tty, uio, flag)); 438 } 439 440 struct tty * 441 sertty(dev) 442 dev_t dev; 443 { 444 /* ARGSUSED */ 445 446 return (ser_tty); 447 } 448 449 /* 450 * We don't do any processing of data here, so we store the raw code 451 * obtained from the uart register. In theory, 110kBaud gives you 452 * 11kcps, so 16k buffer should be more than enough, interrupt 453 * latency of 1s should never happen, or something is seriously 454 * wrong.. 455 * buffers moved to above seropen() -is 456 */ 457 458 /* 459 * This is a replacement for the lack of a hardware fifo. 32k should be 460 * enough (there's only one unit anyway, so this is not going to 461 * accumulate). 462 */ 463 void 464 ser_fastint() 465 { 466 /* 467 * We're at RBE-level, which is higher than VBL-level which is used 468 * to periodically transmit contents of this buffer up one layer, 469 * so no spl-raising is necessary. 470 */ 471 u_short code; 472 473 /* 474 * This register contains both data and status bits! 475 */ 476 code = custom.serdatr; 477 478 /* 479 * Use SERDATF_RBF instead of INTF_RBF; they're equivalent, but 480 * we save one (slow) custom chip access. 481 */ 482 if ((code & SERDATRF_RBF) == 0) 483 return; 484 485 /* 486 * clear interrupt 487 */ 488 custom.intreq = INTF_RBF; 489 490 /* 491 * check for buffer overflow. 492 */ 493 if (sbcnt == SERIBUF_SIZE) { 494 ++sbovfl; 495 return; 496 } 497 /* 498 * store in buffer 499 */ 500 *sbwpt++ = code; 501 if (sbwpt == serbuf + SERIBUF_SIZE) 502 sbwpt = serbuf; 503 ++sbcnt; 504 if (sbcnt > SERIBUF_SIZE - 20) 505 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */ 506 } 507 508 509 void 510 serintr() 511 { 512 int s1, s2, ovfl; 513 struct tty *tp = ser_tty; 514 515 /* 516 * Make sure we're not interrupted by another 517 * vbl, but allow level5 ints 518 */ 519 s1 = spltty(); 520 521 /* 522 * pass along any acumulated information 523 */ 524 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) { 525 /* 526 * no collision with ser_fastint() 527 */ 528 sereint(*sbrpt++); 529 530 ovfl = 0; 531 /* lock against ser_fastint() */ 532 s2 = splser(); 533 sbcnt--; 534 if (sbrpt == serbuf + SERIBUF_SIZE) 535 sbrpt = serbuf; 536 if (sbovfl != 0) { 537 ovfl = sbovfl; 538 sbovfl = 0; 539 } 540 splx(s2); 541 if (ovfl != 0) 542 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n", 543 ovfl); 544 } 545 s2 = splser(); 546 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0) 547 SETRTS(ciab.pra); /* start accepting data again */ 548 splx(s2); 549 splx(s1); 550 } 551 552 void 553 sereint(stat) 554 int stat; 555 { 556 struct tty *tp; 557 u_char ch; 558 int c; 559 560 tp = ser_tty; 561 ch = stat & 0xff; 562 c = ch; 563 564 if ((tp->t_state & TS_ISOPEN) == 0) { 565 #ifdef KGDB 566 /* we don't care about parity errors */ 567 if (kgdb_dev == makedev(sermajor, 0) && c == FRAME_END) 568 kgdb_connect(0); /* trap into kgdb */ 569 #endif 570 return; 571 } 572 573 /* 574 * Check for break and (if enabled) parity error. 575 */ 576 if ((stat & 0x1ff) == 0) 577 c |= TTY_FE; 578 else if ((tp->t_cflag & PARENB) && 579 (((ch >> 7) + even_parity[ch & 0x7f] 580 + !!(tp->t_cflag & PARODD)) & 1)) 581 c |= TTY_PE; 582 583 if (stat & SERDATRF_OVRUN) 584 log(LOG_WARNING, "ser0: silo overflow\n"); 585 586 (*linesw[tp->t_line].l_rint)(c, tp); 587 } 588 589 /* 590 * This interrupt is periodically invoked in the vertical blank 591 * interrupt. It's used to keep track of the modem control lines 592 * and (new with the fast_int code) to move accumulated data 593 * up into the tty layer. 594 */ 595 void 596 sermint(unit) 597 int unit; 598 { 599 struct tty *tp; 600 u_char stat, last, istat; 601 602 tp = ser_tty; 603 if (!tp) 604 return; 605 606 /* 607 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) { 608 sbrpt = sbwpt = serbuf; 609 return; 610 } 611 */ 612 /* 613 * empty buffer 614 */ 615 serintr(); 616 617 stat = ciab.pra; 618 last = last_ciab_pra; 619 last_ciab_pra = stat; 620 621 /* 622 * check whether any interesting signal changed state 623 */ 624 istat = stat ^ last; 625 626 if (istat & serdcd) { 627 (*linesw[tp->t_line].l_modem)(tp, ISDCD(stat)); 628 } 629 630 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) && 631 (tp->t_cflag & CRTSCTS)) { 632 #if 0 633 /* the line is up and we want to do rts/cts flow control */ 634 if (ISCTS(stat)) { 635 tp->t_state &= ~TS_TTSTOP; 636 ttstart(tp); 637 /* cause tbe-int if we were stuck there */ 638 custom.intreq = INTF_SETCLR | INTF_TBE; 639 } else 640 tp->t_state |= TS_TTSTOP; 641 #else 642 /* do this on hardware level, not with tty driver */ 643 if (ISCTS(stat)) { 644 tp->t_state &= ~TS_TTSTOP; 645 /* cause TBE interrupt */ 646 custom.intreq = INTF_SETCLR | INTF_TBE; 647 } 648 #endif 649 } 650 } 651 652 int 653 serioctl(dev, cmd, data, flag, p) 654 dev_t dev; 655 u_long cmd; 656 caddr_t data; 657 int flag; 658 struct proc *p; 659 { 660 register struct tty *tp; 661 register int error; 662 663 tp = ser_tty; 664 if (!tp) 665 return ENXIO; 666 667 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); 668 if (error >= 0) 669 return(error); 670 671 error = ttioctl(tp, cmd, data, flag, p); 672 if (error >= 0) 673 return(error); 674 675 switch (cmd) { 676 case TIOCSBRK: 677 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK; 678 break; 679 680 case TIOCCBRK: 681 custom.adkcon = ADKCONF_UARTBRK; 682 break; 683 684 case TIOCSDTR: 685 (void) sermctl(dev, TIOCM_DTR, DMBIS); 686 break; 687 688 case TIOCCDTR: 689 (void) sermctl(dev, TIOCM_DTR, DMBIC); 690 break; 691 692 case TIOCMSET: 693 (void) sermctl(dev, *(int *) data, DMSET); 694 break; 695 696 case TIOCMBIS: 697 (void) sermctl(dev, *(int *) data, DMBIS); 698 break; 699 700 case TIOCMBIC: 701 (void) sermctl(dev, *(int *) data, DMBIC); 702 break; 703 704 case TIOCMGET: 705 *(int *)data = sermctl(dev, 0, DMGET); 706 break; 707 case TIOCGFLAGS: 708 *(int *)data = serswflags; 709 break; 710 case TIOCSFLAGS: 711 error = suser(p->p_ucred, &p->p_acflag); 712 if (error != 0) 713 return(EPERM); 714 715 serswflags = *(int *)data; 716 serswflags &= /* only allow valid flags */ 717 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 718 break; 719 default: 720 return(ENOTTY); 721 } 722 723 return(0); 724 } 725 726 int 727 serparam(tp, t) 728 struct tty *tp; 729 struct termios *t; 730 { 731 int cflag, ospeed = 0; 732 733 if (t->c_ospeed > 0) { 734 if (t->c_ospeed < 110) 735 return(EINVAL); 736 ospeed = SERBRD(t->c_ospeed); 737 } 738 739 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 740 return(EINVAL); 741 742 /* XXX missing here: console test */ 743 if (serswflags & TIOCFLAG_SOFTCAR) { 744 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL; 745 } 746 747 /* if no changes, dont do anything. com.c explains why. */ 748 if (tp->t_ospeed == t->c_ospeed && 749 tp->t_cflag == t->c_cflag) 750 return (0); 751 752 cflag = t->c_cflag; 753 754 if (cflag & (CLOCAL | MDMBUF)) 755 serdcd = 0; 756 else 757 serdcd = CIAB_PRA_CD; 758 759 /* TODO: support multiple flow control protocols like com.c */ 760 761 /* 762 * copy to tty 763 */ 764 tp->t_ispeed = t->c_ispeed; 765 tp->t_ospeed = t->c_ospeed; 766 tp->t_cflag = cflag; 767 ser_open_speed = tp->t_ispeed; 768 769 /* 770 * enable interrupts 771 */ 772 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE; 773 last_ciab_pra = ciab.pra; 774 775 if (t->c_ospeed == 0) 776 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */ 777 else { 778 /* 779 * (re)enable DTR 780 * and set baud rate. (8 bit mode) 781 */ 782 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET); 783 custom.serper = (0 << 15) | ospeed; 784 } 785 (void)(*linesw[tp->t_line].l_modem)(tp, ISDCD(last_ciab_pra)); 786 787 return(0); 788 } 789 790 int serhwiflow(tp, flag) 791 struct tty *tp; 792 int flag; 793 { 794 #if 0 795 printf ("serhwiflow %d\n", flag); 796 #endif 797 if (flag) 798 CLRRTS(ciab.pra); 799 else 800 SETRTS(ciab.pra); 801 return 1; 802 } 803 804 static void 805 ser_putchar(tp, c) 806 struct tty *tp; 807 u_short c; 808 { 809 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB)) 810 c &= 0x7f; 811 812 /* 813 * handle parity if necessary 814 */ 815 if (tp->t_cflag & PARENB) { 816 if (even_parity[c]) 817 c |= 0x80; 818 if (tp->t_cflag & PARODD) 819 c ^= 0x80; 820 } 821 /* 822 * add stop bit(s) 823 */ 824 if (tp->t_cflag & CSTOPB) 825 c |= 0x300; 826 else 827 c |= 0x100; 828 829 custom.serdat = c; 830 } 831 832 833 static u_char ser_outbuf[SEROBUF_SIZE]; 834 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf; 835 836 void 837 ser_outintr() 838 { 839 struct tty *tp; 840 int s; 841 842 tp = ser_tty; 843 s = spltty(); 844 845 if (tp == 0) 846 goto out; 847 848 if ((custom.intreqr & INTF_TBE) == 0) 849 goto out; 850 851 /* 852 * clear interrupt 853 */ 854 custom.intreq = INTF_TBE; 855 856 if (sob_ptr == sob_end) { 857 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 858 if (tp->t_line) 859 (*linesw[tp->t_line].l_start)(tp); 860 else 861 serstart(tp); 862 goto out; 863 } 864 865 /* 866 * Do hardware flow control here. if the CTS line goes down, don't 867 * transmit anything. That way, we'll be restarted by the periodic 868 * interrupt when CTS comes back up. 869 */ 870 if (ISCTS(ciab.pra)) 871 ser_putchar(tp, *sob_ptr++); 872 else 873 CLRCTS(last_ciab_pra); /* Remember that CTS is off */ 874 out: 875 splx(s); 876 } 877 878 void 879 serstart(tp) 880 struct tty *tp; 881 { 882 int cc, s, hiwat; 883 #ifdef DIAGNOSTIC 884 int unit; 885 #endif 886 887 hiwat = 0; 888 889 if ((tp->t_state & TS_ISOPEN) == 0) 890 return; 891 892 #ifdef DIAGNOSTIC 893 unit = SERUNIT(tp->t_dev); 894 if (unit) 895 panic("serstart: unit is %d\n", unit); 896 #endif 897 898 s = spltty(); 899 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 900 goto out; 901 902 cc = tp->t_outq.c_cc; 903 if (cc <= tp->t_lowat) { 904 if (tp->t_state & TS_ASLEEP) { 905 tp->t_state &= ~TS_ASLEEP; 906 wakeup((caddr_t) & tp->t_outq); 907 } 908 selwakeup(&tp->t_wsel); 909 } 910 if (cc == 0 || (tp->t_state & TS_BUSY)) 911 goto out; 912 913 /* 914 * We only do bulk transfers if using CTSRTS flow control, not for 915 * (probably sloooow) ixon/ixoff devices. 916 */ 917 if ((tp->t_cflag & CRTSCTS) == 0) 918 cc = 1; 919 920 /* 921 * Limit the amount of output we do in one burst 922 * to prevent hogging the CPU. 923 */ 924 if (cc > SEROBUF_SIZE) { 925 hiwat++; 926 cc = SEROBUF_SIZE; 927 } 928 cc = q_to_b(&tp->t_outq, ser_outbuf, cc); 929 if (cc > 0) { 930 tp->t_state |= TS_BUSY; 931 932 sob_ptr = ser_outbuf; 933 sob_end = ser_outbuf + cc; 934 935 /* 936 * Get first character out, then have TBE-interrupts blow out 937 * further characters, until buffer is empty, and TS_BUSY gets 938 * cleared. 939 */ 940 ser_putchar(tp, *sob_ptr++); 941 } 942 out: 943 splx(s); 944 } 945 946 /* 947 * Stop output on a line. 948 */ 949 /*ARGSUSED*/ 950 void 951 serstop(tp, flag) 952 struct tty *tp; 953 int flag; 954 { 955 int s; 956 957 s = spltty(); 958 if (tp->t_state & TS_BUSY) { 959 if ((tp->t_state & TS_TTSTOP) == 0) 960 tp->t_state |= TS_FLUSH; 961 } 962 splx(s); 963 } 964 965 int 966 sermctl(dev, bits, how) 967 dev_t dev; 968 int bits, how; 969 { 970 int s; 971 u_char ub = 0; 972 973 /* 974 * convert TIOCM* mask into CIA mask 975 * which is active low 976 */ 977 if (how != DMGET) { 978 ub = 0; 979 if (bits & TIOCM_DTR) 980 ub |= CIAB_PRA_DTR; 981 if (bits & TIOCM_RTS) 982 ub |= CIAB_PRA_RTS; 983 if (bits & TIOCM_CTS) 984 ub |= CIAB_PRA_CTS; 985 if (bits & TIOCM_CD) 986 ub |= CIAB_PRA_CD; 987 if (bits & TIOCM_RI) 988 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */ 989 if (bits & TIOCM_DSR) 990 ub |= CIAB_PRA_DSR; 991 } 992 s = spltty(); 993 switch (how) { 994 case DMSET: 995 /* invert and set */ 996 ciab.pra = ~ub; 997 break; 998 999 case DMBIC: 1000 ciab.pra |= ub; 1001 ub = ~ciab.pra; 1002 break; 1003 1004 case DMBIS: 1005 ciab.pra &= ~ub; 1006 ub = ~ciab.pra; 1007 break; 1008 1009 case DMGET: 1010 ub = ~ciab.pra; 1011 break; 1012 } 1013 (void)splx(s); 1014 1015 bits = 0; 1016 if (ub & CIAB_PRA_DTR) 1017 bits |= TIOCM_DTR; 1018 if (ub & CIAB_PRA_RTS) 1019 bits |= TIOCM_RTS; 1020 if (ub & CIAB_PRA_CTS) 1021 bits |= TIOCM_CTS; 1022 if (ub & CIAB_PRA_CD) 1023 bits |= TIOCM_CD; 1024 if (ub & CIAB_PRA_SEL) 1025 bits |= TIOCM_RI; 1026 if (ub & CIAB_PRA_DSR) 1027 bits |= TIOCM_DSR; 1028 1029 return(bits); 1030 } 1031 1032 /* 1033 * Following are all routines needed for SER to act as console 1034 */ 1035 void 1036 sercnprobe(cp) 1037 struct consdev *cp; 1038 { 1039 int unit; 1040 1041 /* locate the major number */ 1042 for (sermajor = 0; sermajor < nchrdev; sermajor++) 1043 if (cdevsw[sermajor].d_open == (void *)seropen) 1044 break; 1045 1046 1047 unit = CONUNIT; /* XXX: ick */ 1048 1049 /* 1050 * initialize required fields 1051 */ 1052 cp->cn_dev = makedev(sermajor, unit); 1053 if (serconsole == unit) 1054 cp->cn_pri = CN_REMOTE; 1055 else 1056 cp->cn_pri = CN_NORMAL; 1057 #ifdef KGDB 1058 if (major(kgdb_dev) == 1) /* XXX */ 1059 kgdb_dev = makedev(sermajor, minor(kgdb_dev)); 1060 #endif 1061 } 1062 1063 void 1064 sercninit(cp) 1065 struct consdev *cp; 1066 { 1067 int unit; 1068 1069 unit = SERUNIT(cp->cn_dev); 1070 1071 serinit(serdefaultrate); 1072 serconsole = unit; 1073 serconsinit = 1; 1074 } 1075 1076 void 1077 serinit(rate) 1078 int rate; 1079 { 1080 int s; 1081 1082 s = splser(); 1083 /* 1084 * might want to fiddle with the CIA later ??? 1085 */ 1086 custom.serper = (rate>=110 ? SERBRD(rate) : 0); 1087 splx(s); 1088 } 1089 1090 int 1091 sercngetc(dev) 1092 dev_t dev; 1093 { 1094 u_short stat; 1095 int c, s; 1096 1097 s = splser(); 1098 /* 1099 * poll 1100 */ 1101 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0) 1102 ; 1103 c = stat & 0xff; 1104 /* 1105 * clear interrupt 1106 */ 1107 custom.intreq = INTF_RBF; 1108 splx(s); 1109 return(c); 1110 } 1111 1112 /* 1113 * Console kernel output character routine. 1114 */ 1115 void 1116 sercnputc(dev, c) 1117 dev_t dev; 1118 int c; 1119 { 1120 register int timo; 1121 int s; 1122 1123 s = splhigh(); 1124 1125 if (serconsinit == 0) { 1126 (void)serinit(serdefaultrate); 1127 serconsinit = 1; 1128 } 1129 1130 /* 1131 * wait for any pending transmission to finish 1132 */ 1133 timo = 50000; 1134 while (!(custom.serdatr & SERDATRF_TBE) && --timo); 1135 1136 /* 1137 * transmit char. 1138 */ 1139 custom.serdat = (c & 0xff) | 0x100; 1140 1141 /* 1142 * wait for this transmission to complete 1143 */ 1144 timo = 1500000; 1145 while (!(custom.serdatr & SERDATRF_TBE) && --timo) 1146 ; 1147 1148 /* 1149 * Wait for the device (my vt100..) to process the data, since we 1150 * don't do flow-control with cnputc 1151 */ 1152 for (timo = 0; timo < 30000; timo++) 1153 ; 1154 1155 /* 1156 * clear any interrupts generated by this transmission 1157 */ 1158 custom.intreq = INTF_TBE; 1159 splx(s); 1160 } 1161 1162 void 1163 sercnpollc(dev, on) 1164 dev_t dev; 1165 int on; 1166 { 1167 } 1168 #endif 1169