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