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