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