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