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