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