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