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