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 int sersoftCAR; 65 int ser_active; 66 int ser_hasfifo; 67 int nser = NSER; 68 #ifdef SERCONSOLE 69 int serconsole = SERCONSOLE; 70 #else 71 int serconsole = -1; 72 #endif 73 int serconsinit; 74 int serdefaultrate = TTYDEF_SPEED; 75 int sermajor; 76 struct serdevice *ser_addr[NSER]; 77 struct tty ser_cons; 78 struct tty *ser_tty[NSER] = { &ser_cons }; 79 80 struct speedtab serspeedtab[] = { 81 0, 0, 82 50, SERBRD(50), 83 75, SERBRD(75), 84 110, SERBRD(110), 85 134, SERBRD(134), 86 150, SERBRD(150), 87 200, SERBRD(200), 88 300, SERBRD(300), 89 600, SERBRD(600), 90 1200, SERBRD(1200), 91 1800, SERBRD(1800), 92 2400, SERBRD(2400), 93 4800, SERBRD(4800), 94 9600, SERBRD(9600), 95 19200, SERBRD(19200), 96 38400, SERBRD(38400), 97 -1, -1 98 }; 99 100 101 /* since this UART is not particularly bright (nice put), we'll have to do 102 parity stuff on our own. this table contains the 8th bit in 7bit character 103 mode, for even parity. If you want odd parity, flip the bit. (for 104 generation of the table, see genpar.c) */ 105 106 u_char even_parity[] = { 107 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 108 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 109 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 110 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 111 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 112 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 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 }; 116 117 118 /* since we don't get interrupts for changes on the modem control line, 119 well have to fake them by comparing current settings to the settings 120 we remembered on last invocation. */ 121 u_char last_ciab_pra; 122 123 extern struct tty *constty; 124 #ifdef KGDB 125 #include "machine/remote-sl.h" 126 127 extern dev_t kgdb_dev; 128 extern int kgdb_rate; 129 extern int kgdb_debug_init; 130 #endif 131 132 #if 0 133 #define UNIT(x) minor(x) 134 #else 135 /* just always force this to 0, so we can later interprete special 136 settings out of the unit number.. */ 137 #define UNIT(x) 0 138 #endif 139 140 #ifdef DEBUG 141 long fifoin[17]; 142 long fifoout[17]; 143 long serintrcount[16]; 144 long sermintcount[16]; 145 #endif 146 147 serprobe(ad) 148 register struct amiga_device *ad; 149 { 150 register struct serdevice *ser; 151 register int unit; 152 153 ser = (struct serdevice *) ad->amiga_addr; 154 unit = ad->amiga_unit; 155 if (unit == serconsole) 156 DELAY(100000); 157 158 ad->amiga_ipl = 2; 159 ser_addr[unit] = ser; 160 ser_active |= 1 << unit; 161 sersoftCAR = ad->amiga_flags; 162 #ifdef KGDB 163 if (kgdb_dev == makedev(sermajor, unit)) { 164 if (serconsole == unit) 165 kgdb_dev = NODEV; /* can't debug over console port */ 166 else { 167 (void) serinit(unit, kgdb_rate); 168 serconsinit = 1; /* don't re-init in serputc */ 169 if (kgdb_debug_init) { 170 /* 171 * Print prefix of device name, 172 * let kgdb_connect print the rest. 173 */ 174 printf("ser%d: ", unit); 175 kgdb_connect(1); 176 } else 177 printf("ser%d: kgdb enabled\n", unit); 178 } 179 } 180 #endif 181 /* 182 * Need to reset baud rate, etc. of next print so reset serconsinit. 183 * Also make sure console is always "hardwired." 184 */ 185 if (unit == serconsole) { 186 serconsinit = 0; 187 sersoftCAR |= (1 << unit); 188 } 189 return (1); 190 } 191 192 /* ARGSUSED */ 193 #ifdef __STDC__ 194 seropen(dev_t dev, int flag, int mode, struct proc *p) 195 #else 196 seropen(dev, flag, mode, p) 197 dev_t dev; 198 int flag, mode; 199 struct proc *p; 200 #endif 201 { 202 register struct tty *tp; 203 register int unit; 204 int error = 0; 205 206 unit = minor (dev); 207 208 if (unit == 1) 209 { 210 unit = 0; 211 sersoftCAR = 0; 212 } 213 else if (unit == 2) 214 { 215 unit = 0; 216 sersoftCAR = 0xff; 217 } 218 else 219 unit = 0; 220 221 if (unit >= NSER || (ser_active & (1 << unit)) == 0) 222 return (ENXIO); 223 if(!ser_tty[unit]) { 224 MALLOC(tp, struct tty *, sizeof(struct tty), M_TTYS, M_WAITOK); 225 bzero(tp, sizeof(struct tty)); 226 ser_tty[unit] = tp; 227 } else 228 tp = ser_tty[unit]; 229 tp->t_oproc = serstart; 230 tp->t_param = serparam; 231 tp->t_dev = dev; 232 if ((tp->t_state & TS_ISOPEN) == 0) { 233 tp->t_state |= TS_WOPEN; 234 ttychars(tp); 235 if (tp->t_ispeed == 0) { 236 tp->t_iflag = TTYDEF_IFLAG | IXOFF; /* XXXXX */ 237 tp->t_oflag = TTYDEF_OFLAG; 238 #if 0 239 tp->t_cflag = TTYDEF_CFLAG; 240 #else 241 tp->t_cflag = (CREAD | CS8 | CLOCAL); /* XXXXX */ 242 #endif 243 tp->t_lflag = TTYDEF_LFLAG; 244 tp->t_ispeed = tp->t_ospeed = serdefaultrate; 245 } 246 serparam(tp, &tp->t_termios); 247 ttsetwater(tp); 248 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0) 249 return (EBUSY); 250 (void) sermctl (dev, TIOCM_DTR | TIOCM_RTS, DMSET); 251 if ((sersoftCAR & (1 << unit)) || (sermctl(dev, 0, DMGET) & TIOCM_CD)) 252 tp->t_state |= TS_CARR_ON; 253 (void) spltty(); 254 while ((flag&O_NONBLOCK) == 0 && (tp->t_cflag&CLOCAL) == 0 && 255 (tp->t_state & TS_CARR_ON) == 0) { 256 tp->t_state |= TS_WOPEN; 257 if (error = ttysleep(tp, (caddr_t)&tp->t_raw, TTIPRI | PCATCH, 258 ttopen, 0)) 259 break; 260 } 261 (void) spl0(); 262 if (error == 0) 263 error = (*linesw[tp->t_line].l_open)(dev, tp); 264 return (error); 265 } 266 267 /*ARGSUSED*/ 268 serclose(dev, flag, mode, p) 269 dev_t dev; 270 int flag, mode; 271 struct proc *p; 272 { 273 register struct tty *tp; 274 register struct serdevice *ser; 275 register int unit; 276 277 unit = UNIT(dev); 278 279 ser = ser_addr[unit]; 280 tp = ser_tty[unit]; 281 (*linesw[tp->t_line].l_close)(tp, flag); 282 custom.adkcon = ADKCONF_UARTBRK; /* clear break */ 283 #ifdef KGDB 284 /* do not disable interrupts if debugging */ 285 if (dev != kgdb_dev) 286 #endif 287 custom.intena = INTF_RBF | INTF_VERTB; /* clear interrupt enable */ 288 custom.intreq = INTF_RBF | INTF_VERTB; /* and interrupt request */ 289 #if 0 290 /* if the device is closed, it's close, no matter whether we deal with modem 291 control signals nor not. */ 292 if (tp->t_cflag&HUPCL || tp->t_state&TS_WOPEN || 293 (tp->t_state&TS_ISOPEN) == 0) 294 #endif 295 (void) sermctl(dev, 0, DMSET); 296 ttyclose(tp); 297 #if 0 298 if (tp != &ser_cons) 299 { 300 FREE(tp, M_TTYS); 301 ser_tty[unit] = (struct tty *)NULL; 302 } 303 #endif 304 return (0); 305 } 306 307 serread(dev, uio, flag) 308 dev_t dev; 309 struct uio *uio; 310 { 311 register struct tty *tp = ser_tty[UNIT(dev)]; 312 int error = (*linesw[tp->t_line].l_read)(tp, uio, flag); 313 314 return error; 315 } 316 317 serwrite(dev, uio, flag) 318 dev_t dev; 319 struct uio *uio; 320 { 321 int unit = UNIT(dev); 322 register struct tty *tp = ser_tty[unit]; 323 324 /* 325 * (XXX) We disallow virtual consoles if the physical console is 326 * a serial port. This is in case there is a display attached that 327 * is not the console. In that situation we don't need/want the X 328 * server taking over the console. 329 */ 330 if (constty && unit == serconsole) 331 constty = NULL; 332 return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); 333 } 334 335 serintr(unit) 336 register int unit; 337 { 338 register struct serdevice *ser; 339 register u_short code; 340 register u_char ch; 341 register u_short ints; 342 register struct tty *tp; 343 344 ser = ser_addr[unit]; 345 346 again: 347 ints = custom.intreqr & INTF_RBF; 348 if (! ints) 349 return 0; 350 351 /* clear interrupt(s) */ 352 custom.intreq = ints; 353 354 /* this register contains both data and status bits! */ 355 code = custom.serdatr; 356 357 if (ints & INTF_RBF) 358 { 359 tp = ser_tty[unit]; 360 /* 361 * Process a received byte. Inline for speed... 362 */ 363 #ifdef KGDB 364 #define RCVBYTE() \ 365 ch = code & 0xff; \ 366 if ((tp->t_state & TS_ISOPEN) == 0) { \ 367 if (ch == FRAME_END && \ 368 kgdb_dev == makedev(sermajor, unit)) \ 369 kgdb_connect(0); /* trap into kgdb */ \ 370 } 371 #else 372 #define RCVBYTE() 373 #endif 374 RCVBYTE(); 375 /* sereint does the receive-processing */ 376 sereint (unit, code, ser); 377 } 378 379 /* fake modem-control interrupt */ 380 sermint (unit, ser); 381 /* try to save interrupt load.. */ 382 goto again; 383 } 384 385 sereint(unit, stat, ser) 386 register int unit, stat; 387 register struct serdevice *ser; 388 { 389 register struct tty *tp; 390 register int c; 391 register u_char ch; 392 393 tp = ser_tty[unit]; 394 if ((tp->t_state & TS_ISOPEN) == 0) { 395 #ifdef KGDB 396 /* we don't care about parity errors */ 397 if (kgdb_dev == makedev(sermajor, unit) && c == FRAME_END) 398 kgdb_connect(0); /* trap into kgdb */ 399 #endif 400 return; 401 } 402 ch = stat & 0xff; 403 c = ch; 404 /* all databits 0 including stop indicate break condition */ 405 if (!(stat & 0x1ff)) 406 c |= TTY_FE; 407 408 /* if parity checking enabled, check parity */ 409 else if ((tp->t_cflag & PARENB) && 410 (((ch >> 7) + even_parity[ch & 0x7f] + !!(tp->t_cflag & PARODD)) & 1)) 411 c |= TTY_PE; 412 413 if (stat & SERDATRF_OVRUN) 414 log(LOG_WARNING, "ser%d: silo overflow\n", unit); 415 416 (*linesw[tp->t_line].l_rint)(c, tp); 417 } 418 419 sermint(unit) 420 register int unit; 421 { 422 register struct tty *tp; 423 register u_char stat, last, istat; 424 register struct serdevice *ser; 425 426 tp = ser_tty[unit]; 427 stat = ciab.pra; 428 last = last_ciab_pra; 429 last_ciab_pra = stat; 430 431 /* check whether any interesting signal changed state */ 432 istat = stat ^ last; 433 434 if ((istat & CIAB_PRA_CD) && (sersoftCAR & (1 << unit)) == 0) 435 { 436 if (ISDCD (stat)) 437 (*linesw[tp->t_line].l_modem)(tp, 1); 438 else if ((*linesw[tp->t_line].l_modem)(tp, 0) == 0) 439 { 440 CLRDTR (stat); 441 CLRRTS (stat); 442 ciab.pra = stat; 443 last_ciab_pra = stat; 444 } 445 } 446 else if ((istat & CIAB_PRA_CTS) && (tp->t_state & TS_ISOPEN) && 447 (tp->t_flags & CRTSCTS)) 448 { 449 /* the line is up and we want to do rts/cts flow control */ 450 if (ISCTS (stat)) 451 { 452 tp->t_state &=~ TS_TTSTOP; 453 ttstart(tp); 454 } 455 else 456 tp->t_state |= TS_TTSTOP; 457 } 458 } 459 460 serioctl(dev, cmd, data, flag) 461 dev_t dev; 462 caddr_t data; 463 { 464 register struct tty *tp; 465 register int unit = UNIT(dev); 466 register struct serdevice *ser; 467 register int error; 468 469 tp = ser_tty[unit]; 470 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag); 471 if (error >= 0) 472 return (error); 473 error = ttioctl(tp, cmd, data, flag); 474 if (error >= 0) 475 return (error); 476 477 ser = ser_addr[unit]; 478 switch (cmd) { 479 480 case TIOCSBRK: 481 custom.adkcon = ADKCONF_SETCLR | ADKCONF_UARTBRK; 482 break; 483 484 case TIOCCBRK: 485 custom.adkcon = ADKCONF_UARTBRK; 486 break; 487 488 case TIOCSDTR: 489 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS); 490 break; 491 492 case TIOCCDTR: 493 (void) sermctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC); 494 break; 495 496 case TIOCMSET: 497 (void) sermctl(dev, *(int *)data, DMSET); 498 break; 499 500 case TIOCMBIS: 501 (void) sermctl(dev, *(int *)data, DMBIS); 502 break; 503 504 case TIOCMBIC: 505 (void) sermctl(dev, *(int *)data, DMBIC); 506 break; 507 508 case TIOCMGET: 509 *(int *)data = sermctl(dev, 0, DMGET); 510 break; 511 512 default: 513 return (ENOTTY); 514 } 515 return (0); 516 } 517 518 serparam(tp, t) 519 register struct tty *tp; 520 register struct termios *t; 521 { 522 register struct serdevice *ser; 523 register int cfcr, cflag = t->c_cflag; 524 int unit = UNIT(tp->t_dev); 525 int ospeed = ttspeedtab(t->c_ospeed, serspeedtab); 526 527 /* check requested parameters */ 528 if (ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed)) 529 return (EINVAL); 530 /* and copy to tty */ 531 tp->t_ispeed = t->c_ispeed; 532 tp->t_ospeed = t->c_ospeed; 533 tp->t_cflag = cflag; 534 535 custom.intena = INTF_SETCLR | INTF_RBF; 536 custom.intreq = INTF_RBF; 537 last_ciab_pra = ciab.pra; 538 539 if (ospeed == 0) { 540 (void) sermctl(unit, 0, DMSET); /* hang up line */ 541 return (0); 542 } 543 /* set the baud rate */ 544 custom.serper = (0<<15) | ospeed; /* select 8 bit mode (instead of 9 bit) */ 545 546 return (0); 547 } 548 549 serstart(tp) 550 register struct tty *tp; 551 { 552 register struct serdevice *ser; 553 int s, unit; 554 u_short c; 555 556 unit = UNIT(tp->t_dev); 557 ser = ser_addr[unit]; 558 s = spltty(); 559 again: 560 if (tp->t_state & (TS_TIMEOUT|TS_TTSTOP)) 561 goto out; 562 if (RB_LEN(&tp->t_out) <= tp->t_lowat) { 563 if (tp->t_state&TS_ASLEEP) { 564 tp->t_state &= ~TS_ASLEEP; 565 wakeup((caddr_t)&tp->t_out); 566 } 567 selwakeup (&tp->t_wsel); 568 } 569 if (RB_LEN(&tp->t_out) == 0) 570 goto out; 571 572 while (! (custom.serdatr & SERDATRF_TBE)) ; 573 574 c = rbgetc(&tp->t_out); 575 /* tp->t_state |= TS_BUSY; */ 576 577 /* handle truncation of character if necessary */ 578 if ((tp->t_cflag & CSIZE) == CS7) 579 c &= 0x7f; 580 581 /* handle parity if necessary (forces CS7) */ 582 if (tp->t_cflag & PARENB) 583 { 584 if (even_parity[c & 0x7f]) 585 c |= 0x80; 586 if (tp->t_cflag & PARODD) 587 c ^= 0x80; 588 } 589 590 /* add stop bit(s) */ 591 if (tp->t_cflag & CSTOPB) 592 c |= 0x300; 593 else 594 c |= 0x100; 595 596 custom.serdat = c; 597 598 /* if there's input on the line, stop spitting out characters */ 599 if (! (custom.intreqr & INTF_RBF)) 600 goto again; 601 602 out: 603 splx(s); 604 } 605 606 /* 607 * Stop output on a line. 608 */ 609 /*ARGSUSED*/ 610 serstop(tp, flag) 611 register struct tty *tp; 612 { 613 register int s; 614 615 s = spltty(); 616 if (tp->t_state & TS_BUSY) { 617 if ((tp->t_state&TS_TTSTOP)==0) 618 tp->t_state |= TS_FLUSH; 619 } 620 splx(s); 621 } 622 623 sermctl(dev, bits, how) 624 dev_t dev; 625 int bits, how; 626 { 627 register struct serdevice *ser; 628 register int unit; 629 u_char ub; 630 int s; 631 632 unit = UNIT(dev); 633 ser = ser_addr[unit]; 634 635 /* convert TIOCM* mask into CIA mask (which is really low-active!!) */ 636 if (how != DMGET) 637 { 638 ub = 0; 639 if (bits & TIOCM_DTR) ub |= CIAB_PRA_DTR; 640 if (bits & TIOCM_RTS) ub |= CIAB_PRA_RTS; 641 if (bits & TIOCM_CTS) ub |= CIAB_PRA_CTS; 642 if (bits & TIOCM_CD) ub |= CIAB_PRA_CD; 643 if (bits & TIOCM_RI) ub |= CIAB_PRA_SEL; /* collision with /dev/par ! */ 644 if (bits & TIOCM_DSR) ub |= CIAB_PRA_DSR; 645 } 646 647 648 s = spltty(); 649 switch (how) { 650 651 case DMSET: 652 /* invert and set */ 653 ciab.pra = ~ub; 654 break; 655 656 case DMBIC: 657 ciab.pra |= ub; 658 ub = ~ciab.pra; 659 break; 660 661 case DMBIS: 662 ciab.pra &= ~ub; 663 ub = ~ciab.pra; 664 break; 665 666 case DMGET: 667 ub = ~ciab.pra; 668 break; 669 } 670 (void) splx(s); 671 672 bits = 0; 673 if (ub & CIAB_PRA_DTR) bits |= TIOCM_DTR; 674 if (ub & CIAB_PRA_RTS) bits |= TIOCM_RTS; 675 if (ub & CIAB_PRA_CTS) bits |= TIOCM_CTS; 676 if (ub & CIAB_PRA_CD) bits |= TIOCM_CD; 677 if (ub & CIAB_PRA_SEL) bits |= TIOCM_RI; 678 if (ub & CIAB_PRA_DSR) bits |= TIOCM_DSR; 679 680 return bits; 681 } 682 683 /* 684 * Following are all routines needed for SER to act as console 685 */ 686 #include "../amiga/cons.h" 687 688 sercnprobe(cp) 689 struct consdev *cp; 690 { 691 int unit = CONUNIT; 692 693 /* locate the major number */ 694 for (sermajor = 0; sermajor < nchrdev; sermajor++) 695 if (cdevsw[sermajor].d_open == seropen) 696 break; 697 698 /* XXX: ick */ 699 unit = CONUNIT; 700 701 /* initialize required fields */ 702 cp->cn_dev = makedev(sermajor, unit); 703 cp->cn_tp = ser_tty[unit]; 704 cp->cn_pri = CN_NORMAL; 705 706 /* 707 * If serconsole is initialized, raise our priority. 708 */ 709 if (serconsole == unit) 710 cp->cn_pri = CN_REMOTE; 711 #ifdef KGDB 712 if (major(kgdb_dev) == 1) /* XXX */ 713 kgdb_dev = makedev(sermajor, minor(kgdb_dev)); 714 #endif 715 } 716 717 sercninit(cp) 718 struct consdev *cp; 719 { 720 int unit = UNIT(cp->cn_dev); 721 722 serinit(unit, serdefaultrate); 723 serconsole = unit; 724 serconsinit = 1; 725 } 726 727 serinit(unit, rate) 728 int unit, rate; 729 { 730 int s; 731 732 #ifdef lint 733 stat = unit; if (stat) return; 734 #endif 735 s = splhigh(); 736 /* might want to fiddle with the CIA later ??? */ 737 custom.serper = ttspeedtab(rate, serspeedtab); 738 splx(s); 739 } 740 741 sercngetc(dev) 742 { 743 u_short stat; 744 int c, s; 745 746 #ifdef lint 747 stat = dev; if (stat) return (0); 748 #endif 749 s = splhigh(); 750 while (!((stat = custom.serdatr & 0xffff) & SERDATRF_RBF)) 751 ; 752 c = stat & 0xff; 753 /* clear interrupt */ 754 custom.intreq = INTF_RBF; 755 splx(s); 756 return (c); 757 } 758 759 /* 760 * Console kernel output character routine. 761 */ 762 sercnputc(dev, c) 763 dev_t dev; 764 register int c; 765 { 766 register int timo; 767 short stat; 768 int s = splhigh(); 769 770 #ifdef lint 771 stat = dev; if (stat) return; 772 #endif 773 if (serconsinit == 0) { 774 (void) serinit(UNIT(dev), serdefaultrate); 775 serconsinit = 1; 776 } 777 /* wait for any pending transmission to finish */ 778 timo = 50000; 779 while (! (custom.serdatr & SERDATRF_TBE) && --timo) 780 ; 781 custom.serdat = (c&0xff) | 0x100; 782 /* wait for this transmission to complete */ 783 timo = 1500000; 784 while (! (custom.serdatr & SERDATRF_TBE) && --timo) 785 ; 786 /* wait for the device (my vt100..) to process the data, since 787 we don't do flow-control with cnputc */ 788 for (timo = 0; timo < 30000; timo++) ; 789 790 /* clear any interrupts generated by this transmission */ 791 custom.intreq = INTF_TBE; 792 splx(s); 793 } 794 795 796 serspit(c) 797 int c; 798 { 799 register struct Custom *cu asm("a2") = CUSTOMbase; 800 register int timo asm("d2"); 801 extern int cold; 802 int s; 803 804 if (c == 10) 805 serspit (13); 806 807 s = splhigh(); 808 809 /* wait for any pending transmission to finish */ 810 timo = 500000; 811 while (! (cu->serdatr & (SERDATRF_TBE|SERDATRF_TSRE)) && --timo) 812 ; 813 cu->serdat = (c&0xff) | 0x100; 814 /* wait for this transmission to complete */ 815 timo = 15000000; 816 while (! (cu->serdatr & SERDATRF_TBE) && --timo) 817 ; 818 /* clear any interrupts generated by this transmission */ 819 cu->intreq = INTF_TBE; 820 821 for (timo = 0; timo < 30000; timo++) ; 822 823 splx (s); 824 } 825 826 int 827 serselect(dev, rw, p) 828 dev_t dev; 829 int rw; 830 struct proc *p; 831 { 832 register struct tty *tp = ser_tty[UNIT(dev)]; 833 int nread; 834 int s = spltty(); 835 struct proc *selp; 836 837 switch (rw) { 838 839 case FREAD: 840 nread = ttnread(tp); 841 if (nread > 0 || 842 ((tp->t_cflag&CLOCAL) == 0 && (tp->t_state&TS_CARR_ON) == 0)) 843 goto win; 844 selrecord(p, &tp->t_rsel); 845 break; 846 847 case FWRITE: 848 if (RB_LEN(&tp->t_out) <= tp->t_lowat) 849 goto win; 850 selrecord(p, &tp->t_wsel); 851 break; 852 } 853 splx(s); 854 return (0); 855 win: 856 splx(s); 857 return (1); 858 } 859 860 #endif 861