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