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