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