|
|
1.1 ! root 1: /* (-lgl ! 2: * COHERENT Driver Kit Version 1.1.0 ! 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.12 91/08/06 10:32:23 bin ! 8: * 2nd rts/cts version form hal ! 9: * ! 10: * Revision 1.7 91/08/02 07:59:27 hal ! 11: * Raw input silo uses last slot for byte count. ! 12: * Modem control now gives RTS/CTS flow control: ! 13: * CTS is checked 10x/sec (probably not often enough). ! 14: * On Rx_INT, check T_ISTOP and rawin silo levels; drop RTS if need to. ! 15: * ! 16: * Revision 1.6 91/04/03 18:55:07 root ! 17: * alxclose(): do closing state machine BEFORE dropping control lines. ! 18: * alxioctl(): save and restore interrupt enable register. ! 19: * alxopen(): wait for pending last close (fixes SLOW port bug). ! 20: * This version needs al.h 1.3 or later. ! 21: * ! 22: * Revision 1.5 91/04/02 17:53:37 root ! 23: * save MSR delta status; add MS_INTR handling; use al.h 1.2 ! 24: * ! 25: * Revision 1.4 91/02/22 09:21:17 root ! 26: * alxintr(): replace repeated use of ALPORT macro by local variable ! 27: * ! 28: * Revision 1.3 91/02/21 14:58:16 root ! 29: * Fix unconditional "hupcl" bug in 3.1.0 version. ! 30: * ! 31: * Revision 1.2 91/02/21 11:21:40 hal ! 32: * Used in COH Release 3.1.0 - add COM3/COM4 and polling ! 33: * ! 34: * Revision 1.1 91/02/21 11:08:31 hal ! 35: * Used in COH Release 3.0.0 - no COM3/COM4 ! 36: * ! 37: -lgl) */ ! 38: /* ! 39: * Shared parts of IBM async port drivers. ! 40: */ ! 41: #include <sys/coherent.h> ! 42: #include <sys/i8086.h> ! 43: #include <sys/al.h> ! 44: #include <sys/con.h> ! 45: #include <errno.h> ! 46: #include <sys/stat.h> ! 47: #include <sys/tty.h> ! 48: #include <sys/uproc.h> ! 49: #include <sys/timeout.h> ! 50: #include <sys/clist.h> ! 51: #include <sys/ins8250.h> ! 52: #include <sys/sched.h> ! 53: ! 54: #define ALPORT (((COM_DDP *)(tp->t_ddp))->port) ! 55: #define AL_TIM (((COM_DDP *)(tp->t_ddp))->tim) ! 56: #define AL_NUM (((COM_DDP *)(tp->t_ddp))->com_num) ! 57: #define AL_MSR_DELTAS (((COM_DDP *)(tp->t_ddp))->msr_deltas) ! 58: #define AL_H_CLOSE (((COM_DDP *)(tp->t_ddp))->h_close) ! 59: ! 60: #define DTRTMOUT 3 /* DTR timeout interval in seconds for close */ ! 61: #define IENABLE (IE_RxI+IE_TxI+IE_LSI+IE_MSI) ! 62: ! 63: /* ! 64: * For rawin silo (see ktty.h), use last element of si_buf to count the number ! 65: * of characters in the silo. ! 66: */ ! 67: #define SILO_CHAR_COUNT si_buf[SI_BUFSIZ-1] ! 68: #define SILO_HIGH_MARK (SI_BUFSIZ-SI_BUFSIZ/4) ! 69: #define MAX_SILO_INDEX (SI_BUFSIZ-2) ! 70: #define MAX_SILO_CHARS (SI_BUFSIZ-1) ! 71: ! 72: int al_sg_set = 0; ! 73: int al_sg_clr = 0; ! 74: static int poll_divisor; /* set by set_poll_rate(), read by alxclk() */ ! 75: ! 76: /* ! 77: * functions herein ! 78: */ ! 79: int alxopen(); ! 80: int alxclose(); ! 81: int alxtimer(); ! 82: int alxioctl(); ! 83: int alxparam(); ! 84: int alxcycle(); ! 85: int alxstart(); ! 86: int alxbreak(); ! 87: int alxintr(); ! 88: static int alxclk(); ! 89: static set_poll_rate(); ! 90: ! 91: /* ! 92: * Baud rate table and polling rate table. ! 93: * Indexed by ioctl bit rates. ! 94: */ ! 95: int albaud[] ={ ! 96: 0, /* 0 */ ! 97: 2304, /* 50 */ ! 98: 1536, /* 75 */ ! 99: 1047, /* 110 */ ! 100: 857, /* 134.5 */ ! 101: 768, /* 150 */ ! 102: 576, /* 200 */ ! 103: 384, /* 300 */ ! 104: 192, /* 600 */ ! 105: 96, /* 1200 */ ! 106: 64, /* 1800 */ ! 107: 58, /* 2000 */ ! 108: 48, /* 2400 */ ! 109: 32, /* 3600 */ ! 110: 24, /* 4800 */ ! 111: 16, /* 7200 */ ! 112: 12, /* 9600 */ ! 113: 6, /* 19200 */ ! 114: 0, /* EXTA */ ! 115: 0 /* EXTB */ ! 116: }; ! 117: ! 118: /* ! 119: * alp_rate[] is tied to albaud[] - it gives the minimum polling ! 120: * rate for the corresponding port speed; it must be a multiple ! 121: * of 100 (system clock Hz) and >= baud/6 ! 122: */ ! 123: int alp_rate[] ={ /* baud/6 or zero */ ! 124: 0, /* 0 */ ! 125: 1*HZ, /* 50 */ ! 126: 1*HZ, /* 75 */ ! 127: 1*HZ, /* 110 */ ! 128: 1*HZ, /* 134.5 */ ! 129: 1*HZ, /* 150 */ ! 130: 1*HZ, /* 200 */ ! 131: 1*HZ, /* 300 */ ! 132: 1*HZ, /* 600 */ ! 133: 2*HZ, /* 1200 */ ! 134: 3*HZ, /* 1800 */ ! 135: 4*HZ, /* 2000 */ ! 136: 4*HZ, /* 2400 */ ! 137: 6*HZ, /* 3600 */ ! 138: 8*HZ, /* 4800 */ ! 139: 12*HZ, /* 7200 */ ! 140: 16*HZ, /* 9600 */ ! 141: 0, /* 19200 */ ! 142: 0, /* EXTA */ ! 143: 0 /* EXTB */ ! 144: }; ! 145: ! 146: /* ! 147: * the following is for debug only ! 148: */ ! 149: #if 0 ! 150: #define CDUMP(text) cdump(text); ! 151: ! 152: cdump(message) ! 153: char *message; ! 154: { ! 155: int i, b; ! 156: ! 157: for (i = 0; i < NUM_AL_PORTS; i++) { ! 158: b = ((COM_DDP *)(tp_table[i]->t_ddp))->port; ! 159: printf("%x:%x:%x:%x ", i+1, b, inb(b+MCR), inb(b+IER)); ! 160: } ! 161: printf("poll=%d ", poll_rate); ! 162: printf("%s\n", message); ! 163: } ! 164: #else ! 165: #define CDUMP(text) ! 166: #endif ! 167: ! 168: /* ! 169: * alxopen() ! 170: */ ! 171: alxopen(dev, mode, tp, irqtty) ! 172: dev_t dev; ! 173: int mode; ! 174: register TTY *tp, **irqtty; ! 175: { ! 176: register int s; ! 177: register int b; ! 178: register int minor_h; /* minor device number including high bit */ ! 179: unsigned char msr; ! 180: ! 181: minor_h = minor(dev); /* complete minor number */ ! 182: ! 183: b = ALPORT; ! 184: ! 185: if (inb(b+IER) & ~IENABLE) { /* chip not found */ ! 186: u.u_error = ENXIO; ! 187: return; ! 188: } ! 189: ! 190: if ((tp->t_flags & T_EXCL) && !super()) { ! 191: u.u_error = ENODEV; ! 192: return; ! 193: } ! 194: ! 195: if (drvl[major(dev)].d_time != 0) { /* Modem settling */ ! 196: u.u_error = EDBUSY; ! 197: return; ! 198: } ! 199: ! 200: /* ! 201: * Can't open a polled port if another driver is using polling. ! 202: */ ! 203: if (dev & CPOLL && poll_owner & ~ POLL_AL) { ! 204: u.u_error = EDBUSY; ! 205: return; ! 206: } ! 207: ! 208: /* ! 209: * exclusion conditions: ! 210: * can't have same port polled and IRQ at once ! 211: * can't have both com[13] or both com[24] IRQ at once ! 212: */ ! 213: if (dev & CPOLL) { ! 214: if (com_usage[AL_NUM] == COM_IRQ) { ! 215: u.u_error = EDBUSY; ! 216: return; ! 217: } ! 218: } else { ! 219: if (com_usage[AL_NUM] == COM_POLLED ! 220: || com_usage[AL_NUM ^ 2] == COM_IRQ) { ! 221: u.u_error = EDBUSY; ! 222: return; ! 223: } ! 224: } ! 225: ! 226: if (tp->t_open == 0) { /* not already open */ ! 227: /* ! 228: * Wait for pending last close (if any) to finish. ! 229: */ ! 230: while (AL_H_CLOSE) { ! 231: sleep((char *)(&AL_H_CLOSE), CVTTOUT, IVTTOUT, ! 232: SVTTOUT); ! 233: } ! 234: s = sphi(); ! 235: /* ! 236: * Raise basic modem control lines even if modem ! 237: * control hasn't been specified. ! 238: * MC_OUT2 turns on NON-open-collector IRQ line from the UART. ! 239: * since we can't have two UART's on same IRQ with MC_OUT2 on ! 240: */ ! 241: if (dev & CPOLL) { ! 242: outb(b+MCR, MC_RTS|MC_DTR); ! 243: } else { ! 244: *irqtty = tp_table[AL_NUM]; ! 245: outb(b+MCR, MC_RTS|MC_DTR|MC_OUT2); ! 246: } ! 247: ! 248: outb(b+IER, IENABLE); /* enable interrupts */ ! 249: ! 250: if ((minor_h & NMODC) == 0) { /* want modem control? */ ! 251: tp->t_flags |= T_MODC | T_HOPEN | T_STOP; ! 252: while (1) { /* wait for carrier */ ! 253: msr = inb(b+MSR); ! 254: AL_MSR_DELTAS |= msr; ! 255: if (msr & MS_RLSD) ! 256: break; ! 257: sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, ! 258: SVTTOUT); /* wait for carrier */ ! 259: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 260: outb(b+MCR, inb(b+MCR)&MC_OUT2); ! 261: /* ! 262: * make sure port is hungup ! 263: * disable all ints except for TxI ! 264: */ ! 265: outb(b+IER, IE_TxI); ! 266: u.u_error = EINTR; ! 267: spl(s); ! 268: return; ! 269: } ! 270: } ! 271: tp->t_flags &= ~T_HOPEN; /* no longer hanging in open */ ! 272: if (msr & MS_CTS) ! 273: tp->t_flags &= ~T_STOP; ! 274: } else { ! 275: tp->t_flags &= ~T_MODC; /* no modem control */ ! 276: } ! 277: tp->t_flags |= T_CARR; /* carrier on */ ! 278: ttopen(tp); /* stty inits */ ! 279: ! 280: /* ! 281: * Allow custom modification of defaults. ! 282: */ ! 283: tp->t_sgttyb.sg_flags |= al_sg_set; ! 284: tp->t_sgttyb.sg_flags &= ~al_sg_clr; ! 285: alxparam(tp); ! 286: spl(s); ! 287: } else { /* already open */ ! 288: if ((minor_h & NMODC) == 0) { /* want modem control? */ ! 289: if ((tp->t_flags & T_MODC)==0) { /* already not modem control? */ ! 290: u.u_error = ENODEV; /* yes, don't allow open */ ! 291: return; ! 292: } ! 293: } else { /* don't want modem control */ ! 294: if (tp->t_flags & T_MODC) { /* already modem control? */ ! 295: u.u_error = ENODEV; /* yes, don't allow open */ ! 296: return; ! 297: } ! 298: } ! 299: } ! 300: tp->t_open++; ! 301: ttsetgrp(tp, dev); ! 302: ! 303: /* ! 304: * now that we've successfully opened, designate port as ! 305: * polled or interrupt driven to avoid future conflicts ! 306: */ ! 307: if (dev & CPOLL) { ! 308: com_usage[AL_NUM] = COM_POLLED; ! 309: set_poll_rate(); ! 310: } else { /* irq-driven port */ ! 311: com_usage[AL_NUM] = COM_IRQ; ! 312: } ! 313: ! 314: CDUMP((dev&CPOLL)?"open polled":"open irq") ! 315: } ! 316: ! 317: /* ! 318: * alxclose() ! 319: * ! 320: * Called at high priority on last close for the device. ! 321: */ ! 322: alxclose(dev, mode, tp) ! 323: dev_t dev; ! 324: int mode; ! 325: TTY *tp; ! 326: { ! 327: register unsigned holdflags; ! 328: register int b; ! 329: int state, maj; ! 330: int s; ! 331: ! 332: /* ! 333: * Called at high priority by alclose after al_buff is drained ! 334: */ ! 335: holdflags = tp->t_flags; /* save flags */ ! 336: AL_H_CLOSE = 1; /* disallow reopen til done closing */ ! 337: ttclose(tp); /* clear flags */ ! 338: b = ALPORT; ! 339: /* ! 340: * ttclose() only emptied the output queue tp->t_oq; ! 341: * now wait for the silo tp->rawout to empty ! 342: * and allow a delay for the UART on-chip xmit buffer to empty ! 343: * state 2: waiting for silo to empty ! 344: * state 1: stalling so UART can empty xmit buffer ! 345: * state 0: done! ok to shut off IRQ for this chip by clearing MC_OUT2 ! 346: */ ! 347: state = 2; ! 348: while (state) { ! 349: timeout(&AL_TIM, 10, wakeup, (int)&AL_TIM); ! 350: sleep((char *)&AL_TIM, CVTTOUT, IVTTOUT, SVTTOUT); ! 351: if (tp->t_rawout.si_ix == tp->t_rawout.si_ox && state) ! 352: state--; ! 353: } ! 354: ! 355: /* ! 356: * If not hanging in open ! 357: */ ! 358: if ((holdflags & T_HOPEN) == 0) { ! 359: /* ! 360: * Disable all ints except TxI ! 361: */ ! 362: outb(b+IER, IE_TxI); ! 363: } else { ! 364: /* ! 365: * Flags for first open ! 366: */ ! 367: tp->t_flags = T_MODC | T_HOPEN; ! 368: } ! 369: ! 370: /* ! 371: * If hupcls ! 372: */ ! 373: if (holdflags & T_HPCL) { ! 374: /* ! 375: * Hangup port ! 376: */ ! 377: s = sphi(); ! 378: outb(b+MCR, inb(b+MCR)&MC_OUT2); ! 379: spl(s); ! 380: ! 381: /* ! 382: * Hold dtr low for timeout ! 383: */ ! 384: maj = major(dev); ! 385: drvl[maj].d_time = 1; ! 386: sleep((char *)&drvl[maj].d_time, CVTTOUT, IVTTOUT, SVTTOUT); ! 387: drvl[maj].d_time = 0; ! 388: } ! 389: s = sphi(); ! 390: outb(b+MCR, inb(b+MCR)&(~MC_OUT2)); ! 391: spl(s); ! 392: com_usage[AL_NUM] = COM_UNUSED; ! 393: set_poll_rate(); ! 394: AL_H_CLOSE = 0; /* allow reopen - done closing */ ! 395: wakeup((char *)&AL_H_CLOSE); ! 396: CDUMP("closed") ! 397: } ! 398: ! 399: /* ! 400: * Common c_timer routine for async ports. ! 401: */ ! 402: alxtimer(dev) ! 403: dev_t dev; ! 404: { ! 405: if (++drvl[major(dev)].d_time > DTRTMOUT) ! 406: wakeup((char *)&drvl[major(dev)].d_time); ! 407: } ! 408: ! 409: ! 410: /* ! 411: * Common c_ioctl routine for async ports. ! 412: */ ! 413: alxioctl(dev, com, vec, tp) ! 414: dev_t dev; ! 415: struct sgttyb *vec; ! 416: register TTY *tp; ! 417: { ! 418: register int s, b; ! 419: int stat1, stat2; ! 420: unsigned char msr; ! 421: unsigned char ier_save; ! 422: ! 423: s = sphi(); ! 424: b = ALPORT; ! 425: ier_save=inb(b+IER); ! 426: stat1 = inb(b+MCR); /* get current MCR register status */ ! 427: stat2 = inb(b+LCR); /* get current LCR register status */ ! 428: ! 429: switch(com) { ! 430: case TIOCSBRK: /* set BREAK */ ! 431: outb(b+LCR, stat2|LC_SBRK); ! 432: break; ! 433: case TIOCCBRK: /* clear BREAK */ ! 434: outb(b+LCR, stat2 & ~LC_SBRK); ! 435: break; ! 436: case TIOCSDTR: /* set DTR */ ! 437: outb(b+MCR, stat1|MC_DTR); ! 438: break; ! 439: case TIOCCDTR: /* clear DTR */ ! 440: outb(b+MCR, stat1 & ~MC_DTR); ! 441: break; ! 442: case TIOCSRTS: /* set RTS */ ! 443: outb(b+MCR, stat1|MC_RTS); ! 444: break; ! 445: case TIOCCRTS: /* clear RTS */ ! 446: outb(b+MCR, stat1 & ~MC_RTS); ! 447: break; ! 448: case TIOCRSPEED: /* set "raw" I/O speed divisor */ ! 449: outb(b+LCR, stat2|LC_DLAB); /* set speed latch bit */ ! 450: outb(b+DLL, (unsigned) vec); ! 451: outb(b+DLH, (unsigned) vec >> 8); ! 452: outb(b+LCR, stat2); /* reset latch bit */ ! 453: break; ! 454: case TIOCWORDL: /* set word length and stop bits */ ! 455: outb(b+LCR, ((stat2&~0x7) | ((unsigned) vec & 0x7))); ! 456: break; ! 457: case TIOCRMSR: /* get CTS/DSR/RI/RLSD (MSR) */ ! 458: msr = inb(b+MSR); ! 459: AL_MSR_DELTAS |= msr; ! 460: stat1 = msr >> 4; ! 461: kucopy(&stat1, (unsigned *) vec, sizeof(unsigned)); ! 462: break; ! 463: default: ! 464: ttioctl(tp, com, vec); ! 465: } ! 466: outb(b+IER, ier_save); ! 467: spl(s); ! 468: } ! 469: ! 470: alxparam(tp) ! 471: TTY *tp; ! 472: { ! 473: register int b; ! 474: register int baud; ! 475: int s; ! 476: ! 477: b = ALPORT; ! 478: ! 479: /* ! 480: * error if input speed not the same as output speed ! 481: */ ! 482: if (tp->t_sgttyb.sg_ispeed!=tp->t_sgttyb.sg_ospeed) { ! 483: u.u_error = ENODEV; ! 484: return; ! 485: } ! 486: ! 487: if ((baud = albaud[tp->t_sgttyb.sg_ispeed]) == 0) { ! 488: if (tp->t_flags & T_MODC) { /* modem control? */ ! 489: tp->t_flags &= ~T_CARR; /* indicate no carrier */ ! 490: s = sphi(); ! 491: outb(b+MCR, inb(b+MCR) & MC_OUT2); /* hangup */ ! 492: spl(s); ! 493: } ! 494: } ! 495: ! 496: if (baud) { ! 497: unsigned char ier_save; ! 498: ! 499: s=sphi(); ! 500: ier_save=inb(b+IER); /* some chips need this */ ! 501: outb(b+LCR, LC_DLAB); ! 502: outb(b+DLL, baud); ! 503: outb(b+DLH, baud >> 8); ! 504: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) { ! 505: case EVENP: ! 506: outb(b+LCR, LC_CS7 + LC_PARENB + LC_PAREVEN); ! 507: break; ! 508: ! 509: case ODDP: ! 510: outb(b+LCR, LC_CS7 + LC_PARENB); ! 511: break; ! 512: ! 513: default: ! 514: outb(b+LCR, LC_CS8); ! 515: break; ! 516: } ! 517: outb(b+IER, ier_save); ! 518: spl(s); ! 519: } ! 520: set_poll_rate(); ! 521: } ! 522: ! 523: /* ! 524: * Middle level processor. ! 525: * ! 526: * Invoked 10 times per second. ! 527: * Checks modem status for loss of carrier. ! 528: * Tranfers rawin buffer [from intr level] to canonical input queue. ! 529: * Transfers output queue to rawout buffer [for intr level]. ! 530: */ ! 531: alxcycle(tp) ! 532: register TTY * tp; ! 533: { ! 534: register int b; ! 535: register int n; ! 536: unsigned char msr, mcr; ! 537: int s; ! 538: ! 539: /* ! 540: * Check modem status every ten clock ticks. ! 541: * ! 542: * Modem status interrupts were not enabled due to 8250 hardware bug. ! 543: * Enabling modem status and receive interrupts may cause lockup ! 544: * on older parts. ! 545: * ! 546: * Also check if input silo is nearly full in case we need RTS ! 547: * flow control. ! 548: */ ! 549: if (tp->t_flags & T_MODC) { ! 550: ! 551: /* ! 552: * Get status ! 553: */ ! 554: msr = inb(ALPORT+MSR); ! 555: AL_MSR_DELTAS |= msr; ! 556: ! 557: /* ! 558: * Carrier changed. ! 559: */ ! 560: if (AL_MSR_DELTAS & MS_DRLSD) { ! 561: AL_MSR_DELTAS &= ~MS_DRLSD; ! 562: /* ! 563: * wakeup open ! 564: */ ! 565: if (tp->t_open == 0) { ! 566: wakeup((char *)(&tp->t_open)); ! 567: } ! 568: ! 569: /* ! 570: * carrier off? ! 571: */ ! 572: else if ((msr & MS_RLSD) == 0) { ! 573: /* ! 574: * clear carrier flag; send hangup signal ! 575: */ ! 576: s = sphi(); ! 577: tp->t_rawin.si_ox = tp->t_rawin.si_ix; ! 578: tp->t_rawin.SILO_CHAR_COUNT = 0; ! 579: spl(s); ! 580: tthup(tp); ! 581: } ! 582: } ! 583: ! 584: /* ! 585: * CTS changed. ! 586: */ ! 587: if (AL_MSR_DELTAS & MS_DCTS) { ! 588: AL_MSR_DELTAS &= ~MS_DCTS; ! 589: if (msr & MS_CTS) ! 590: tp->t_flags &= ~T_STOP; ! 591: else ! 592: tp->t_flags |= T_STOP; ! 593: } ! 594: ! 595: /* ! 596: * If input silo not nearly full, assert RTS. ! 597: */ ! 598: if (tp->t_rawin.SILO_CHAR_COUNT <= SILO_HIGH_MARK) { ! 599: mcr = inb(ALPORT+MCR); ! 600: if ((mcr & MC_RTS) == 0) { ! 601: printf("%x RTS ON\n", ALPORT); ! 602: outb(ALPORT+MCR, mcr | MC_RTS); ! 603: } ! 604: } ! 605: } ! 606: ! 607: /* ! 608: * Empty raw input buffer. ! 609: * If modem control enabled and tt input queue is at high limit ! 610: * (e.g., tp->t_iq.cq_cc >= IHILIM), don't copy from rawin silo ! 611: * to tt input queue. ! 612: */ ! 613: if (!(tp->t_flags & T_MODC) || !(tp->t_flags & T_ISTOP)) ! 614: while (tp->t_rawin.SILO_CHAR_COUNT > 0) { ! 615: ttin(tp, tp->t_rawin.si_buf[tp->t_rawin.si_ox]); ! 616: if (tp->t_rawin.si_ox < MAX_SILO_INDEX) ! 617: tp->t_rawin.si_ox++; ! 618: else ! 619: tp->t_rawin.si_ox = 0; ! 620: tp->t_rawin.SILO_CHAR_COUNT--; ! 621: } ! 622: ! 623: /* ! 624: * Calculate free output slot count. ! 625: */ ! 626: n = sizeof(tp->t_rawout.si_buf) - 1; ! 627: n += tp->t_rawout.si_ox - tp->t_rawout.si_ix; ! 628: n %= sizeof(tp->t_rawout.si_buf); ! 629: ! 630: /* ! 631: * Fill raw output buffer. ! 632: */ ! 633: while ((--n >= 0) && ((b = ttout(tp)) >= 0)) { ! 634: tp->t_rawout.si_buf[ tp->t_rawout.si_ix ] = b; ! 635: if (tp->t_rawout.si_ix >= sizeof(tp->t_rawout.si_buf) - 1) ! 636: tp->t_rawout.si_ix = 0; ! 637: else ! 638: tp->t_rawout.si_ix++; ! 639: } ! 640: ! 641: /* ! 642: * (Re)start output, wake sleeping processes, etc. ! 643: */ ! 644: ttstart(tp); ! 645: ! 646: /* ! 647: * Schedule next cycle. ! 648: */ ! 649: timeout(&tp->t_rawtim, HZ/10, alxcycle, tp); ! 650: } ! 651: ! 652: /* ! 653: * Serial Transmit Start Routine. ! 654: */ ! 655: alxstart(tp) ! 656: register TTY * tp; ! 657: { ! 658: register int b; ! 659: register int s; ! 660: extern alxbreak(); ! 661: ! 662: /* ! 663: * Read line status register AFTER disabling interrupts. ! 664: */ ! 665: s = sphi(); ! 666: b = inb(ALPORT+LSR); ! 667: ! 668: /* ! 669: * Process break indication. ! 670: * NOTE: Break indication cleared when line status register was read. ! 671: */ ! 672: if (b & LS_BREAK) ! 673: defer(alxbreak, tp); ! 674: ! 675: /* ! 676: * Transmitter is empty, output data is pending. ! 677: */ ! 678: if ((b & LS_TxRDY) && (tp->t_rawout.si_ix != tp->t_rawout.si_ox)) { ! 679: outb( ALPORT+DREG, ! 680: tp->t_rawout.si_buf[ tp->t_rawout.si_ox ]); ! 681: if (++tp->t_rawout.si_ox >= sizeof(tp->t_rawout.si_buf)) ! 682: tp->t_rawout.si_ox = 0; ! 683: } ! 684: spl(s); ! 685: } ! 686: ! 687: /* ! 688: * Serial Received Break Handler. ! 689: */ ! 690: alxbreak(tp) ! 691: TTY * tp; ! 692: { ! 693: ttsignal(tp, SIGINT); ! 694: } ! 695: ! 696: /* ! 697: * Serial Interrupt Handler. ! 698: */ ! 699: alxintr(tp) ! 700: register TTY * tp; ! 701: { ! 702: register int b; ! 703: int port = ALPORT; ! 704: unsigned char mcr; ! 705: ! 706: rescan: ! 707: switch (inb(port+IIR)) { ! 708: ! 709: case LS_INTR: ! 710: if (inb(port+LSR) & LS_BREAK) ! 711: defer(alxbreak, tp); ! 712: goto rescan; ! 713: ! 714: case Rx_INTR: ! 715: b = inb(port+DREG); ! 716: if (tp->t_open == 0) ! 717: goto rescan; ! 718: /* ! 719: * Must recognize XOFF quickly to avoid transmit overrun. ! 720: * Recognize XON here as well to avoid race conditions. ! 721: */ ! 722: if ((tp->t_sgttyb.sg_flags & RAWIN) == 0) { ! 723: /* ! 724: * XOFF. ! 725: */ ! 726: if (tp->t_tchars.t_stopc == (b & 0177)) { ! 727: tp->t_flags |= T_STOP; ! 728: goto rescan; ! 729: } ! 730: ! 731: /* ! 732: * XON. ! 733: */ ! 734: if (tp->t_tchars.t_startc == (b & 0177)) { ! 735: tp->t_flags &= ~T_STOP; ! 736: goto rescan; ! 737: } ! 738: } ! 739: ! 740: /* ! 741: * Save char in raw input buffer. ! 742: */ ! 743: if (tp->t_rawin.SILO_CHAR_COUNT < MAX_SILO_CHARS) { ! 744: tp->t_rawin.si_buf[tp->t_rawin.si_ix] = b; ! 745: if (tp->t_rawin.si_ix < MAX_SILO_INDEX) ! 746: tp->t_rawin.si_ix++; ! 747: else ! 748: tp->t_rawin.si_ix = 0; ! 749: tp->t_rawin.SILO_CHAR_COUNT++; ! 750: } ! 751: if (tp->t_flags & T_MODC) ! 752: if ((tp->t_flags & T_ISTOP) ! 753: || (tp->t_rawin.SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 754: mcr = inb(port+MCR); ! 755: if (mcr & MC_RTS) { ! 756: outb(port+MCR, mcr & ~MC_RTS); ! 757: printf("%x RTS OFF\n", port); ! 758: } ! 759: } ! 760: goto rescan; ! 761: ! 762: case Tx_INTR: ! 763: /* ! 764: * Do nothing if no raw output data or output is stopped. ! 765: */ ! 766: if (tp->t_rawout.si_ix == tp->t_rawout.si_ox) { ! 767: goto rescan; ! 768: } ! 769: if (tp->t_flags & T_STOP) ! 770: goto rescan; ! 771: ! 772: /* ! 773: * Transmit next char in raw output buffer. ! 774: */ ! 775: outb(port+DREG, ! 776: tp->t_rawout.si_buf[ tp->t_rawout.si_ox ]); ! 777: ! 778: /* ! 779: * Adjust raw output buffer output index. ! 780: */ ! 781: if (++tp->t_rawout.si_ox >= sizeof(tp->t_rawout.si_buf)) ! 782: tp->t_rawout.si_ox = 0; ! 783: ! 784: /* ! 785: * Try to fill buffer if now empty. ! 786: */ ! 787: if (tp->t_rawout.si_ox == tp->t_rawout.si_ix) { ! 788: defer(alxcycle, tp); ! 789: } ! 790: goto rescan; ! 791: ! 792: case MS_INTR: ! 793: AL_MSR_DELTAS |= inb(port+MSR); ! 794: defer(alxcycle, tp); ! 795: goto rescan; ! 796: } ! 797: } ! 798: ! 799: /* ! 800: * alxclk will be called every time T0 interrupts - if it returns 0, ! 801: * the usual system timer interrupt stuff is done ! 802: */ ! 803: static int alxclk() ! 804: { ! 805: static int count; ! 806: int i; ! 807: ! 808: for (i = 0; i < NUM_AL_PORTS; i++) ! 809: if (com_usage[i] == COM_POLLED) ! 810: alxintr(tp_table[i]); ! 811: count++; ! 812: if (count >= poll_divisor) ! 813: count = 0; ! 814: return count; ! 815: } ! 816: ! 817: /* ! 818: * set_poll_rate is called when a port is opened or closed or changes speed ! 819: * it sets the polling rate only as fast as needed, and shuts off polling ! 820: * whenever possible ! 821: */ ! 822: static set_poll_rate() ! 823: { ! 824: int port_num, max_rate, port_rate; ! 825: ! 826: /* ! 827: * If another driver has the polling clock, do nothing. ! 828: */ ! 829: if (poll_owner & ~ POLL_AL) ! 830: return; ! 831: ! 832: /* ! 833: * find highest valid polling rate in units of HZ/10 ! 834: */ ! 835: max_rate = 0; ! 836: for (port_num = 0; port_num < NUM_AL_PORTS; port_num++) { ! 837: if (com_usage[port_num] == COM_POLLED) { ! 838: port_rate = alp_rate[(tp_table[port_num])->t_sgttyb.sg_ispeed]; ! 839: if (max_rate < port_rate) ! 840: max_rate = port_rate; ! 841: } ! 842: } ! 843: /* ! 844: * if max_rate is not current rate, adjust the system clock ! 845: */ ! 846: if (max_rate != poll_rate) { ! 847: poll_rate = max_rate; ! 848: poll_divisor = poll_rate/HZ; /* used in alxclk() */ ! 849: altclk_out(); /* stop previous polling */ ! 850: poll_owner &= ~ POLL_AL; ! 851: if (max_rate) { /* resume polling at new rate if needed */ ! 852: poll_owner |= POLL_AL; ! 853: altclk_in(poll_rate, alxclk); ! 854: } ! 855: CDUMP("new rate") ! 856: } ! 857: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.