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