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