1 /* $NetBSD: ser.c,v 1.86 2022/10/26 23:38:06 riastradh 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.86 2022/10/26 23:38:06 riastradh 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 <ddb/db_active.h> 68 69 #include "ser.h" 70 #if NSER > 0 71 72 void serattach(device_t, device_t, void *); 73 int sermatch(device_t, cfdata_t, void *); 74 75 struct ser_softc { 76 struct tty *ser_tty; 77 }; 78 79 CFATTACH_DECL_NEW(ser, sizeof(struct ser_softc), 80 sermatch, serattach, NULL, NULL); 81 82 extern struct cfdriver ser_cd; 83 84 dev_type_open(seropen); 85 dev_type_close(serclose); 86 dev_type_read(serread); 87 dev_type_write(serwrite); 88 dev_type_ioctl(serioctl); 89 dev_type_stop(serstop); 90 dev_type_tty(sertty); 91 dev_type_poll(serpoll); 92 93 const struct cdevsw ser_cdevsw = { 94 .d_open = seropen, 95 .d_close = serclose, 96 .d_read = serread, 97 .d_write = serwrite, 98 .d_ioctl = serioctl, 99 .d_stop = serstop, 100 .d_tty = sertty, 101 .d_poll = serpoll, 102 .d_mmap = nommap, 103 .d_kqfilter = ttykqfilter, 104 .d_discard = nodiscard, 105 .d_flag = D_TTY 106 }; 107 108 #ifndef SEROBUF_SIZE 109 #define SEROBUF_SIZE 32 110 #endif 111 #ifndef SERIBUF_SIZE 112 #define SERIBUF_SIZE 512 113 #endif 114 115 #define splser() spl5() 116 117 void serstart(struct tty *); 118 void ser_shutdown(struct ser_softc *); 119 int serparam(struct tty *, struct termios *); 120 void serintr(void); 121 int serhwiflow(struct tty *, int); 122 int sermctl(dev_t dev, int, int); 123 void ser_fastint(void); 124 void sereint(int); 125 static void ser_putchar(struct tty *, u_short); 126 void ser_outintr(void); 127 void sercnprobe(struct consdev *); 128 void sercninit(struct consdev *); 129 void serinit(int); 130 int sercngetc(dev_t dev); 131 void sercnputc(dev_t, int); 132 void sercnpollc(dev_t, int); 133 134 int nser = NSER; 135 #ifdef SERCONSOLE 136 int serconsole = 0; 137 #else 138 int serconsole = -1; 139 #endif 140 int serconsinit; 141 int serdefaultrate = TTYDEF_SPEED; 142 int serswflags; 143 144 struct vbl_node ser_vbl_node; 145 struct tty ser_cons; 146 struct tty *ser_tty; 147 148 static u_short serbuf[SERIBUF_SIZE]; 149 static u_short *sbrpt = serbuf; 150 static u_short *sbwpt = serbuf; 151 static u_short sbcnt; 152 static u_short sbovfl; 153 static u_char serdcd; 154 155 /* 156 * Since this UART is not particularly bright (to put it nicely), we'll 157 * have to do parity stuff on our own. This table contains the 8th bit 158 * in 7bit character mode, for even parity. If you want odd parity, 159 * flip the bit. (for generation of the table, see genpar.c) 160 */ 161 162 u_char even_parity[] = { 163 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 164 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 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 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 168 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 169 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 170 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 171 }; 172 173 /* 174 * Since we don't get interrupts for changes on the modem control line, 175 * we'll have to fake them by comparing current settings to the settings 176 * we remembered on last invocation. 177 */ 178 179 u_char last_ciab_pra; 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 accumulated 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 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