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