1 /* $NetBSD: ser.c,v 1.87 2026/11/07 22:20:10 thorpej 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.87 2026/11/07 22:20:10 thorpej 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 if (!db_active) { 609 console_debugger(); 610 return; 611 } 612 } 613 #endif 614 } else { 615 break_in_progress = 0; 616 if ((tp->t_cflag & PARENB) && 617 (((ch >> 7) + even_parity[ch & 0x7f] 618 + !!(tp->t_cflag & PARODD)) & 1)) 619 c |= TTY_PE; 620 } 621 622 if (stat & SERDATRF_OVRUN) 623 log(LOG_WARNING, "ser0: silo overflow\n"); 624 625 tp->t_linesw->l_rint(c, tp); 626 } 627 628 /* 629 * This interrupt is periodically invoked in the vertical blank 630 * interrupt. It's used to keep track of the modem control lines 631 * and (new with the fast_int code) to move accumulated data 632 * up into the tty layer. 633 */ 634 void 635 sermint(int unit) 636 { 637 struct tty *tp; 638 u_char stat, last, istat; 639 640 tp = ser_tty; 641 if (!tp) 642 return; 643 644 /* 645 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) { 646 sbrpt = sbwpt = serbuf; 647 return; 648 } 649 */ 650 /* 651 * empty buffer 652 */ 653 serintr(); 654 655 stat = ciab.pra; 656 last = last_ciab_pra; 657 last_ciab_pra = stat; 658 659 /* 660 * check whether any interesting signal changed state 661 */ 662 istat = stat ^ last; 663 664 if (istat & serdcd) { 665 tp->t_linesw->l_modem(tp, ISDCD(stat)); 666 } 667 668 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) && 669 (tp->t_cflag & CRTSCTS)) { 670 #if 0 671 /* the line is up and we want to do rts/cts flow control */ 672 if (ISCTS(stat)) { 673 tp->t_state &= ~TS_TTSTOP; 674 ttstart(tp); 675 /* cause tbe-int if we were stuck there */ 676 custom.intreq = INTF_SETCLR | INTF_TBE; 677 } else 678 tp->t_state |= TS_TTSTOP; 679 #else 680 /* do this on hardware level, not with tty driver */ 681 if (ISCTS(stat)) { 682 tp->t_state &= ~TS_TTSTOP; 683 /* cause TBE interrupt */ 684 custom.intreq = INTF_SETCLR | INTF_TBE; 685 } 686 #endif 687 } 688 } 689 690 int 691 serioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 692 { 693 register struct tty *tp; 694 register int error; 695 696 tp = ser_tty; 697 if (!tp) 698 return ENXIO; 699 700 error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); 701 if (error != EPASSTHROUGH) 702 return(error); 703 704 error = ttioctl(tp, cmd, data, flag, l); 705 if (error != EPASSTHROUGH) 706 return(error); 707 708 switch (cmd) { 709 case TIOCSBRK: 710 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK; 711 break; 712 713 case TIOCCBRK: 714 custom.adkcon = ADKCONF_UARTBRK; 715 break; 716 717 case TIOCSDTR: 718 (void) sermctl(dev, TIOCM_DTR, DMBIS); 719 break; 720 721 case TIOCCDTR: 722 (void) sermctl(dev, TIOCM_DTR, DMBIC); 723 break; 724 725 case TIOCMSET: 726 (void) sermctl(dev, *(int *) data, DMSET); 727 break; 728 729 case TIOCMBIS: 730 (void) sermctl(dev, *(int *) data, DMBIS); 731 break; 732 733 case TIOCMBIC: 734 (void) sermctl(dev, *(int *) data, DMBIC); 735 break; 736 737 case TIOCMGET: 738 *(int *)data = sermctl(dev, 0, DMGET); 739 break; 740 case TIOCGFLAGS: 741 *(int *)data = serswflags; 742 break; 743 case TIOCSFLAGS: 744 error = kauth_authorize_device_tty(l->l_cred, 745 KAUTH_DEVICE_TTY_PRIVSET, tp); 746 if (error != 0) 747 return(EPERM); 748 749 serswflags = *(int *)data; 750 serswflags &= /* only allow valid flags */ 751 (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); 752 break; 753 default: 754 return(EPASSTHROUGH); 755 } 756 757 return(0); 758 } 759 760 int 761 serparam(struct tty *tp, struct termios *t) 762 { 763 int cflag, ospeed = 0; 764 765 if (t->c_ospeed > 0) { 766 if (t->c_ospeed < 110) 767 return(EINVAL); 768 ospeed = SERBRD(t->c_ospeed); 769 } 770 771 if (t->c_ispeed && t->c_ispeed != t->c_ospeed) 772 return(EINVAL); 773 774 if (serswflags & TIOCFLAG_SOFTCAR || serconsole == 0) { 775 t->c_cflag = (t->c_cflag & ~HUPCL) | CLOCAL; 776 } 777 778 /* if no changes, dont do anything. com.c explains why. */ 779 if (tp->t_ospeed == t->c_ospeed && 780 tp->t_cflag == t->c_cflag) 781 return (0); 782 783 cflag = t->c_cflag; 784 785 if (cflag & (CLOCAL | MDMBUF)) 786 serdcd = 0; 787 else 788 serdcd = CIAB_PRA_CD; 789 790 /* TODO: support multiple flow control protocols like com.c */ 791 792 /* 793 * copy to tty 794 */ 795 tp->t_ispeed = t->c_ispeed; 796 tp->t_ospeed = t->c_ospeed; 797 tp->t_cflag = cflag; 798 ser_open_speed = tp->t_ispeed; 799 800 /* 801 * enable interrupts 802 */ 803 custom.intena = INTF_SETCLR | INTF_RBF | INTF_TBE; 804 last_ciab_pra = ciab.pra; 805 806 if (t->c_ospeed == 0) 807 (void)sermctl(tp->t_dev, 0, DMSET); /* hang up line */ 808 else { 809 /* 810 * (re)enable DTR 811 * and set baud rate. (8 bit mode) 812 */ 813 (void)sermctl(tp->t_dev, TIOCM_DTR, DMSET); 814 custom.serper = (0 << 15) | ospeed; 815 } 816 (void)tp->t_linesw->l_modem(tp, ISDCD(last_ciab_pra)); 817 818 return(0); 819 } 820 821 int serhwiflow(struct tty *tp, int flag) 822 { 823 #if 0 824 printf ("serhwiflow %d\n", flag); 825 #endif 826 if (flag) 827 CLRRTS(ciab.pra); 828 else 829 SETRTS(ciab.pra); 830 return 1; 831 } 832 833 static void 834 ser_putchar(struct tty *tp, u_short c) 835 { 836 if ((tp->t_cflag & CSIZE) == CS7 || (tp->t_cflag & PARENB)) 837 c &= 0x7f; 838 839 /* 840 * handle parity if necessary 841 */ 842 if (tp->t_cflag & PARENB) { 843 if (even_parity[c]) 844 c |= 0x80; 845 if (tp->t_cflag & PARODD) 846 c ^= 0x80; 847 } 848 /* 849 * add stop bit(s) 850 */ 851 if (tp->t_cflag & CSTOPB) 852 c |= 0x300; 853 else 854 c |= 0x100; 855 856 custom.serdat = c; 857 } 858 859 860 static u_char ser_outbuf[SEROBUF_SIZE]; 861 static u_char *sob_ptr = ser_outbuf, *sob_end = ser_outbuf; 862 863 void 864 ser_outintr(void) 865 { 866 struct tty *tp; 867 int s; 868 869 tp = ser_tty; 870 s = spltty(); 871 872 if (tp == 0) 873 goto out; 874 875 if ((custom.intreqr & INTF_TBE) == 0) 876 goto out; 877 878 /* 879 * clear interrupt 880 */ 881 custom.intreq = INTF_TBE; 882 883 if (sob_ptr == sob_end) { 884 tp->t_state &= ~(TS_BUSY | TS_FLUSH); 885 if (tp->t_linesw) 886 tp->t_linesw->l_start(tp); 887 else 888 serstart(tp); 889 goto out; 890 } 891 892 /* 893 * Do hardware flow control here. if the CTS line goes down, don't 894 * transmit anything. That way, we'll be restarted by the periodic 895 * interrupt when CTS comes back up. 896 */ 897 if (ISCTS(ciab.pra)) 898 ser_putchar(tp, *sob_ptr++); 899 else 900 CLRCTS(last_ciab_pra); /* Remember that CTS is off */ 901 out: 902 splx(s); 903 } 904 905 void 906 serstart(struct tty *tp) 907 { 908 int cc, s, hiwat; 909 #ifdef DIAGNOSTIC 910 int unit; 911 #endif 912 913 hiwat = 0; 914 915 if ((tp->t_state & TS_ISOPEN) == 0) 916 return; 917 918 #ifdef DIAGNOSTIC 919 unit = SERUNIT(tp->t_dev); 920 if (unit) 921 panic("serstart: unit is %d", unit); 922 #endif 923 924 s = spltty(); 925 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) 926 goto out; 927 928 cc = tp->t_outq.c_cc; 929 if (!ttypull(tp) || (tp->t_state & TS_BUSY)) 930 goto out; 931 932 /* 933 * We only do bulk transfers if using CTSRTS flow control, not for 934 * (probably sloooow) ixon/ixoff devices. 935 */ 936 if ((tp->t_cflag & CRTSCTS) == 0) 937 cc = 1; 938 939 /* 940 * Limit the amount of output we do in one burst 941 * to prevent hogging the CPU. 942 */ 943 if (cc > SEROBUF_SIZE) { 944 hiwat++; 945 cc = SEROBUF_SIZE; 946 } 947 cc = q_to_b(&tp->t_outq, ser_outbuf, cc); 948 if (cc > 0) { 949 tp->t_state |= TS_BUSY; 950 951 sob_ptr = ser_outbuf; 952 sob_end = ser_outbuf + cc; 953 954 /* 955 * Get first character out, then have TBE-interrupts blow out 956 * further characters, until buffer is empty, and TS_BUSY gets 957 * cleared. 958 */ 959 ser_putchar(tp, *sob_ptr++); 960 } 961 out: 962 splx(s); 963 } 964 965 /* 966 * Stop output on a line. 967 */ 968 /*ARGSUSED*/ 969 void 970 serstop(struct tty *tp, int flag) 971 { 972 int s; 973 974 s = spltty(); 975 if (tp->t_state & TS_BUSY) { 976 if ((tp->t_state & TS_TTSTOP) == 0) 977 tp->t_state |= TS_FLUSH; 978 } 979 splx(s); 980 } 981 982 int 983 sermctl(dev_t dev, int bits, int how) 984 { 985 int s; 986 u_char ub = 0; 987 988 /* 989 * convert TIOCM* mask into CIA mask 990 * which is active low 991 */ 992 if (how != DMGET) { 993 ub = 0; 994 if (bits & TIOCM_DTR) 995 ub |= CIAB_PRA_DTR; 996 if (bits & TIOCM_RTS) 997 ub |= CIAB_PRA_RTS; 998 if (bits & TIOCM_CTS) 999 ub |= CIAB_PRA_CTS; 1000 if (bits & TIOCM_CD) 1001 ub |= CIAB_PRA_CD; 1002 if (bits & TIOCM_RI) 1003 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */ 1004 if (bits & TIOCM_DSR) 1005 ub |= CIAB_PRA_DSR; 1006 } 1007 s = spltty(); 1008 switch (how) { 1009 case DMSET: 1010 /* invert and set */ 1011 ciab.pra = ~ub; 1012 break; 1013 1014 case DMBIC: 1015 ciab.pra |= ub; 1016 ub = ~ciab.pra; 1017 break; 1018 1019 case DMBIS: 1020 ciab.pra &= ~ub; 1021 ub = ~ciab.pra; 1022 break; 1023 1024 case DMGET: 1025 ub = ~ciab.pra; 1026 break; 1027 } 1028 (void)splx(s); 1029 1030 bits = 0; 1031 if (ub & CIAB_PRA_DTR) 1032 bits |= TIOCM_DTR; 1033 if (ub & CIAB_PRA_RTS) 1034 bits |= TIOCM_RTS; 1035 if (ub & CIAB_PRA_CTS) 1036 bits |= TIOCM_CTS; 1037 if (ub & CIAB_PRA_CD) 1038 bits |= TIOCM_CD; 1039 if (ub & CIAB_PRA_SEL) 1040 bits |= TIOCM_RI; 1041 if (ub & CIAB_PRA_DSR) 1042 bits |= TIOCM_DSR; 1043 1044 return(bits); 1045 } 1046 1047 /* 1048 * Following are all routines needed for SER to act as console 1049 */ 1050 void 1051 sercnprobe(struct consdev *cp) 1052 { 1053 int maj, unit; 1054 #ifdef KGDB 1055 extern const struct cdevsw ctty_cdevsw; 1056 #endif 1057 1058 /* locate the major number */ 1059 maj = cdevsw_lookup_major(&ser_cdevsw); 1060 1061 1062 unit = CONUNIT; /* XXX: ick */ 1063 1064 /* 1065 * initialize required fields 1066 */ 1067 cp->cn_dev = makedev(maj, unit); 1068 if (serconsole == unit) 1069 cp->cn_pri = CN_REMOTE; 1070 else 1071 cp->cn_pri = CN_NORMAL; 1072 #ifdef KGDB 1073 /* XXX */ 1074 if (cdevsw_lookup(kgdb_dev) == &ctty_cdevsw) 1075 kgdb_dev = makedev(maj, minor(kgdb_dev)); 1076 #endif 1077 } 1078 1079 void 1080 sercninit(struct consdev *cp) 1081 { 1082 int unit; 1083 1084 unit = SERUNIT(cp->cn_dev); 1085 1086 serinit(serdefaultrate); 1087 serconsole = unit; 1088 serconsinit = 1; 1089 } 1090 1091 void 1092 serinit(int rate) 1093 { 1094 int s; 1095 1096 s = splser(); 1097 /* 1098 * might want to fiddle with the CIA later ??? 1099 */ 1100 custom.serper = (rate>=110 ? SERBRD(rate) : 0); 1101 splx(s); 1102 } 1103 1104 int 1105 sercngetc(dev_t dev) 1106 { 1107 u_short stat; 1108 int c, s; 1109 1110 s = splser(); 1111 /* 1112 * poll 1113 */ 1114 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0) 1115 ; 1116 1117 c = stat & 0xff; 1118 /* 1119 * clear interrupt 1120 */ 1121 custom.intreq = INTF_RBF; 1122 splx(s); 1123 1124 return(c); 1125 } 1126 1127 /* 1128 * Console kernel output character routine. 1129 */ 1130 void 1131 sercnputc(dev_t dev, int c) 1132 { 1133 register int timo; 1134 int s; 1135 1136 s = splhigh(); 1137 1138 if (serconsinit == 0) { 1139 (void)serinit(serdefaultrate); 1140 serconsinit = 1; 1141 } 1142 1143 /* 1144 * wait for any pending transmission to finish 1145 */ 1146 timo = 50000; 1147 while (!(custom.serdatr & SERDATRF_TBE) && --timo); 1148 1149 /* 1150 * transmit char. 1151 */ 1152 custom.serdat = (c & 0xff) | 0x100; 1153 1154 /* 1155 * wait for this transmission to complete 1156 */ 1157 timo = 1500000; 1158 while (!(custom.serdatr & SERDATRF_TBE) && --timo) 1159 ; 1160 1161 /* 1162 * Wait for the device (my vt100..) to process the data, since we 1163 * don't do flow-control with cnputc 1164 */ 1165 for (timo = 0; timo < 30000; timo++) 1166 ; 1167 1168 /* 1169 * We set TBE so that ser_outintr() is called right after to check 1170 * whether there still are chars to process. 1171 * We used to clear this, but it hung the tty output if the kernel 1172 * output a char while userland did on the same serial port. 1173 */ 1174 custom.intreq = INTF_SETCLR | INTF_TBE; 1175 splx(s); 1176 } 1177 1178 void 1179 sercnpollc(dev_t dev, int on) 1180 { 1181 } 1182 #endif 1183