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