|
|
1.1 ! root 1: /* (-lgl ! 2: * COHERENT Driver Kit Version 2.1.0 ! 3: * Copyright (c) 1982, 1993 by Mark Williams Company. ! 4: * All rights reserved. May not be copied without permission. ! 5: * ! 6: * ! 7: -lgl) */ ! 8: /* ! 9: * Shared parts of IBM async port drivers. ! 10: */ ! 11: #include <sys/coherent.h> ! 12: #ifndef _I386 ! 13: #include <sys/i8086.h> ! 14: #endif ! 15: #include <sys/al.h> ! 16: #include <sys/con.h> ! 17: #include <errno.h> ! 18: #include <sys/stat.h> ! 19: #include <sys/tty.h> ! 20: #include <sys/timeout.h> ! 21: #include <sys/clist.h> ! 22: #include <sys/ins8250.h> ! 23: #include <sys/sched.h> ! 24: #include <sys/silo.h> ! 25: ! 26: #ifdef _I386 ! 27: #define EEBUSY EBUSY ! 28: #else ! 29: #define EEBUSY EDBUSY ! 30: #endif ! 31: ! 32: #define ALPORT (((COM_DDP *)(tp->t_ddp))->port) ! 33: #define AL_NUM (((COM_DDP *)(tp->t_ddp))->com_num) ! 34: ! 35: #define DTRTMOUT 3 /* DTR timeout interval in seconds for close */ ! 36: ! 37: /* ! 38: * For rawin silo (see poll_clk.h), use last element of si_buf to count ! 39: * the number of characters in the silo. ! 40: */ ! 41: #define SILO_CHAR_COUNT si_buf[SI_BUFSIZ-1] ! 42: #define SILO_HIGH_MARK (SI_BUFSIZ-SI_BUFSIZ/4) ! 43: #define SILO_LOW_MARK (SI_BUFSIZ/4) ! 44: #define MAX_SILO_INDEX (SI_BUFSIZ-2) ! 45: #define MAX_SILO_CHARS (SI_BUFSIZ-1) ! 46: ! 47: /* ! 48: * The following silo FLUSH macros are always called at high priority! ! 49: */ ! 50: #ifdef NO_ISILO ! 51: #define RAWIN_FLUSH(in_silo) ! 52: #else ! 53: #define RAWIN_FLUSH(in_silo) { in_silo->si_ox = in_silo->si_ix; \ ! 54: in_silo->SILO_CHAR_COUNT = 0; } ! 55: #endif ! 56: #define RAWOUT_FLUSH(out_silo) { out_silo->si_ox = out_silo->si_ix; } ! 57: ! 58: int al_sg_set = 0; ! 59: int al_sg_clr = 0; ! 60: static int poll_divisor; /* set by set_poll_rate(), read by alxclk() */ ! 61: ! 62: /* ! 63: * functions herein ! 64: */ ! 65: int alxopen(); ! 66: int alxclose(); ! 67: int alxtimer(); ! 68: int alxioctl(); ! 69: int alxparam(); ! 70: int alxcycle(); ! 71: int alxstart(); ! 72: int alxbreak(); ! 73: int alxintr(); ! 74: static int alxclk(); ! 75: static set_poll_rate(); ! 76: static void alxpoll(); ! 77: static void alx_send(); ! 78: static int iocbaud[4]; ! 79: static char ioclcr[4]; ! 80: ! 81: /* ! 82: * Port addresses are now patchable. ! 83: */ ! 84: int AL_ADDR[] = { ! 85: #if BOB_H ! 86: 0x280, 0x288, 0x290, 0x298 ! 87: #else ! 88: 0x3F8, 0x2F8, 0x3E8, 0x2E8 ! 89: #endif ! 90: }; ! 91: ! 92: /* ! 93: * Baud rate table and polling rate table. ! 94: * Indexed by ioctl bit rates. ! 95: */ ! 96: extern int albaud[], alp_rate[]; ! 97: ! 98: /* ! 99: * the following is for debug only ! 100: */ ! 101: #if TRACER ! 102: int ASY_OR = 0; ! 103: #define LSR_READ(lval, port) \ ! 104: { lval = inb((port)+LSR); if (lval & LS_OVER) ASY_OR++; } ! 105: #define CDUMP(text, tp) cdump(text, tp); ! 106: #define tprintf(str) { T_HAL(4, printf(str)); } ! 107: #define REPORT_OE {if(ASY_OR&&(t_hal&0x20)){printf("oe=%d ",ASY_OR);ASY_OR=0;}} ! 108: cdump(message, tp) ! 109: char *message; ! 110: TTY *tp; ! 111: { ! 112: int i, b; ! 113: char cmd[11]; ! 114: ! 115: if ((t_hal & 4) == 0) ! 116: return; ! 117: for (i = 0; i < NUM_AL_PORTS; i++) { ! 118: if (tp_table[i]) { ! 119: b = ((COM_DDP *)(tp_table[i]->t_ddp))->port; ! 120: printf("%x:%x:%x:%x ", i+1, b, inb(b+MCR), inb(b+IER)); ! 121: } ! 122: } ! 123: for (i = 0; i < 10; i++) { ! 124: cmd[i] = u.u_comm[i]; ! 125: } ! 126: cmd[10] = '\0'; ! 127: printf("poll=%d cmd=%s pid=%d ", poll_rate, cmd, SELF->p_pid); ! 128: printf("%s\n", message); ! 129: if (tp) { ! 130: printf("#%d f=%x op=%d ", AL_NUM, tp->t_flags, tp->t_open); ! 131: printf("in_use=%d irq=%d has_irq=%d ", ! 132: com_usage[AL_NUM].in_use, ! 133: com_usage[AL_NUM].irq, ! 134: com_usage[AL_NUM].has_irq); ! 135: printf("poll=%d hcls=%d ohlt=%d\n", ! 136: com_usage[AL_NUM].poll, ! 137: com_usage[AL_NUM].hcls, ! 138: com_usage[AL_NUM].ohlt); ! 139: } ! 140: } ! 141: #else ! 142: #define CDUMP(text, tp) ! 143: #define REPORT_OE ! 144: #define LSR_READ(lval, port) { lval = inb((port)+LSR); } ! 145: #endif ! 146: ! 147: /* ! 148: * alxopen() ! 149: */ ! 150: alxopen(dev, mode, tp, irqtty) ! 151: dev_t dev; ! 152: int mode; ! 153: register TTY *tp, **irqtty; ! 154: { ! 155: int s; ! 156: int b; ! 157: int minor_h; /* minor device number including high bit */ ! 158: unsigned char msr; ! 159: ! 160: minor_h = minor(dev); /* complete minor number */ ! 161: b = ALPORT; ! 162: ! 163: if (com_usage[AL_NUM].uart_type == US_NONE) { /* chip not found */ ! 164: u.u_error = ENXIO; ! 165: goto bad_open; ! 166: } ! 167: ! 168: if ((tp->t_flags & T_EXCL) && !super()) { ! 169: u.u_error = ENODEV; ! 170: goto bad_open; ! 171: } ! 172: ! 173: if (drvl[major(dev)].d_time) { /* Modem settling */ ! 174: u.u_error = EEBUSY; ! 175: goto bad_open; ! 176: } ! 177: ! 178: /* ! 179: * Can't open a polled port if another driver is using polling. ! 180: */ ! 181: if (dev & CPOLL && poll_owner & ~ POLL_AL) { ! 182: u.u_error = EEBUSY; ! 183: goto bad_open; ! 184: } ! 185: ! 186: /* ! 187: * Can't have both com[13] or both com[24] IRQ at once. ! 188: */ ! 189: if ( !(dev & CPOLL) ! 190: && com_usage[AL_NUM^2].irq ! 191: && com_usage[AL_NUM^2].in_use) { ! 192: u.u_error = EEBUSY; ! 193: goto bad_open; ! 194: } ! 195: ! 196: /* ! 197: * If port already in use, are new and old open modes compatible? ! 198: */ ! 199: if (com_usage[AL_NUM].in_use) { ! 200: int oldmode = 0, newmode = 0; /* mctl:1 poll:2 flow:4 */ ! 201: ! 202: if (tp->t_flags & T_MODC) ! 203: oldmode += 1; ! 204: if (com_usage[AL_NUM].irq == 0) ! 205: oldmode += 2; ! 206: if (tp->t_flags & T_CFLOW) ! 207: oldmode += 4; ! 208: if ((minor_h & NMODC) == 0) ! 209: newmode += 1; ! 210: if (dev & CPOLL) ! 211: newmode += 2; ! 212: if (minor_h & CFLOW) ! 213: newmode += 4; ! 214: if (oldmode != newmode) { ! 215: u.u_error = EEBUSY; ! 216: goto bad_open; ! 217: } ! 218: } ! 219: ! 220: /* ! 221: * Sleep here if another process is opening or closing the port. ! 222: * This can happen if: ! 223: * another process is trying a first open and awaiting CD; ! 224: * another process is closing the port after losing CD; ! 225: * a remote process opened the port, spawned a daemon, ! 226: * and disconnected, and the daemon ignored SIGHUP and is ! 227: * improperly keeping the port open. ! 228: * Don't try to set tp->t_flags before this sleep! During ! 229: * the sleep, ttclose() may be called and clear the flags. ! 230: */ ! 231: while (com_usage[AL_NUM].in_use && ! 232: (com_usage[AL_NUM].hcls || ! 233: ((minor_h & NMODC) == 0 && (inb(b+MSR) & MS_RLSD) == 0))) { ! 234: #ifdef _I386 ! 235: x_sleep((char *)(&tp->t_open), pritty, slpriSigCatch, "alxopn1"); ! 236: #else ! 237: v_sleep((char *)(&tp->t_open), ! 238: CVTTOUT, IVTTOUT, SVTTOUT, "alxopn1"); ! 239: #endif ! 240: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 241: u.u_error = EINTR; ! 242: goto bad_open; ! 243: } ! 244: } ! 245: ! 246: /* ! 247: * If port already in use, are new and old open modes compatible? ! 248: * If not in use, mark it as such. ! 249: */ ! 250: if (com_usage[AL_NUM].in_use) { ! 251: int oldmode = 0, newmode = 0; /* mctl:1 poll:2 flow:4 */ ! 252: ! 253: if (tp->t_flags & T_MODC) ! 254: oldmode += 1; ! 255: if (com_usage[AL_NUM].irq == 0) ! 256: oldmode += 2; ! 257: if (tp->t_flags & T_CFLOW) ! 258: oldmode += 4; ! 259: if ((minor_h & NMODC) == 0) ! 260: newmode += 1; ! 261: if (dev & CPOLL) ! 262: newmode += 2; ! 263: if (minor_h & CFLOW) ! 264: newmode += 4; ! 265: if (oldmode != newmode) { ! 266: u.u_error = EEBUSY; ! 267: goto bad_open; ! 268: } ! 269: } else { ! 270: /* ! 271: * Save modes for this open attempt to avoid future conflicts. ! 272: * Then start alxcycle() for this port. ! 273: */ ! 274: if (dev & CPOLL) ! 275: com_usage[AL_NUM].irq = 0; ! 276: else ! 277: com_usage[AL_NUM].irq = 1; ! 278: if (minor_h & CFLOW) ! 279: tp->t_flags |= T_CFLOW; ! 280: else ! 281: tp->t_flags &= ~T_CFLOW; ! 282: if (minor_h & NMODC) ! 283: tp->t_flags &= ~T_MODC; ! 284: else ! 285: tp->t_flags |= T_MODC; ! 286: } ! 287: com_usage[AL_NUM].in_use++; ! 288: /* ! 289: * From here, error exit is bad_open_u. ! 290: */ ! 291: ! 292: if (tp->t_open == 0) { /* not already open */ ! 293: if (!(dev & CPOLL)) { ! 294: *irqtty = tp_table[AL_NUM]; ! 295: com_usage[AL_NUM].has_irq = 1; ! 296: } ! 297: ! 298: /* ! 299: * Need to start cycling to scan for CD. ! 300: */ ! 301: alxcycle(tp); ! 302: ! 303: s = sphi(); ! 304: /* ! 305: * Raise basic modem control lines even if modem ! 306: * control hasn't been specified. ! 307: * MC_OUT2 turns on NON-open-collector IRQ line from the UART. ! 308: * since we can't have two UART's on same IRQ with MC_OUT2 on ! 309: */ ! 310: if (dev & CPOLL) { ! 311: outb(b+MCR, MC_RTS|MC_DTR); ! 312: } else { ! 313: outb(b+MCR, MC_RTS|MC_DTR|MC_OUT2); ! 314: outb(b+IER, IENABLE); ! 315: } ! 316: ! 317: if ((minor_h & NMODC) == 0) { /* want modem control? */ ! 318: tp->t_flags |= T_HOPEN | T_STOP; ! 319: for (;;) { /* wait for carrier */ ! 320: msr = inb(b+MSR); ! 321: /* ! 322: * If carrier detect present ! 323: * if port not already open ! 324: * break out of loop and finish first open ! 325: * else ! 326: * do second (or third, etc.) open ! 327: */ ! 328: if (msr & MS_RLSD) ! 329: break; ! 330: ! 331: /* wait for carrier */ ! 332: #ifdef _I386 ! 333: x_sleep((char *)(&tp->t_open), ! 334: pritty, slpriSigCatch, "alxopn2"); ! 335: #else ! 336: v_sleep((char *)(&tp->t_open), ! 337: CVTTOUT, IVTTOUT, SVTTOUT, "alxopn2"); ! 338: #endif ! 339: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 340: outb(b+MCR, 0); ! 341: outb(b+IER, 0); ! 342: u.u_error = EINTR; ! 343: tp->t_flags &= ~(T_HOPEN | T_STOP); ! 344: spl(s); ! 345: goto bad_open_u; ! 346: } ! 347: } ! 348: ! 349: /* ! 350: * Mark that we are no longer hanging in open. ! 351: * Allow output over the port unless hardware flow ! 352: * control says not to. ! 353: */ ! 354: tp->t_flags &= ~T_HOPEN; ! 355: tp->t_flags &= ~T_STOP; ! 356: if (!(tp->t_flags & T_CFLOW) || (msr & MS_CTS)) ! 357: com_usage[AL_NUM].ohlt = 0; ! 358: else ! 359: com_usage[AL_NUM].ohlt = 1; ! 360: ! 361: /* ! 362: * Awaken any other opens on same device. ! 363: */ ! 364: wakeup((char *)(&tp->t_open)); ! 365: } ! 366: tp->t_flags |= T_CARR; ! 367: ttopen(tp); /* stty inits */ ! 368: ! 369: /* ! 370: * Allow custom modification of defaults. ! 371: */ ! 372: tp->t_sgttyb.sg_flags |= al_sg_set; ! 373: tp->t_sgttyb.sg_flags &= ~al_sg_clr; ! 374: ! 375: alxparam(tp); ! 376: spl(s); ! 377: } /* end of first-open case */ ! 378: ! 379: tp->t_open++; ! 380: ttsetgrp(tp, dev, mode); ! 381: ! 382: /* ! 383: * Turn on polling for the port. ! 384: */ ! 385: if (dev & CPOLL) { ! 386: com_usage[AL_NUM].poll = 1; ! 387: set_poll_rate(); ! 388: } ! 389: ! 390: CDUMP((dev&CPOLL)?"open polled":"open irq", tp) ! 391: return; ! 392: ! 393: bad_open_u: ! 394: --com_usage[AL_NUM].in_use; ! 395: wakeup((char *)(&tp->t_open)); ! 396: bad_open: ! 397: return; ! 398: } ! 399: ! 400: /* ! 401: * alxclose() ! 402: * ! 403: * Called whenever kernel closes a com port. ! 404: */ ! 405: alxclose(dev, mode, tp) ! 406: dev_t dev; ! 407: int mode; ! 408: TTY *tp; ! 409: { ! 410: register int b; ! 411: int maj; ! 412: int flags; ! 413: int s; ! 414: unsigned char lsr; ! 415: silo_t * out_silo = &com_usage[AL_NUM].raw_out; ! 416: silo_t * in_silo = &com_usage[AL_NUM].raw_in; ! 417: ! 418: if (--tp->t_open) ! 419: goto closed; ! 420: s = sphi(); ! 421: ! 422: /* ! 423: * Called at high priority by alclose after al_buff is drained ! 424: */ ! 425: com_usage[AL_NUM].hcls = 1; /* disallow reopen til done closing */ ! 426: flags = tp->t_flags; /* save flags - ttclose zeroes them */ ! 427: ttclose(tp); ! 428: b = ALPORT; ! 429: ! 430: /* ! 431: * Wait for output silo and uart xmit buffer to empty. ! 432: * Allow signal to break the sleep. ! 433: */ ! 434: for (;;) { ! 435: LSR_READ(lsr, b); ! 436: if ((lsr & LS_TxIDLE) ! 437: && (out_silo->si_ix == out_silo->si_ox)) ! 438: break; ! 439: CDUMP("slp cls", tp) ! 440: #ifdef _I386 ! 441: x_sleep((char *)out_silo, pritty, slpriSigCatch, "alxcls1"); ! 442: #else ! 443: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT, "alxcls1"); ! 444: #endif ! 445: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 446: RAWOUT_FLUSH(out_silo); ! 447: break; ! 448: } ! 449: } ! 450: ! 451: /* ! 452: * If not hanging in open ! 453: */ ! 454: if ((flags & T_HOPEN) == 0) { ! 455: /* ! 456: * Disable interrupts. ! 457: */ ! 458: outb(b+IER, 0); ! 459: outb(b+MCR, inb(b+MCR)&(~MC_OUT2)); ! 460: } ! 461: ! 462: /* ! 463: * If hupcls ! 464: */ ! 465: if (flags & T_HPCL) { ! 466: /* ! 467: * Hangup port - drop DTR and RTS. ! 468: */ ! 469: outb(b+MCR, inb(b+MCR)&MC_OUT2); ! 470: ! 471: /* ! 472: * Hold dtr low for timeout ! 473: */ ! 474: maj = major(dev); ! 475: drvl[maj].d_time = 1; ! 476: CDUMP("slp DTR", tp) ! 477: #ifdef _I386 ! 478: x_sleep((char *)&drvl[maj].d_time, ! 479: pritty, slpriNoSig, "alxcls2"); ! 480: #else ! 481: v_sleep((char *)&drvl[maj].d_time, ! 482: CVTTOUT, IVTTOUT, SVTTOUT, "alxcls2"); ! 483: #endif ! 484: drvl[maj].d_time = 0; ! 485: } ! 486: com_usage[AL_NUM].poll = 0; ! 487: set_poll_rate(); ! 488: RAWIN_FLUSH(in_silo); ! 489: com_usage[AL_NUM].hcls = 0; /* allow reopen - done closing */ ! 490: wakeup((char *)(&tp->t_open)); ! 491: spl(s); ! 492: closed:; ! 493: --com_usage[AL_NUM].in_use; ! 494: wakeup((char *)(&tp->t_open)); ! 495: CDUMP("closed", tp) ! 496: } ! 497: ! 498: /* ! 499: * Common c_timer routine for async ports. ! 500: */ ! 501: alxtimer(dev) ! 502: dev_t dev; ! 503: { ! 504: if (++drvl[major(dev)].d_time > DTRTMOUT) ! 505: wakeup((char *)&drvl[major(dev)].d_time); ! 506: } ! 507: ! 508: ! 509: /* ! 510: * Common c_ioctl routine for async ports. ! 511: */ ! 512: alxioctl(dev, com, vec, tp) ! 513: dev_t dev; ! 514: struct sgttyb *vec; ! 515: register TTY *tp; ! 516: { ! 517: register int s, b; ! 518: int stat1, stat2; ! 519: unsigned char msr; ! 520: unsigned char ier_save; ! 521: silo_t * out_silo = &com_usage[AL_NUM].raw_out; ! 522: silo_t * in_silo = &com_usage[AL_NUM].raw_in; ! 523: ! 524: s = sphi(); ! 525: b = ALPORT; ! 526: ier_save=inb(b+IER); ! 527: stat1 = inb(b+MCR); /* get current MCR register status */ ! 528: stat2 = inb(b+LCR); /* get current LCR register status */ ! 529: ! 530: switch(com) { ! 531: case TIOCSBRK: /* set BREAK */ ! 532: outb(b+LCR, stat2|LC_SBRK); ! 533: break; ! 534: case TIOCCBRK: /* clear BREAK */ ! 535: outb(b+LCR, stat2 & ~LC_SBRK); ! 536: break; ! 537: case TIOCSDTR: /* set DTR */ ! 538: outb(b+MCR, stat1|MC_DTR); ! 539: break; ! 540: case TIOCCDTR: /* clear DTR */ ! 541: outb(b+MCR, stat1 & ~MC_DTR); ! 542: break; ! 543: case TIOCSRTS: /* set RTS */ ! 544: outb(b+MCR, stat1|MC_RTS); ! 545: break; ! 546: case TIOCCRTS: /* clear RTS */ ! 547: outb(b+MCR, stat1 & ~MC_RTS); ! 548: break; ! 549: case TIOCRSPEED: /* set "raw" I/O speed divisor */ ! 550: outb(b+LCR, stat2|LC_DLAB); /* set speed latch bit */ ! 551: outb(b+DLL, (unsigned) vec); ! 552: outb(b+DLH, (unsigned) vec >> 8); ! 553: outb(b+LCR, stat2); /* reset latch bit */ ! 554: break; ! 555: case TIOCWORDL: /* set word length and stop bits */ ! 556: outb(b+LCR, ((stat2&~0x7) | ((unsigned) vec & 0x7))); ! 557: break; ! 558: case TIOCRMSR: /* get CTS/DSR/RI/RLSD (MSR) */ ! 559: msr = inb(b+MSR); ! 560: stat1 = msr >> 4; ! 561: kucopy(&stat1, (unsigned *) vec, sizeof(unsigned)); ! 562: break; ! 563: case TIOCFLUSH: /* Flush silos here, queues in tty.c */ ! 564: RAWIN_FLUSH(in_silo); ! 565: RAWOUT_FLUSH(out_silo); ! 566: /* fall through to default... */ ! 567: default: ! 568: ttioctl(tp, com, vec); ! 569: } ! 570: outb(b+IER, ier_save); ! 571: spl(s); ! 572: } ! 573: ! 574: alxparam(tp) ! 575: TTY *tp; ! 576: { ! 577: register int b; ! 578: register int baud; ! 579: int s; ! 580: char newlcr; ! 581: int write_baud=1, write_lcr=1; ! 582: int alnum; ! 583: ! 584: b = ALPORT; ! 585: ! 586: /* ! 587: * error if input speed not the same as output speed ! 588: */ ! 589: if (tp->t_sgttyb.sg_ispeed!=tp->t_sgttyb.sg_ospeed) { ! 590: u.u_error = ENODEV; ! 591: return; ! 592: } ! 593: ! 594: if ((baud = albaud[tp->t_sgttyb.sg_ispeed]) == 0) { ! 595: if (tp->t_flags & T_MODC) { /* modem control? */ ! 596: s = sphi(); ! 597: tp->t_flags &= ~T_CARR; /* indicate no carrier */ ! 598: outb(b+MCR, inb(b+MCR) & MC_OUT2); /* hangup */ ! 599: spl(s); ! 600: } ! 601: write_baud = 0; ! 602: } ! 603: ! 604: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) { ! 605: case ODDP: ! 606: newlcr = LC_CS7|LC_PARENB; ! 607: break; ! 608: case EVENP: ! 609: newlcr = LC_CS7|LC_PARENB|LC_PAREVEN; ! 610: break; ! 611: default: ! 612: newlcr = LC_CS8; ! 613: break; ! 614: } ! 615: ! 616: alnum = AL_NUM; ! 617: if (alnum >= 0 && alnum < 4) { ! 618: if (baud == iocbaud[alnum]) { ! 619: write_baud = 0; ! 620: if (newlcr == ioclcr[alnum]) { ! 621: write_lcr = 0; ! 622: } ! 623: } ! 624: iocbaud[alnum] = baud; ! 625: ioclcr[alnum] = newlcr; ! 626: } ! 627: ! 628: if (write_lcr) { ! 629: unsigned char ier_save; ! 630: s=sphi(); ! 631: ier_save=inb(b+IER); ! 632: if (write_baud) { ! 633: outb(b+LCR, LC_DLAB); ! 634: outb(b+DLL, baud); ! 635: outb(b+DLH, baud >> 8); ! 636: } ! 637: outb(b+LCR, newlcr); ! 638: if (com_usage[AL_NUM].uart_type == US_16550A) ! 639: outb(b+FCR, FC_ENABLE | FC_Rx_RST | FC_Rx_08); ! 640: outb(b+IER, ier_save); ! 641: spl(s); ! 642: } ! 643: ! 644: set_poll_rate(); ! 645: } ! 646: ! 647: /* ! 648: * Middle level processor. ! 649: * ! 650: * Invoked 10 times per second. (Once every ten clock ticks.) ! 651: * Tranfers rawin buffer [from intr level] to canonical input queue. ! 652: * Checks modem status for loss of carrier. ! 653: * Transfers output queue to rawout buffer [for intr level]. ! 654: */ ! 655: alxcycle(tp) ! 656: register TTY * tp; ! 657: { ! 658: register int b; ! 659: register int n; ! 660: unsigned char msr, mcr; ! 661: int s; ! 662: silo_t * out_silo = &com_usage[AL_NUM].raw_out; ! 663: silo_t * in_silo = &com_usage[AL_NUM].raw_in; ! 664: ! 665: REPORT_OE; ! 666: /* ! 667: * Check Carrier Detect (RLSD). ! 668: * ! 669: * Modem status interrupts were not enabled due to 8250 hardware bug. ! 670: * Enabling modem status and receive interrupts may cause lockup ! 671: * on older parts. ! 672: */ ! 673: if (tp->t_flags & T_MODC) { ! 674: ! 675: /* ! 676: * Get status ! 677: */ ! 678: msr = inb(ALPORT+MSR); ! 679: ! 680: /* ! 681: * Carrier changed. ! 682: */ ! 683: if ((msr & MS_RLSD) && !(tp->t_flags & T_CARR)) { ! 684: /* ! 685: * Carrier is on - wakeup open. ! 686: */ ! 687: s = sphi(); ! 688: tp->t_flags |= T_CARR; ! 689: spl(s); ! 690: wakeup((char *)(&tp->t_open)); ! 691: } ! 692: ! 693: if (!(msr & MS_RLSD) && (tp->t_flags & T_CARR)) { ! 694: s = sphi(); ! 695: RAWIN_FLUSH(in_silo); ! 696: RAWOUT_FLUSH(out_silo); ! 697: tp->t_flags &= ~T_CARR; ! 698: spl(s); ! 699: tthup(tp); ! 700: } ! 701: } ! 702: ! 703: /* ! 704: * Empty raw input buffer. ! 705: * ! 706: * The line discipline module (tty.c) will set T_ISTOP true when the ! 707: * tt input queue is nearly full (tp->t_iq.cq_cc >= IHILIM), and make ! 708: * T_ISTOP false when it's ready for more input. ! 709: * ! 710: * When T_ISTOP is true, ttin() simply discards the character passed. ! 711: */ ! 712: #ifndef NOISILO ! 713: if (!(tp->t_flags & T_ISTOP)) { ! 714: while (in_silo->SILO_CHAR_COUNT > 0) { ! 715: s = sphi(); ! 716: ttin(tp, in_silo->si_buf[in_silo->si_ox]); ! 717: if (in_silo->si_ox < MAX_SILO_INDEX) ! 718: in_silo->si_ox++; ! 719: else ! 720: in_silo->si_ox = 0; ! 721: in_silo->SILO_CHAR_COUNT--; ! 722: spl(s); ! 723: } ! 724: } ! 725: #endif ! 726: ! 727: /* ! 728: * Hardware flow control. ! 729: * Check CTS to see if we need to halt output. ! 730: * (MS_INTR should have done this - repeat code here to be sure) ! 731: * Check input silo to see if we need to raise RTS. ! 732: */ ! 733: if (tp->t_flags & T_CFLOW) { ! 734: ! 735: /* ! 736: * Get status ! 737: */ ! 738: msr = inb(ALPORT+MSR); ! 739: ! 740: s = sphi(); ! 741: if (msr & MS_CTS) ! 742: com_usage[AL_NUM].ohlt = 0; ! 743: else ! 744: com_usage[AL_NUM].ohlt = 1; ! 745: spl(s); ! 746: #if TRACER ! 747: if(t_hal & 4) {static cts = 0; ! 748: if (!cts && (msr & MS_CTS)) { ! 749: cts = 1; ! 750: printf("["); ! 751: } else if (cts && !(msr & MS_CTS)) { ! 752: cts = 0; ! 753: printf("]"); ! 754: }} ! 755: #endif ! 756: ! 757: /* ! 758: * If using hardware flow control, see if we need to drop RTS. ! 759: */ ! 760: if ( (tp->t_flags & T_CFLOW) ! 761: #ifdef NO_ISILO ! 762: && (tp->t_flags & T_ISTOP)) { ! 763: #else ! 764: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 765: #endif ! 766: s = sphi(); ! 767: mcr = inb(ALPORT+MCR); ! 768: if (mcr & MC_RTS) { ! 769: outb(ALPORT+MCR, mcr & ~MC_RTS); ! 770: #if TRACER ! 771: tprintf("-"); ! 772: #endif ! 773: } ! 774: spl(s); ! 775: } ! 776: ! 777: /* ! 778: * If input silo below low mark, assert RTS. ! 779: */ ! 780: #ifdef NO_ISILO ! 781: if ((tp->t_flags & T_ISTOP) == 0) { ! 782: #else ! 783: if (in_silo->SILO_CHAR_COUNT <= SILO_LOW_MARK) { ! 784: #endif ! 785: s = sphi(); ! 786: mcr = inb(ALPORT+MCR); ! 787: if ((mcr & MC_RTS) == 0) { ! 788: outb(ALPORT+MCR, mcr | MC_RTS); ! 789: #if TRACER ! 790: tprintf("+"); ! 791: #endif ! 792: } ! 793: spl(s); ! 794: } ! 795: } ! 796: ! 797: /* ! 798: * Calculate free output slot count. ! 799: */ ! 800: n = sizeof(out_silo->si_buf) - 1; ! 801: n += out_silo->si_ox - out_silo->si_ix; ! 802: n %= sizeof(out_silo->si_buf); ! 803: ! 804: /* ! 805: * Fill raw output buffer. ! 806: */ ! 807: for (;;) { ! 808: if (--n < 0) ! 809: break; ! 810: s = sphi(); ! 811: b = ttout(tp); ! 812: spl(s); ! 813: if (b < 0) ! 814: break; ! 815: ! 816: s = sphi(); ! 817: out_silo->si_buf[out_silo->si_ix] = b; ! 818: if (out_silo->si_ix >= sizeof(out_silo->si_buf) - 1) ! 819: out_silo->si_ix = 0; ! 820: else ! 821: out_silo->si_ix++; ! 822: spl(s); ! 823: } ! 824: ! 825: /* ! 826: * (Re)start output, wake sleeping processes, etc. ! 827: */ ! 828: ttstart(tp); ! 829: ! 830: /* ! 831: * Schedule next cycle. ! 832: */ ! 833: if (com_usage[AL_NUM].in_use) ! 834: timeout(&tp->t_rawtim, HZ/10, alxcycle, tp); ! 835: } ! 836: ! 837: /* ! 838: * Serial Transmit Start Routine. ! 839: */ ! 840: alxstart(tp) ! 841: register TTY * tp; ! 842: { ! 843: int b; ! 844: int s; ! 845: extern alxbreak(); ! 846: int need_xmit = 1; /* True if should start sending data now. */ ! 847: silo_t * out_silo = &com_usage[AL_NUM].raw_out; ! 848: ! 849: /* ! 850: * Read line status register AFTER disabling interrupts. ! 851: */ ! 852: s = sphi(); ! 853: LSR_READ(b, ALPORT); ! 854: ! 855: /* ! 856: * Process break indication. ! 857: * NOTE: Break indication cleared when line status register was read. ! 858: */ ! 859: if (b & LS_BREAK) ! 860: defer(alxbreak, tp); ! 861: ! 862: /* ! 863: * If no output data, it may be time to finish closing the port; ! 864: * but won't need another xmit interrupt. ! 865: */ ! 866: if (out_silo->si_ix == out_silo->si_ox) { ! 867: wakeup((char *)out_silo); ! 868: need_xmit = 0; ! 869: } ! 870: ! 871: /* ! 872: * Do nothing if output is stopped. ! 873: */ ! 874: if (tp->t_flags & T_STOP) ! 875: need_xmit = 0; ! 876: if (com_usage[AL_NUM].ohlt) ! 877: need_xmit = 0; ! 878: ! 879: /* ! 880: * Start data transmission by writing to UART xmit reg. ! 881: */ ! 882: if ((b & LS_TxRDY) && need_xmit) { ! 883: int xmit_count; ! 884: ! 885: xmit_count = (com_usage[AL_NUM].uart_type == US_16550A)?16:1; ! 886: alx_send(out_silo, ALPORT+DREG, xmit_count); ! 887: } ! 888: ! 889: spl(s); ! 890: } ! 891: ! 892: /* ! 893: * Serial Received Break Handler. ! 894: */ ! 895: alxbreak(tp) ! 896: TTY * tp; ! 897: { ! 898: int s; ! 899: silo_t * out_silo = &com_usage[AL_NUM].raw_out; ! 900: silo_t * in_silo = &com_usage[AL_NUM].raw_in; ! 901: ! 902: s = sphi(); ! 903: RAWIN_FLUSH(in_silo); ! 904: RAWOUT_FLUSH(out_silo); ! 905: spl(s); ! 906: ttsignal(tp, SIGINT); ! 907: } ! 908: ! 909: /* ! 910: * Serial Interrupt Handler. ! 911: */ ! 912: alxintr(tp) ! 913: register TTY * tp; ! 914: { ! 915: int c; ! 916: register int port = ALPORT; ! 917: unsigned char msr, lsr; ! 918: int xmit_count; ! 919: silo_t * in_silo = &com_usage[AL_NUM].raw_in; ! 920: silo_t * out_silo = &com_usage[AL_NUM].raw_out; ! 921: ! 922: if (tp) { ! 923: rescan: ! 924: switch (inb(port+IIR) & 0x07) { ! 925: ! 926: case LS_INTR: ! 927: LSR_READ(lsr, port); ! 928: if (lsr & LS_BREAK) ! 929: defer(alxbreak, tp); ! 930: goto rescan; ! 931: ! 932: case Rx_INTR: ! 933: c = inb(port+DREG); ! 934: if (tp->t_open == 0) ! 935: goto rescan; ! 936: /* ! 937: * Must recognize XOFF quickly to avoid transmit overrun. ! 938: * Recognize XON here as well to avoid race conditions. ! 939: */ ! 940: if (ISIXON) { ! 941: /* ! 942: * XOFF. ! 943: */ ! 944: if (ISSTOP) { ! 945: tp->t_flags |= T_STOP; ! 946: goto rescan; ! 947: } ! 948: ! 949: /* ! 950: * XON. ! 951: */ ! 952: if (ISSTART) { ! 953: tp->t_flags &= ~T_STOP; ! 954: goto rescan; ! 955: } ! 956: } ! 957: ! 958: /* ! 959: * Save char in raw input buffer. ! 960: */ ! 961: #ifdef NO_ISILO ! 962: if (tp->t_flags & T_ISTOP) { ! 963: /* ! 964: * If using hardware flow control, we need to drop RTS. ! 965: */ ! 966: if (tp->t_flags & T_CFLOW) { ! 967: unsigned char mcr = inb(port+MCR); ! 968: if (mcr & MC_RTS) ! 969: outb(port+MCR, mcr & ~MC_RTS); ! 970: } ! 971: } else { ! 972: ttin(tp, c); ! 973: } ! 974: #else ! 975: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) { ! 976: in_silo->si_buf[in_silo->si_ix] = c; ! 977: if (in_silo->si_ix < MAX_SILO_INDEX) ! 978: in_silo->si_ix++; ! 979: else ! 980: in_silo->si_ix = 0; ! 981: in_silo->SILO_CHAR_COUNT++; ! 982: } ! 983: ! 984: /* ! 985: * If using hardware flow control, see if we need to drop RTS. ! 986: */ ! 987: if ( (tp->t_flags & T_CFLOW) ! 988: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 989: unsigned char mcr = inb(port+MCR); ! 990: if (mcr & MC_RTS) { ! 991: outb(port+MCR, mcr & ~MC_RTS); ! 992: } ! 993: } ! 994: #endif ! 995: goto rescan; ! 996: ! 997: case Tx_INTR: ! 998: /* ! 999: * Do nothing if output is stopped. ! 1000: */ ! 1001: if (tp->t_flags & T_STOP) ! 1002: goto rescan; ! 1003: if (com_usage[AL_NUM].ohlt) ! 1004: goto rescan; ! 1005: ! 1006: /* ! 1007: * Transmit next char in raw output buffer. ! 1008: */ ! 1009: xmit_count = ! 1010: (com_usage[AL_NUM].uart_type == US_16550A)?16:1; ! 1011: alx_send(out_silo, port+DREG, xmit_count); ! 1012: goto rescan; ! 1013: ! 1014: case MS_INTR: ! 1015: /* ! 1016: * Get status (and clear interrupt). ! 1017: */ ! 1018: msr = inb(port+MSR); ! 1019: ! 1020: /* ! 1021: * Hardware flow control. ! 1022: * Check CTS to see if we need to halt output. ! 1023: */ ! 1024: if (tp->t_flags & T_CFLOW) { ! 1025: if (msr & MS_CTS) ! 1026: com_usage[AL_NUM].ohlt = 0; ! 1027: else ! 1028: com_usage[AL_NUM].ohlt = 1; ! 1029: } ! 1030: ! 1031: goto rescan; ! 1032: } /* endswitch */ ! 1033: } else { ! 1034: /* ! 1035: * If tp is zero, an interrupt occurred before things ! 1036: * are fully set up. Just try to clear all pending ! 1037: * interrupts from ANY serial ports. ! 1038: */ ! 1039: int com_num; ! 1040: for (com_num = 0; com_num < 4; com_num++) { ! 1041: port = AL_ADDR[com_num]; ! 1042: inb(port+IIR); ! 1043: inb(port+LSR); ! 1044: inb(port+MSR); ! 1045: inb(port+DREG); ! 1046: } ! 1047: } ! 1048: } ! 1049: ! 1050: /* ! 1051: * alxclk will be called every time T0 interrupts - if it returns 0, ! 1052: * the usual system timer interrupt stuff is done ! 1053: */ ! 1054: static int alxclk() ! 1055: { ! 1056: static int count; ! 1057: int i; ! 1058: ! 1059: for (i = 0; i < NUM_AL_PORTS; i++) ! 1060: if (com_usage[i].poll) ! 1061: alxpoll(tp_table[i]); ! 1062: count++; ! 1063: if (count >= poll_divisor) ! 1064: count = 0; ! 1065: return count; ! 1066: } ! 1067: ! 1068: /* ! 1069: * set_poll_rate is called when a port is opened or closed or changes speed ! 1070: * it sets the polling rate only as fast as needed, and shuts off polling ! 1071: * whenever possible ! 1072: */ ! 1073: static set_poll_rate() ! 1074: { ! 1075: int port_num, max_rate, port_rate; ! 1076: ! 1077: /* ! 1078: * If another driver has the polling clock, do nothing. ! 1079: */ ! 1080: if (poll_owner & ~ POLL_AL) ! 1081: return; ! 1082: ! 1083: /* ! 1084: * Find highest valid polling rate in units of HZ/10. ! 1085: * If using FIFO chip, can poll at 1/16 the usual rate. ! 1086: */ ! 1087: max_rate = 0; ! 1088: for (port_num = 0; port_num < NUM_AL_PORTS; port_num++) { ! 1089: if (com_usage[port_num].poll) { ! 1090: port_rate = alp_rate[(tp_table[port_num])->t_sgttyb.sg_ispeed]; ! 1091: if (com_usage[port_num].uart_type == US_16550A) { ! 1092: port_rate /= 16; ! 1093: if (port_rate % HZ) ! 1094: port_rate += HZ - (port_rate % HZ); ! 1095: } ! 1096: if (max_rate < port_rate) ! 1097: max_rate = port_rate; ! 1098: } ! 1099: } ! 1100: /* ! 1101: * if max_rate is not current rate, adjust the system clock ! 1102: */ ! 1103: if (max_rate != poll_rate) { ! 1104: poll_rate = max_rate; ! 1105: poll_divisor = poll_rate/HZ; /* used in alxclk() */ ! 1106: altclk_out(); /* stop previous polling */ ! 1107: poll_owner &= ~ POLL_AL; ! 1108: if (max_rate) { /* resume polling at new rate if needed */ ! 1109: poll_owner |= POLL_AL; ! 1110: altclk_in(poll_rate, alxclk); ! 1111: } ! 1112: CDUMP("new rate", 0) ! 1113: } ! 1114: } ! 1115: ! 1116: /* ! 1117: * alxpoll() ! 1118: * ! 1119: * Serial polling handler. Compare to alxintr(). ! 1120: */ ! 1121: static void alxpoll(tp) ! 1122: register TTY * tp; ! 1123: { ! 1124: int c; ! 1125: int port = ALPORT; ! 1126: int xmit_count; ! 1127: unsigned char lsr; ! 1128: silo_t * in_silo = &com_usage[AL_NUM].raw_in; ! 1129: silo_t * out_silo = &com_usage[AL_NUM].raw_out; ! 1130: ! 1131: /* ! 1132: * Check for received break first. ! 1133: * This status is wiped out on reading the LSR. ! 1134: */ ! 1135: LSR_READ(lsr, port); ! 1136: if (lsr & LS_BREAK) ! 1137: defer(alxbreak, tp); ! 1138: ! 1139: /* ! 1140: * Handle all incoming characters. ! 1141: */ ! 1142: for (;;) { ! 1143: LSR_READ(lsr, port); ! 1144: if ((lsr & LS_RxRDY) == 0) ! 1145: break; ! 1146: c = inb(port+DREG); ! 1147: if (tp->t_open == 0) ! 1148: continue; ! 1149: /* ! 1150: * Must recognize XOFF quickly to avoid transmit overrun. ! 1151: * Recognize XON here as well to avoid race conditions. ! 1152: */ ! 1153: if (ISIXON) { ! 1154: /* ! 1155: * XOFF. ! 1156: */ ! 1157: if (ISSTOP) { ! 1158: tp->t_flags |= T_STOP; ! 1159: continue; ! 1160: } ! 1161: ! 1162: /* ! 1163: * XON. ! 1164: */ ! 1165: if (ISSTART) { ! 1166: tp->t_flags &= ~T_STOP; ! 1167: continue; ! 1168: } ! 1169: } ! 1170: ! 1171: /* ! 1172: * Save char in raw input buffer. ! 1173: */ ! 1174: #ifdef NO_ISILO ! 1175: if (tp->t_flags & T_ISTOP) { ! 1176: /* ! 1177: * If using hardware flow control, we need to drop RTS. ! 1178: */ ! 1179: if (tp->t_flags & T_CFLOW) { ! 1180: unsigned char mcr = inb(port+MCR); ! 1181: if (mcr & MC_RTS) ! 1182: outb(port+MCR, mcr & ~MC_RTS); ! 1183: } ! 1184: } else { ! 1185: ttin(tp, c); ! 1186: } ! 1187: #else ! 1188: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) { ! 1189: in_silo->si_buf[in_silo->si_ix] = c; ! 1190: if (in_silo->si_ix < MAX_SILO_INDEX) ! 1191: in_silo->si_ix++; ! 1192: else ! 1193: in_silo->si_ix = 0; ! 1194: in_silo->SILO_CHAR_COUNT++; ! 1195: } ! 1196: ! 1197: /* ! 1198: * If using hardware flow control, see if we need to drop RTS. ! 1199: */ ! 1200: if ( (tp->t_flags & T_CFLOW) ! 1201: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 1202: unsigned char mcr = inb(port+MCR); ! 1203: if (mcr & MC_RTS) { ! 1204: outb(port+MCR, mcr & ~MC_RTS); ! 1205: } ! 1206: } ! 1207: #endif ! 1208: } ! 1209: ! 1210: /* ! 1211: * Handle outgoing characters. ! 1212: * Do nothing if output is stopped. ! 1213: */ ! 1214: LSR_READ(lsr, port); ! 1215: if ((lsr & LS_TxRDY) ! 1216: && !(tp->t_flags & T_STOP) ! 1217: && !(com_usage[AL_NUM].ohlt)) { ! 1218: /* ! 1219: * Transmit next char in raw output buffer. ! 1220: */ ! 1221: xmit_count = (com_usage[AL_NUM].uart_type == US_16550A)?16:1; ! 1222: alx_send(out_silo, port+DREG, xmit_count); ! 1223: } ! 1224: ! 1225: /* ! 1226: * Hardware flow control. ! 1227: * Check CTS to see if we need to halt output. ! 1228: */ ! 1229: if (tp->t_flags & T_CFLOW) { ! 1230: if (inb(port+MSR) & MS_CTS) ! 1231: com_usage[AL_NUM].ohlt = 0; ! 1232: else ! 1233: com_usage[AL_NUM].ohlt = 1; ! 1234: } ! 1235: } ! 1236: ! 1237: /* ! 1238: * alx_send() ! 1239: * ! 1240: * Write to xmit data register of the UART. ! 1241: * Assume all checking about whether it's time to send has been done already. ! 1242: * Called by time-critical IRQ and polling routines! ! 1243: * ! 1244: * "rawout" is the output silo for the TTY struct supplying data to the port. ! 1245: * "dreg" is the i/o address of the UART xmit data register. ! 1246: * "xmit_count" is the max number of chars we can write (16 for FIFO parts). ! 1247: */ ! 1248: static void alx_send(rawout, dreg, xmit_count) ! 1249: register silo_t * rawout; ! 1250: int dreg, xmit_count; ! 1251: { ! 1252: /* ! 1253: * Transmit next chars in raw output buffer. ! 1254: */ ! 1255: for (;(rawout->si_ix != rawout->si_ox) && xmit_count; xmit_count--) { ! 1256: outb(dreg, rawout->si_buf[rawout->si_ox]); ! 1257: /* ! 1258: * Adjust raw output buffer output index. ! 1259: */ ! 1260: if (++rawout->si_ox >= sizeof(rawout->si_buf)) ! 1261: rawout->si_ox = 0; ! 1262: } ! 1263: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.