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