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