1 /* $NetBSD: ser.c,v 1.77 2007/11/19 18:51:37 ad 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.77 2007/11/19 18:51:37 ad 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 = (struct ser_softc *)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 if (unit >= ser_cd.cd_ndevs) 285 return (ENXIO); 286 287 sc = ser_cd.cd_devs[unit]; 288 if (sc == 0) 289 return (ENXIO); 290 291 /* XXX com.c: insert KGDB check here */ 292 293 /* XXX ser.c had: s = spltty(); */ 294 295 tp = sc->ser_tty; 296 297 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp)) 298 return (EBUSY); 299 300 s = spltty(); 301 302 /* 303 * If this is a first open... 304 */ 305 306 if ((tp->t_state & TS_ISOPEN) == 0 && tp->t_wopen == 0) { 307 struct termios t; 308 309 tp->t_dev = dev; 310 311 s2 = splser(); 312 /* 313 * XXX here: hw enable, 314 */ 315 last_ciab_pra = ciab.pra; 316 317 splx(s2); 318 t.c_ispeed = 0; 319 320 /* XXX serconsolerate? */ 321 t.c_ospeed = TTYDEF_SPEED; 322 t.c_cflag = TTYDEF_CFLAG; 323 324 if (serswflags & TIOCFLAG_CLOCAL) 325 t.c_cflag |= CLOCAL; 326 if (serswflags & TIOCFLAG_CRTSCTS) 327 t.c_cflag |= CRTSCTS; 328 if (serswflags & TIOCFLAG_MDMBUF) 329 t.c_cflag |= MDMBUF; 330 331 /* Make sure serparam() will do something. */ 332 tp->t_ospeed = 0; 333 serparam(tp, &t); 334 tp->t_iflag = TTYDEF_IFLAG; 335 tp->t_oflag = TTYDEF_OFLAG; 336 tp->t_lflag = TTYDEF_LFLAG; 337 ttychars(tp); 338 ttsetwater(tp); 339 340 s2 = splser(); 341 (void)sermctl(dev, TIOCM_DTR, DMSET); 342 /* clear input ring */ 343 sbrpt = sbwpt = serbuf; 344 sbcnt = 0; 345 splx(s2); 346 } 347 348 splx(s); 349 350 error = ttyopen(tp, DIALOUT(dev), flag & O_NONBLOCK); 351 if (error) 352 goto bad; 353 354 error = tp->t_linesw->l_open(dev, tp); 355 if (error) 356 goto bad; 357 358 return (0); 359 360 bad: 361 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 362 ser_shutdown(sc); 363 } 364 365 return (error); 366 } 367 368 /*ARGSUSED*/ 369 int 370 serclose(dev_t dev, int flag, int mode, struct lwp *l) 371 { 372 struct ser_softc *sc; 373 struct tty *tp; 374 375 sc = ser_cd.cd_devs[0]; 376 tp = ser_tty; 377 378 /* XXX This is for cons.c, according to com.c */ 379 if (!(tp->t_state & TS_ISOPEN)) 380 return (0); 381 382 tp->t_linesw->l_close(tp, flag); 383 ttyclose(tp); 384 385 if (!(tp->t_state & TS_ISOPEN) && tp->t_wopen == 0) { 386 ser_shutdown(sc); 387 } 388 return (0); 389 } 390 391 void 392 ser_shutdown(struct ser_softc *sc) 393 { 394 struct tty *tp = sc->ser_tty; 395 int s; 396 397 s = splser(); 398 399 custom.adkcon = ADKCONF_UARTBRK; /* clear break */ 400 #if 0 /* XXX fix: #ifdef KGDB */ 401 /* 402 * do not disable interrupts if debugging 403 */ 404 if (dev != kgdb_dev) 405 #endif 406 custom.intena = INTF_RBF | INTF_TBE; /* disable interrupts */ 407 custom.intreq = INTF_RBF | INTF_TBE; /* clear intr request */ 408 409 /* 410 * If HUPCL is not set, leave DTR unchanged. 411 */ 412 if (tp->t_cflag & HUPCL) { 413 (void)sermctl(tp->t_dev, TIOCM_DTR, DMBIC); 414 /* 415 * Idea from dev/ic/com.c: 416 * sleep a bit so that other side will notice, even if we 417 * reopen immediately. 418 */ 419 (void) tsleep(tp, TTIPRI, ttclos, hz); 420 } 421 422 #if not_yet 423 if (tp != &ser_cons) { 424 remove_vbl_function(&ser_vbl_node); 425 ttyfree(tp); 426 ser_tty = (struct tty *) NULL; 427 } 428 #endif 429 ser_open_speed = tp->t_ispeed; 430 return; 431 } 432 433 int 434 serread(dev_t dev, struct uio *uio, int flag) 435 { 436 /* ARGSUSED */ 437 438 return ser_tty->t_linesw->l_read(ser_tty, uio, flag); 439 } 440 441 int 442 serwrite(dev_t dev, struct uio *uio, int flag) 443 { 444 /* ARGSUSED */ 445 446 return ser_tty->t_linesw->l_write(ser_tty, uio, flag); 447 } 448 449 int 450 serpoll(dev_t dev, int events, struct lwp *l) 451 { 452 /* ARGSUSED */ 453 454 return ser_tty->t_linesw->l_poll(ser_tty, events, l); 455 } 456 457 struct tty * 458 sertty(dev_t dev) 459 { 460 /* ARGSUSED */ 461 462 return (ser_tty); 463 } 464 465 /* 466 * We don't do any processing of data here, so we store the raw code 467 * obtained from the uart register. In theory, 110kBaud gives you 468 * 11kcps, so 16k buffer should be more than enough, interrupt 469 * latency of 1s should never happen, or something is seriously 470 * wrong.. 471 * buffers moved to above seropen() -is 472 */ 473 474 /* 475 * This is a replacement for the lack of a hardware fifo. 32k should be 476 * enough (there's only one unit anyway, so this is not going to 477 * accumulate). 478 */ 479 void 480 ser_fastint(void) 481 { 482 /* 483 * We're at RBE-level, which is higher than VBL-level which is used 484 * to periodically transmit contents of this buffer up one layer, 485 * so no spl-raising is necessary. 486 */ 487 u_short code; 488 489 /* 490 * This register contains both data and status bits! 491 */ 492 code = custom.serdatr; 493 494 /* 495 * Use SERDATF_RBF instead of INTF_RBF; they're equivalent, but 496 * we save one (slow) custom chip access. 497 */ 498 if ((code & SERDATRF_RBF) == 0) 499 return; 500 501 /* 502 * clear interrupt 503 */ 504 custom.intreq = INTF_RBF; 505 506 /* 507 * check for buffer overflow. 508 */ 509 if (sbcnt == SERIBUF_SIZE) { 510 ++sbovfl; 511 return; 512 } 513 /* 514 * store in buffer 515 */ 516 *sbwpt++ = code; 517 if (sbwpt == serbuf + SERIBUF_SIZE) 518 sbwpt = serbuf; 519 ++sbcnt; 520 if (sbcnt > SERIBUF_SIZE - 20) 521 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */ 522 } 523 524 525 void 526 serintr(void) 527 { 528 int s1, s2, ovfl; 529 struct tty *tp = ser_tty; 530 531 /* 532 * Make sure we're not interrupted by another 533 * vbl, but allow level5 ints 534 */ 535 s1 = spltty(); 536 537 /* 538 * pass along any acumulated information 539 */ 540 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) { 541 /* 542 * no collision with ser_fastint() 543 */ 544 sereint(*sbrpt++); 545 546 ovfl = 0; 547 /* lock against ser_fastint() */ 548 s2 = splser(); 549 sbcnt--; 550 if (sbrpt == serbuf + SERIBUF_SIZE) 551 sbrpt = serbuf; 552 if (sbovfl != 0) { 553 ovfl = sbovfl; 554 sbovfl = 0; 555 } 556 splx(s2); 557 if (ovfl != 0) 558 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n", 559 ovfl); 560 } 561 s2 = splser(); 562 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0) 563 SETRTS(ciab.pra); /* start accepting data again */ 564 splx(s2); 565 splx(s1); 566 } 567 568 void 569 sereint(int stat) 570 { 571 static int break_in_progress = 0; 572 struct tty *tp; 573 u_char ch; 574 int c; 575 576 tp = ser_tty; 577 ch = stat & 0xff; 578 c = ch; 579 580 if ((tp->t_state & TS_ISOPEN) == 0) { 581 #ifdef KGDB 582 int maj; 583 584 /* we don't care about parity errors */ 585 maj = cdevsw_lookup_major(&ser_cdevsw); 586 if (kgdb_dev == makedev(maj, 0) && c == FRAME_END) 587 kgdb_connect(0); /* trap into kgdb */ 588 #endif 589 return; 590 } 591 592 /* 593 * Check for break and (if enabled) parity error. 594 */ 595 if ((stat & 0x1ff) == 0) { 596 if (break_in_progress) 597 return; 598 599 c = TTY_FE; 600 break_in_progress = 1; 601 #ifdef DDB 602 if (serconsole == 0) { 603 extern int db_active; 604 605 if (!db_active) { 606 console_debugger(); 607 return; 608 } 609 } 610 #endif 611 } else { 612 break_in_progress = 0; 613 if ((tp->t_cflag & PARENB) && 614 (((ch >> 7) + even_parity[ch & 0x7f] 615 + !!(tp->t_cflag & PARODD)) & 1)) 616 c |= TTY_PE; 617 } 618 619 if (stat & SERDATRF_OVRUN) 620 log(LOG_WARNING, "ser0: silo overflow\n"); 621 622 tp->t_linesw->l_rint(c, tp); 623 } 624 625 /* 626 * This interrupt is periodically invoked in the vertical blank 627 * interrupt. It's used to keep track of the modem control lines 628 * and (new with the fast_int code) to move accumulated data 629 * up into the tty layer. 630 */ 631 void 632 sermint(int unit) 633 { 634 struct tty *tp; 635 u_char stat, last, istat; 636 637 tp = ser_tty; 638 if (!tp) 639 return; 640 641 /* 642 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) { 643 sbrpt = sbwpt = serbuf; 644 return; 645 } 646 */ 647 /* 648 * empty buffer 649 */ 650 serintr(); 651 652 stat = ciab.pra; 653 last = last_ciab_pra; 654 last_ciab_pra = stat; 655 656 /* 657 * check whether any interesting signal changed state 658 */ 659 istat = stat ^ last; 660 661 if (istat & serdcd) { 662 tp->t_linesw->l_modem(tp, ISDCD(stat)); 663 } 664 665 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) && 666 (tp->t_cflag & CRTSCTS)) { 667 #if 0 668 /* the line is up and we want to do rts/cts flow control */ 669 if (ISCTS(stat)) { 670 tp->t_state &= ~TS_TTSTOP; 671 ttstart(tp); 672 /* cause tbe-int if we were stuck there */ 673 custom.intreq = INTF_SETCLR | INTF_TBE; 674 } else 675 tp->t_state |= TS_TTSTOP; 676 #else 677 /* do this on hardware level, not with tty driver */ 678 if (ISCTS(stat)) { 679 tp->t_state &= ~TS_TTSTOP; 680 /* cause TBE interrupt */ 681 custom.intreq = INTF_SETCLR | INTF_TBE; 682 } 683 #endif 684 } 685 } 686 687 int 688 serioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 689 { 690 register struct tty *tp; 691 register int error; 692 693 tp = ser_tty; 694 if (!tp) 695 return ENXIO; 696 697 error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); 698 if (error != EPASSTHROUGH) 699 return(error); 700 701 error = ttioctl(tp, cmd, data, flag, l); 702 if (error != EPASSTHROUGH) 703 return(error); 704 705 switch (cmd) { 706 case TIOCSBRK: 707 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK; 708 break; 709 710 case TIOCCBRK: 711 custom.adkcon = ADKCONF_UARTBRK; 712 break; 713 714 case TIOCSDTR: 715 (void) sermctl(dev, TIOCM_DTR, DMBIS); 716 break; 717 718 case TIOCCDTR: 719 (void) sermctl(dev, TIOCM_DTR, DMBIC); 720 break; 721 722 case TIOCMSET: 723 (void) sermctl(dev, *(int *) data, DMSET); 724 break; 725 726 case TIOCMBIS: 727 (void) sermctl(dev, *(int *) data, DMBIS); 728 break; 729 730 case TIOCMBIC: 731 (void) sermctl(dev, *(int *) data, DMBIC); 732 break; 733 734 case TIOCMGET: 735 *(int *)data = sermctl(dev, 0, DMGET); 736 break; 737 case TIOCGFLAGS: 738 *(int *)data = serswflags; 739 break; 740 case TIOCSFLAGS: 741 error = kauth_authorize_device_tty(l->l_cred, 742 KAUTH_DEVICE_TTY_PRIVSET, tp); 743 if (error != 0) 744 return(EPERM); 745 746 serswflags = *(int *)data; 747 serswflags &= /* only allow valid flags */ 748 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 749 break; 750 default: 751 return(EPASSTHROUGH); 752 } 753 754 return(0); 755 } 756 757 int 758 serparam(struct tty *tp, 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 if (serswflags & TIOCFLAG_SOFTCAR || serconsole == 0) { 772 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL; 773 } 774 775 /* if no changes, dont do anything. com.c explains why. */ 776 if (tp->t_ospeed == t->c_ospeed && 777 tp->t_cflag == t->c_cflag) 778 return (0); 779 780 cflag = t->c_cflag; 781 782 if (cflag & (CLOCAL | MDMBUF)) 783 serdcd = 0; 784 else 785 serdcd = CIAB_PRA_CD; 786 787 /* TODO: support multiple flow control protocols like com.c */ 788 789 /* 790 * copy to tty 791 */ 792 tp->t_ispeed = t->c_ispeed; 793 tp->t_ospeed = t->c_ospeed; 794 tp->t_cflag = cflag; 795 ser_open_speed = tp->t_ispeed; 796 797 /* 798 * enable interrupts 799 */ 800 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE; 801 last_ciab_pra = ciab.pra; 802 803 if (t->c_ospeed == 0) 804 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */ 805 else { 806 /* 807 * (re)enable DTR 808 * and set baud rate. (8 bit mode) 809 */ 810 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET); 811 custom.serper = (0 << 15) | ospeed; 812 } 813 (void)tp->t_linesw->l_modem(tp, ISDCD(last_ciab_pra)); 814 815 return(0); 816 } 817 818 int serhwiflow(struct tty *tp, int flag) 819 { 820 #if 0 821 printf ("serhwiflow %d\n", flag); 822 #endif 823 if (flag) 824 CLRRTS(ciab.pra); 825 else 826 SETRTS(ciab.pra); 827 return 1; 828 } 829 830 static void 831 ser_putchar(struct tty *tp, u_short c) 832 { 833 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB)) 834 c &= 0x7f; 835 836 /* 837 * handle parity if necessary 838 */ 839 if (tp->t_cflag & PARENB) { 840 if (even_parity[c]) 841 c |= 0x80; 842 if (tp->t_cflag & PARODD) 843 c ^= 0x80; 844 } 845 /* 846 * add stop bit(s) 847 */ 848 if (tp->t_cflag & CSTOPB) 849 c |= 0x300; 850 else 851 c |= 0x100; 852 853 custom.serdat = c; 854 } 855 856 857 static u_char ser_outbuf[SEROBUF_SIZE]; 858 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf; 859 860 void 861 ser_outintr(void) 862 { 863 struct tty *tp; 864 int s; 865 866 tp = ser_tty; 867 s = spltty(); 868 869 if (tp == 0) 870 goto out; 871 872 if ((custom.intreqr & INTF_TBE) == 0) 873 goto out; 874 875 /* 876 * clear interrupt 877 */ 878 custom.intreq = INTF_TBE; 879 880 if (sob_ptr == sob_end) { 881 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 882 if (tp->t_linesw) 883 tp->t_linesw->l_start(tp); 884 else 885 serstart(tp); 886 goto out; 887 } 888 889 /* 890 * Do hardware flow control here. if the CTS line goes down, don't 891 * transmit anything. That way, we'll be restarted by the periodic 892 * interrupt when CTS comes back up. 893 */ 894 if (ISCTS(ciab.pra)) 895 ser_putchar(tp, *sob_ptr++); 896 else 897 CLRCTS(last_ciab_pra); /* Remember that CTS is off */ 898 out: 899 splx(s); 900 } 901 902 void 903 serstart(struct tty *tp) 904 { 905 int cc, s, hiwat; 906 #ifdef DIAGNOSTIC 907 int unit; 908 #endif 909 910 hiwat = 0; 911 912 if ((tp->t_state & TS_ISOPEN) == 0) 913 return; 914 915 #ifdef DIAGNOSTIC 916 unit = SERUNIT(tp->t_dev); 917 if (unit) 918 panic("serstart: unit is %d", unit); 919 #endif 920 921 s = spltty(); 922 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 923 goto out; 924 925 cc = tp->t_outq.c_cc; 926 if (!ttypull(tp) || (tp->t_state & TS_BUSY)) 927 goto out; 928 929 /* 930 * We only do bulk transfers if using CTSRTS flow control, not for 931 * (probably sloooow) ixon/ixoff devices. 932 */ 933 if ((tp->t_cflag & CRTSCTS) == 0) 934 cc = 1; 935 936 /* 937 * Limit the amount of output we do in one burst 938 * to prevent hogging the CPU. 939 */ 940 if (cc > SEROBUF_SIZE) { 941 hiwat++; 942 cc = SEROBUF_SIZE; 943 } 944 cc = q_to_b(&tp->t_outq, ser_outbuf, cc); 945 if (cc > 0) { 946 tp->t_state |= TS_BUSY; 947 948 sob_ptr = ser_outbuf; 949 sob_end = ser_outbuf + cc; 950 951 /* 952 * Get first character out, then have TBE-interrupts blow out 953 * further characters, until buffer is empty, and TS_BUSY gets 954 * cleared. 955 */ 956 ser_putchar(tp, *sob_ptr++); 957 } 958 out: 959 splx(s); 960 } 961 962 /* 963 * Stop output on a line. 964 */ 965 /*ARGSUSED*/ 966 void 967 serstop(struct tty *tp, int flag) 968 { 969 int s; 970 971 s = spltty(); 972 if (tp->t_state & TS_BUSY) { 973 if ((tp->t_state & TS_TTSTOP) == 0) 974 tp->t_state |= TS_FLUSH; 975 } 976 splx(s); 977 } 978 979 int 980 sermctl(dev_t dev, int bits, int how) 981 { 982 int s; 983 u_char ub = 0; 984 985 /* 986 * convert TIOCM* mask into CIA mask 987 * which is active low 988 */ 989 if (how != DMGET) { 990 ub = 0; 991 if (bits & TIOCM_DTR) 992 ub |= CIAB_PRA_DTR; 993 if (bits & TIOCM_RTS) 994 ub |= CIAB_PRA_RTS; 995 if (bits & TIOCM_CTS) 996 ub |= CIAB_PRA_CTS; 997 if (bits & TIOCM_CD) 998 ub |= CIAB_PRA_CD; 999 if (bits & TIOCM_RI) 1000 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */ 1001 if (bits & TIOCM_DSR) 1002 ub |= CIAB_PRA_DSR; 1003 } 1004 s = spltty(); 1005 switch (how) { 1006 case DMSET: 1007 /* invert and set */ 1008 ciab.pra = ~ub; 1009 break; 1010 1011 case DMBIC: 1012 ciab.pra |= ub; 1013 ub = ~ciab.pra; 1014 break; 1015 1016 case DMBIS: 1017 ciab.pra &= ~ub; 1018 ub = ~ciab.pra; 1019 break; 1020 1021 case DMGET: 1022 ub = ~ciab.pra; 1023 break; 1024 } 1025 (void)splx(s); 1026 1027 bits = 0; 1028 if (ub & CIAB_PRA_DTR) 1029 bits |= TIOCM_DTR; 1030 if (ub & CIAB_PRA_RTS) 1031 bits |= TIOCM_RTS; 1032 if (ub & CIAB_PRA_CTS) 1033 bits |= TIOCM_CTS; 1034 if (ub & CIAB_PRA_CD) 1035 bits |= TIOCM_CD; 1036 if (ub & CIAB_PRA_SEL) 1037 bits |= TIOCM_RI; 1038 if (ub & CIAB_PRA_DSR) 1039 bits |= TIOCM_DSR; 1040 1041 return(bits); 1042 } 1043 1044 /* 1045 * Following are all routines needed for SER to act as console 1046 */ 1047 void 1048 sercnprobe(struct consdev *cp) 1049 { 1050 int maj, unit; 1051 #ifdef KGDB 1052 extern const struct cdevsw ctty_cdevsw; 1053 #endif 1054 1055 /* locate the major number */ 1056 maj = cdevsw_lookup_major(&ser_cdevsw); 1057 1058 1059 unit = CONUNIT; /* XXX: ick */ 1060 1061 /* 1062 * initialize required fields 1063 */ 1064 cp->cn_dev = makedev(maj, unit); 1065 if (serconsole == unit) 1066 cp->cn_pri = CN_REMOTE; 1067 else 1068 cp->cn_pri = CN_NORMAL; 1069 #ifdef KGDB 1070 /* XXX */ 1071 if (cdevsw_lookup(kgdb_dev) == &ctty_cdevsw) 1072 kgdb_dev = makedev(maj, minor(kgdb_dev)); 1073 #endif 1074 } 1075 1076 void 1077 sercninit(struct consdev *cp) 1078 { 1079 int unit; 1080 1081 unit = SERUNIT(cp->cn_dev); 1082 1083 serinit(serdefaultrate); 1084 serconsole = unit; 1085 serconsinit = 1; 1086 } 1087 1088 void 1089 serinit(int rate) 1090 { 1091 int s; 1092 1093 s = splser(); 1094 /* 1095 * might want to fiddle with the CIA later ??? 1096 */ 1097 custom.serper = (rate>=110 ? SERBRD(rate) : 0); 1098 splx(s); 1099 } 1100 1101 int 1102 sercngetc(dev_t dev) 1103 { 1104 u_short stat; 1105 int c, s; 1106 1107 s = splser(); 1108 /* 1109 * poll 1110 */ 1111 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0) 1112 ; 1113 1114 c = stat & 0xff; 1115 /* 1116 * clear interrupt 1117 */ 1118 custom.intreq = INTF_RBF; 1119 splx(s); 1120 1121 return(c); 1122 } 1123 1124 /* 1125 * Console kernel output character routine. 1126 */ 1127 void 1128 sercnputc(dev_t dev, int c) 1129 { 1130 register int timo; 1131 int s; 1132 1133 s = splhigh(); 1134 1135 if (serconsinit == 0) { 1136 (void)serinit(serdefaultrate); 1137 serconsinit = 1; 1138 } 1139 1140 /* 1141 * wait for any pending transmission to finish 1142 */ 1143 timo = 50000; 1144 while (!(custom.serdatr & SERDATRF_TBE) && --timo); 1145 1146 /* 1147 * transmit char. 1148 */ 1149 custom.serdat = (c & 0xff) | 0x100; 1150 1151 /* 1152 * wait for this transmission to complete 1153 */ 1154 timo = 1500000; 1155 while (!(custom.serdatr & SERDATRF_TBE) && --timo) 1156 ; 1157 1158 /* 1159 * Wait for the device (my vt100..) to process the data, since we 1160 * don't do flow-control with cnputc 1161 */ 1162 for (timo = 0; timo < 30000; timo++) 1163 ; 1164 1165 /* 1166 * We set TBE so that ser_outintr() is called right after to check 1167 * whether there still are chars to process. 1168 * We used to clear this, but it hung the tty output if the kernel 1169 * output a char while userland did on the same serial port. 1170 */ 1171 custom.intreq = INTF_SETCLR | INTF_TBE; 1172 splx(s); 1173 } 1174 1175 void 1176 sercnpollc(dev_t dev, int on) 1177 { 1178 } 1179 #endif 1180