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