1 /* $NetBSD: ser.c,v 1.72 2006/05/14 21:55:09 elad 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.72 2006/05/14 21:55:09 elad 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/malloc.h> 53 #include <sys/uio.h> 54 #include <sys/kernel.h> 55 #include <sys/syslog.h> 56 #include <sys/queue.h> 57 #include <sys/conf.h> 58 #include <sys/kauth.h> 59 #include <machine/cpu.h> 60 #include <amiga/amiga/device.h> 61 #include <amiga/dev/serreg.h> 62 #include <amiga/amiga/custom.h> 63 #include <amiga/amiga/cia.h> 64 #include <amiga/amiga/cc.h> 65 66 #include <dev/cons.h> 67 68 #include "ser.h" 69 #if NSER > 0 70 71 void serattach(struct device *, struct device *, void *); 72 int sermatch(struct device *, struct cfdata *, void *); 73 74 struct ser_softc { 75 struct device dev; 76 struct tty *ser_tty; 77 }; 78 79 CFATTACH_DECL(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 seropen, serclose, serread, serwrite, serioctl, 95 serstop, sertty, serpoll, nommap, ttykqfilter, D_TTY 96 }; 97 98 #ifndef SEROBUF_SIZE 99 #define SEROBUF_SIZE 32 100 #endif 101 #ifndef SERIBUF_SIZE 102 #define SERIBUF_SIZE 512 103 #endif 104 105 #define splser() spl5() 106 107 void serstart(struct tty *); 108 void ser_shutdown(struct ser_softc *); 109 int serparam(struct tty *, struct termios *); 110 void serintr(void); 111 int serhwiflow(struct tty *, int); 112 int sermctl(dev_t dev, int, int); 113 void ser_fastint(void); 114 void sereint(int); 115 static void ser_putchar(struct tty *, u_short); 116 void ser_outintr(void); 117 void sercnprobe(struct consdev *); 118 void sercninit(struct consdev *); 119 void serinit(int); 120 int sercngetc(dev_t dev); 121 void sercnputc(dev_t, int); 122 void sercnpollc(dev_t, int); 123 124 int nser = NSER; 125 #ifdef SERCONSOLE 126 int serconsole = 0; 127 #else 128 int serconsole = -1; 129 #endif 130 int serconsinit; 131 int serdefaultrate = TTYDEF_SPEED; 132 int serswflags; 133 134 struct vbl_node ser_vbl_node; 135 struct tty ser_cons; 136 struct tty *ser_tty; 137 138 static u_short serbuf[SERIBUF_SIZE]; 139 static u_short *sbrpt = serbuf; 140 static u_short *sbwpt = serbuf; 141 static u_short sbcnt; 142 static u_short sbovfl; 143 static u_char serdcd; 144 145 /* 146 * Since this UART is not particularly bright (to put it nicely), we'll 147 * have to do parity stuff on our own. This table contains the 8th bit 148 * in 7bit character mode, for even parity. If you want odd parity, 149 * flip the bit. (for generation of the table, see genpar.c) 150 */ 151 152 u_char even_parity[] = { 153 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 154 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 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 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 158 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 159 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 160 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 161 }; 162 163 /* 164 * Since we don't get interrupts for changes on the modem control line, 165 * we'll have to fake them by comparing current settings to the settings 166 * we remembered on last invocation. 167 */ 168 169 u_char last_ciab_pra; 170 171 extern struct tty *constty; 172 173 extern int ser_open_speed; /* current speed of open serial device */ 174 175 #ifdef KGDB 176 #include <machine/remote-sl.h> 177 178 extern dev_t kgdb_dev; 179 extern int kgdb_rate; 180 extern int kgdb_debug_init; 181 #endif 182 183 #ifdef DEBUG 184 long fifoin[17]; 185 long fifoout[17]; 186 long serintrcount[16]; 187 long sermintcount[16]; 188 #endif 189 190 void sermint(register int unit); 191 192 int 193 sermatch(struct device *pdp, struct cfdata *cfp, void *auxp) 194 { 195 static int ser_matched = 0; 196 static int ser_matched_real = 0; 197 198 /* Allow only once instance. */ 199 if (matchname("ser", (char *)auxp) == 0) 200 return(0); 201 202 if (amiga_realconfig) { 203 if (ser_matched_real) 204 return(0); 205 ser_matched_real = 1; 206 } else { 207 if (serconsole != 0) 208 return(0); 209 210 if (ser_matched != 0) 211 return(0); 212 213 ser_matched = 1; 214 } 215 return(1); 216 } 217 218 219 void 220 serattach(struct device *pdp, struct device *dp, void *auxp) 221 { 222 struct ser_softc *sc; 223 struct tty *tp; 224 u_short ir; 225 226 sc = (struct ser_softc *)dp; 227 228 ir = custom.intenar; 229 if (serconsole == 0) 230 DELAY(100000); 231 232 ser_vbl_node.function = (void (*) (void *)) sermint; 233 add_vbl_function(&ser_vbl_node, SER_VBL_PRIORITY, (void *) 0); 234 #ifdef KGDB 235 if (kgdb_dev == makedev(cdevsw_lookup_major(&ser_cdevsw), 0)) { 236 if (serconsole == 0) 237 kgdb_dev = NODEV; /* can't debug over console port */ 238 else { 239 (void) serinit(kgdb_rate); 240 serconsinit = 1; /* don't re-init in serputc */ 241 if (kgdb_debug_init == 0) 242 printf(" kgdb enabled\n"); 243 else { 244 /* 245 * Print prefix of device name, 246 * let kgdb_connect print the rest. 247 */ 248 printf("ser0: "); 249 kgdb_connect(1); 250 } 251 } 252 } 253 #endif 254 /* 255 * Need to reset baud rate, etc. of next print so reset serconsinit. 256 */ 257 if (0 == serconsole) 258 serconsinit = 0; 259 260 tp = ttymalloc(); 261 tp->t_oproc = (void (*) (struct tty *)) serstart; 262 tp->t_param = serparam; 263 tp->t_hwiflow = serhwiflow; 264 tty_attach(tp); 265 sc->ser_tty = ser_tty = tp; 266 267 if (dp) 268 printf(": input fifo %d output fifo %d\n", SERIBUF_SIZE, 269 SEROBUF_SIZE); 270 } 271 272 273 /* ARGSUSED */ 274 int 275 seropen(dev_t dev, int flag, int mode, struct lwp *l) 276 { 277 struct ser_softc *sc; 278 struct tty *tp; 279 int unit, error, s, s2; 280 281 error = 0; 282 unit = SERUNIT(dev); 283 284 if (unit >= ser_cd.cd_ndevs) 285 return (ENXIO); 286 287 sc = ser_cd.cd_devs[unit]; 288 if (sc == 0) 289 return (ENXIO); 290 291 /* XXX com.c: insert KGDB check here */ 292 293 /* XXX ser.c had: s = spltty(); */ 294 295 tp = sc->ser_tty; 296 297 if ((tp->t_state & TS_ISOPEN) && 298 (tp->t_state & TS_XCLUDE) && 299 kauth_authorize_generic(l->l_proc->p_cred, 300 KAUTH_GENERIC_ISSUSER, 301 &l->l_proc->p_acflag) != 0) 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 = ser_cd.cd_devs[0]; 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 ttyfree(tp); 430 ser_tty = (struct tty *) NULL; 431 } 432 #endif 433 ser_open_speed = tp->t_ispeed; 434 return; 435 } 436 437 int 438 serread(dev_t dev, struct uio *uio, int flag) 439 { 440 /* ARGSUSED */ 441 442 return ser_tty->t_linesw->l_read(ser_tty, uio, flag); 443 } 444 445 int 446 serwrite(dev_t dev, struct uio *uio, int flag) 447 { 448 /* ARGSUSED */ 449 450 return ser_tty->t_linesw->l_write(ser_tty, uio, flag); 451 } 452 453 int 454 serpoll(dev_t dev, int events, struct lwp *l) 455 { 456 /* ARGSUSED */ 457 458 return ser_tty->t_linesw->l_poll(ser_tty, events, l); 459 } 460 461 struct tty * 462 sertty(dev_t dev) 463 { 464 /* ARGSUSED */ 465 466 return (ser_tty); 467 } 468 469 /* 470 * We don't do any processing of data here, so we store the raw code 471 * obtained from the uart register. In theory, 110kBaud gives you 472 * 11kcps, so 16k buffer should be more than enough, interrupt 473 * latency of 1s should never happen, or something is seriously 474 * wrong.. 475 * buffers moved to above seropen() -is 476 */ 477 478 /* 479 * This is a replacement for the lack of a hardware fifo. 32k should be 480 * enough (there's only one unit anyway, so this is not going to 481 * accumulate). 482 */ 483 void 484 ser_fastint(void) 485 { 486 /* 487 * We're at RBE-level, which is higher than VBL-level which is used 488 * to periodically transmit contents of this buffer up one layer, 489 * so no spl-raising is necessary. 490 */ 491 u_short code; 492 493 /* 494 * This register contains both data and status bits! 495 */ 496 code = custom.serdatr; 497 498 /* 499 * Use SERDATF_RBF instead of INTF_RBF; they're equivalent, but 500 * we save one (slow) custom chip access. 501 */ 502 if ((code & SERDATRF_RBF) == 0) 503 return; 504 505 /* 506 * clear interrupt 507 */ 508 custom.intreq = INTF_RBF; 509 510 /* 511 * check for buffer overflow. 512 */ 513 if (sbcnt == SERIBUF_SIZE) { 514 ++sbovfl; 515 return; 516 } 517 /* 518 * store in buffer 519 */ 520 *sbwpt++ = code; 521 if (sbwpt == serbuf + SERIBUF_SIZE) 522 sbwpt = serbuf; 523 ++sbcnt; 524 if (sbcnt > SERIBUF_SIZE - 20) 525 CLRRTS(ciab.pra); /* drop RTS if buffer almost full */ 526 } 527 528 529 void 530 serintr(void) 531 { 532 int s1, s2, ovfl; 533 struct tty *tp = ser_tty; 534 535 /* 536 * Make sure we're not interrupted by another 537 * vbl, but allow level5 ints 538 */ 539 s1 = spltty(); 540 541 /* 542 * pass along any acumulated information 543 */ 544 while (sbcnt > 0 && (tp->t_state & TS_TBLOCK) == 0) { 545 /* 546 * no collision with ser_fastint() 547 */ 548 sereint(*sbrpt++); 549 550 ovfl = 0; 551 /* lock against ser_fastint() */ 552 s2 = splser(); 553 sbcnt--; 554 if (sbrpt == serbuf + SERIBUF_SIZE) 555 sbrpt = serbuf; 556 if (sbovfl != 0) { 557 ovfl = sbovfl; 558 sbovfl = 0; 559 } 560 splx(s2); 561 if (ovfl != 0) 562 log(LOG_WARNING, "ser0: %d ring buffer overflows.\n", 563 ovfl); 564 } 565 s2 = splser(); 566 if (sbcnt == 0 && (tp->t_state & TS_TBLOCK) == 0) 567 SETRTS(ciab.pra); /* start accepting data again */ 568 splx(s2); 569 splx(s1); 570 } 571 572 void 573 sereint(int stat) 574 { 575 static int break_in_progress = 0; 576 struct tty *tp; 577 u_char ch; 578 int c; 579 580 tp = ser_tty; 581 ch = stat & 0xff; 582 c = ch; 583 584 if ((tp->t_state & TS_ISOPEN) == 0) { 585 #ifdef KGDB 586 int maj; 587 588 /* we don't care about parity errors */ 589 maj = cdevsw_lookup_major(&ser_cdevsw); 590 if (kgdb_dev == makedev(maj, 0) && c == FRAME_END) 591 kgdb_connect(0); /* trap into kgdb */ 592 #endif 593 return; 594 } 595 596 /* 597 * Check for break and (if enabled) parity error. 598 */ 599 if ((stat & 0x1ff) == 0) { 600 if (break_in_progress) 601 return; 602 603 c = TTY_FE; 604 break_in_progress = 1; 605 #ifdef DDB 606 if (serconsole == 0) { 607 extern int db_active; 608 609 if (!db_active) { 610 console_debugger(); 611 return; 612 } 613 } 614 #endif 615 } else { 616 break_in_progress = 0; 617 if ((tp->t_cflag & PARENB) && 618 (((ch >> 7) + even_parity[ch & 0x7f] 619 + !!(tp->t_cflag & PARODD)) & 1)) 620 c |= TTY_PE; 621 } 622 623 if (stat & SERDATRF_OVRUN) 624 log(LOG_WARNING, "ser0: silo overflow\n"); 625 626 tp->t_linesw->l_rint(c, tp); 627 } 628 629 /* 630 * This interrupt is periodically invoked in the vertical blank 631 * interrupt. It's used to keep track of the modem control lines 632 * and (new with the fast_int code) to move accumulated data 633 * up into the tty layer. 634 */ 635 void 636 sermint(int unit) 637 { 638 struct tty *tp; 639 u_char stat, last, istat; 640 641 tp = ser_tty; 642 if (!tp) 643 return; 644 645 /* 646 if ((tp->t_state & TS_ISOPEN) == 0 || tp->t_wopen == 0) { 647 sbrpt = sbwpt = serbuf; 648 return; 649 } 650 */ 651 /* 652 * empty buffer 653 */ 654 serintr(); 655 656 stat = ciab.pra; 657 last = last_ciab_pra; 658 last_ciab_pra = stat; 659 660 /* 661 * check whether any interesting signal changed state 662 */ 663 istat = stat ^ last; 664 665 if (istat & serdcd) { 666 tp->t_linesw->l_modem(tp, ISDCD(stat)); 667 } 668 669 if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) && 670 (tp->t_cflag & CRTSCTS)) { 671 #if 0 672 /* the line is up and we want to do rts/cts flow control */ 673 if (ISCTS(stat)) { 674 tp->t_state &= ~TS_TTSTOP; 675 ttstart(tp); 676 /* cause tbe-int if we were stuck there */ 677 custom.intreq = INTF_SETCLR | INTF_TBE; 678 } else 679 tp->t_state |= TS_TTSTOP; 680 #else 681 /* do this on hardware level, not with tty driver */ 682 if (ISCTS(stat)) { 683 tp->t_state &= ~TS_TTSTOP; 684 /* cause TBE interrupt */ 685 custom.intreq = INTF_SETCLR | INTF_TBE; 686 } 687 #endif 688 } 689 } 690 691 int 692 serioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l) 693 { 694 register struct tty *tp; 695 register int error; 696 697 tp = ser_tty; 698 if (!tp) 699 return ENXIO; 700 701 error = tp->t_linesw->l_ioctl(tp, cmd, data, flag, l); 702 if (error != EPASSTHROUGH) 703 return(error); 704 705 error = ttioctl(tp, cmd, data, flag, l); 706 if (error != EPASSTHROUGH) 707 return(error); 708 709 switch (cmd) { 710 case TIOCSBRK: 711 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK; 712 break; 713 714 case TIOCCBRK: 715 custom.adkcon = ADKCONF_UARTBRK; 716 break; 717 718 case TIOCSDTR: 719 (void) sermctl(dev, TIOCM_DTR, DMBIS); 720 break; 721 722 case TIOCCDTR: 723 (void) sermctl(dev, TIOCM_DTR, DMBIC); 724 break; 725 726 case TIOCMSET: 727 (void) sermctl(dev, *(int *) data, DMSET); 728 break; 729 730 case TIOCMBIS: 731 (void) sermctl(dev, *(int *) data, DMBIS); 732 break; 733 734 case TIOCMBIC: 735 (void) sermctl(dev, *(int *) data, DMBIC); 736 break; 737 738 case TIOCMGET: 739 *(int *)data = sermctl(dev, 0, DMGET); 740 break; 741 case TIOCGFLAGS: 742 *(int *)data = serswflags; 743 break; 744 case TIOCSFLAGS: 745 error = kauth_authorize_generic(l->l_proc->p_cred, 746 KAUTH_GENERIC_ISSUSER, 747 &l->l_proc->p_acflag); 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 (cc <= tp->t_lowat) { 932 if (tp->t_state & TS_ASLEEP) { 933 tp->t_state &= ~TS_ASLEEP; 934 wakeup((caddr_t) & tp->t_outq); 935 } 936 selwakeup(&tp->t_wsel); 937 } 938 if (cc == 0 || (tp->t_state & TS_BUSY)) 939 goto out; 940 941 /* 942 * We only do bulk transfers if using CTSRTS flow control, not for 943 * (probably sloooow) ixon/ixoff devices. 944 */ 945 if ((tp->t_cflag & CRTSCTS) == 0) 946 cc = 1; 947 948 /* 949 * Limit the amount of output we do in one burst 950 * to prevent hogging the CPU. 951 */ 952 if (cc > SEROBUF_SIZE) { 953 hiwat++; 954 cc = SEROBUF_SIZE; 955 } 956 cc = q_to_b(&tp->t_outq, ser_outbuf, cc); 957 if (cc > 0) { 958 tp->t_state |= TS_BUSY; 959 960 sob_ptr = ser_outbuf; 961 sob_end = ser_outbuf + cc; 962 963 /* 964 * Get first character out, then have TBE-interrupts blow out 965 * further characters, until buffer is empty, and TS_BUSY gets 966 * cleared. 967 */ 968 ser_putchar(tp, *sob_ptr++); 969 } 970 out: 971 splx(s); 972 } 973 974 /* 975 * Stop output on a line. 976 */ 977 /*ARGSUSED*/ 978 void 979 serstop(struct tty *tp, int flag) 980 { 981 int s; 982 983 s = spltty(); 984 if (tp->t_state & TS_BUSY) { 985 if ((tp->t_state & TS_TTSTOP) == 0) 986 tp->t_state |= TS_FLUSH; 987 } 988 splx(s); 989 } 990 991 int 992 sermctl(dev_t dev, int bits, int how) 993 { 994 int s; 995 u_char ub = 0; 996 997 /* 998 * convert TIOCM* mask into CIA mask 999 * which is active low 1000 */ 1001 if (how != DMGET) { 1002 ub = 0; 1003 if (bits & TIOCM_DTR) 1004 ub |= CIAB_PRA_DTR; 1005 if (bits & TIOCM_RTS) 1006 ub |= CIAB_PRA_RTS; 1007 if (bits & TIOCM_CTS) 1008 ub |= CIAB_PRA_CTS; 1009 if (bits & TIOCM_CD) 1010 ub |= CIAB_PRA_CD; 1011 if (bits & TIOCM_RI) 1012 ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */ 1013 if (bits & TIOCM_DSR) 1014 ub |= CIAB_PRA_DSR; 1015 } 1016 s = spltty(); 1017 switch (how) { 1018 case DMSET: 1019 /* invert and set */ 1020 ciab.pra = ~ub; 1021 break; 1022 1023 case DMBIC: 1024 ciab.pra |= ub; 1025 ub = ~ciab.pra; 1026 break; 1027 1028 case DMBIS: 1029 ciab.pra &= ~ub; 1030 ub = ~ciab.pra; 1031 break; 1032 1033 case DMGET: 1034 ub = ~ciab.pra; 1035 break; 1036 } 1037 (void)splx(s); 1038 1039 bits = 0; 1040 if (ub & CIAB_PRA_DTR) 1041 bits |= TIOCM_DTR; 1042 if (ub & CIAB_PRA_RTS) 1043 bits |= TIOCM_RTS; 1044 if (ub & CIAB_PRA_CTS) 1045 bits |= TIOCM_CTS; 1046 if (ub & CIAB_PRA_CD) 1047 bits |= TIOCM_CD; 1048 if (ub & CIAB_PRA_SEL) 1049 bits |= TIOCM_RI; 1050 if (ub & CIAB_PRA_DSR) 1051 bits |= TIOCM_DSR; 1052 1053 return(bits); 1054 } 1055 1056 /* 1057 * Following are all routines needed for SER to act as console 1058 */ 1059 void 1060 sercnprobe(struct consdev *cp) 1061 { 1062 int maj, unit; 1063 #ifdef KGDB 1064 extern const struct cdevsw ctty_cdevsw; 1065 #endif 1066 1067 /* locate the major number */ 1068 maj = cdevsw_lookup_major(&ser_cdevsw); 1069 1070 1071 unit = CONUNIT; /* XXX: ick */ 1072 1073 /* 1074 * initialize required fields 1075 */ 1076 cp->cn_dev = makedev(maj, unit); 1077 if (serconsole == unit) 1078 cp->cn_pri = CN_REMOTE; 1079 else 1080 cp->cn_pri = CN_NORMAL; 1081 #ifdef KGDB 1082 /* XXX */ 1083 if (cdevsw_lookup(kgdb_dev) == &ctty_cdevsw) 1084 kgdb_dev = makedev(maj, minor(kgdb_dev)); 1085 #endif 1086 } 1087 1088 void 1089 sercninit(struct consdev *cp) 1090 { 1091 int unit; 1092 1093 unit = SERUNIT(cp->cn_dev); 1094 1095 serinit(serdefaultrate); 1096 serconsole = unit; 1097 serconsinit = 1; 1098 } 1099 1100 void 1101 serinit(int rate) 1102 { 1103 int s; 1104 1105 s = splser(); 1106 /* 1107 * might want to fiddle with the CIA later ??? 1108 */ 1109 custom.serper = (rate>=110 ? SERBRD(rate) : 0); 1110 splx(s); 1111 } 1112 1113 int 1114 sercngetc(dev_t dev) 1115 { 1116 u_short stat; 1117 int c, s; 1118 1119 s = splser(); 1120 /* 1121 * poll 1122 */ 1123 while (((stat = custom.serdatr & 0xffff) & SERDATRF_RBF) == 0) 1124 ; 1125 1126 c = stat & 0xff; 1127 /* 1128 * clear interrupt 1129 */ 1130 custom.intreq = INTF_RBF; 1131 splx(s); 1132 1133 return(c); 1134 } 1135 1136 /* 1137 * Console kernel output character routine. 1138 */ 1139 void 1140 sercnputc(dev_t dev, int c) 1141 { 1142 register int timo; 1143 int s; 1144 1145 s = splhigh(); 1146 1147 if (serconsinit == 0) { 1148 (void)serinit(serdefaultrate); 1149 serconsinit = 1; 1150 } 1151 1152 /* 1153 * wait for any pending transmission to finish 1154 */ 1155 timo = 50000; 1156 while (!(custom.serdatr & SERDATRF_TBE) && --timo); 1157 1158 /* 1159 * transmit char. 1160 */ 1161 custom.serdat = (c & 0xff) | 0x100; 1162 1163 /* 1164 * wait for this transmission to complete 1165 */ 1166 timo = 1500000; 1167 while (!(custom.serdatr & SERDATRF_TBE) && --timo) 1168 ; 1169 1170 /* 1171 * Wait for the device (my vt100..) to process the data, since we 1172 * don't do flow-control with cnputc 1173 */ 1174 for (timo = 0; timo < 30000; timo++) 1175 ; 1176 1177 /* 1178 * We set TBE so that ser_outintr() is called right after to check 1179 * whether there still are chars to process. 1180 * We used to clear this, but it hung the tty output if the kernel 1181 * output a char while userland did on the same serial port. 1182 */ 1183 custom.intreq = INTF_SETCLR | INTF_TBE; 1184 splx(s); 1185 } 1186 1187 void 1188 sercnpollc(dev_t dev, int on) 1189 { 1190 } 1191 #endif 1192