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