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