|
|
1.1 ! root 1: /* ! 2: * File: asy.c ! 3: * ! 4: * Purpose: 8250-family async port device driver ! 5: * ! 6: * Devices are named /dev/asy[00..31]{fpl} ! 7: * Minor number bit assignments: ! 8: * x... .... 1 for NO modem control, "l" ! 9: * .x.. .... 1 for polled operation (no irq service), "p" ! 10: * ..x. .... 1 for RTS/CTS flow control, "f" ! 11: * ...x xxxx channel number - 0..31 ! 12: */ ! 13: ! 14: /* ! 15: * ----------------------------------------------------------------- ! 16: * Includes. ! 17: */ ! 18: #include <sys/coherent.h> ! 19: #include <sys/stat.h> ! 20: #include <sys/proc.h> ! 21: #include <sys/tty.h> ! 22: #include <sys/con.h> ! 23: #include <sys/devices.h> ! 24: #include <errno.h> ! 25: #include <poll.h> ! 26: #include <sys/sched.h> /* CVTTOUT, IVTTOUT, SVTTOUT */ ! 27: #include <sys/asy.h> ! 28: #include <sys/ins8250.h> ! 29: #include <sys/poll_clk.h> ! 30: #ifdef _I386 ! 31: #include <termio.h> ! 32: #endif ! 33: ! 34: /* ! 35: * ----------------------------------------------------------------- ! 36: * Definitions. ! 37: * Constants. ! 38: * Macros with argument lists. ! 39: * Typedefs. ! 40: * Enums. ! 41: */ ! 42: #define IEN_USE_MSI (IE_RxI | IE_TxI | IE_LSI | IE_MSI) ! 43: #define IEN_NO_MSI (IE_RxI | IE_TxI | IE_LSI) ! 44: ! 45: #define CTLQ 0021 ! 46: #define CTLS 0023 ! 47: ! 48: #define NUM_IRQ 16 /* PC allows irq numbers 0..15 */ ! 49: #define BPB 8 /* 8 bits per byte */ ! 50: #define DTRTMOUT 3 /* DTR seconds for close */ ! 51: #define LOOP_LIMIT 100 /* safety valve on irq loops */ ! 52: ! 53: /* ! 54: * For rawin silo (see poll_clk.h), use last element of si_buf to count ! 55: * the number of characters in the silo. ! 56: */ ! 57: #define SILO_CHAR_COUNT si_buf[SI_BUFSIZ-1] ! 58: #define SILO_HIGH_MARK (SI_BUFSIZ-SI_BUFSIZ/4) ! 59: #define SILO_LOW_MARK (SI_BUFSIZ/4) ! 60: #define MAX_SILO_INDEX (SI_BUFSIZ-2) ! 61: #define MAX_SILO_CHARS (SI_BUFSIZ-1) ! 62: ! 63: #define RAWIN_FLUSH(in_silo) { \ ! 64: in_silo->si_ox = in_silo->si_ix; \ ! 65: in_silo->SILO_CHAR_COUNT = 0; } ! 66: #define RAWOUT_FLUSH(out_silo) { out_silo->si_ox = out_silo->si_ix; } ! 67: #define channel(dev) (dev & 0x1F) ! 68: ! 69: #define IEN ((a0->a_nms)?IEN_NO_MSI:IEN_USE_MSI) ! 70: #ifdef _I386 ! 71: #define EEBUSY EBUSY ! 72: #else ! 73: #define EEBUSY EDBUSY ! 74: #endif ! 75: ! 76: #define NW_OUTSILO 1 /* bits in need_wake[] entries */ ! 77: ! 78: typedef void (* VPTR)(); /* pointer to function returning void */ ! 79: typedef void (* FPTR)(); /* pointer to function returning int */ ! 80: ! 81: /* ! 82: * ----------------------------------------------------------------- ! 83: * Functions. ! 84: * Import Functions. ! 85: * Export Functions. ! 86: * Local Functions. ! 87: */ ! 88: int nulldev(); ! 89: ! 90: void asy_putchar(); ! 91: ! 92: /* ! 93: * Configuration functions (local). ! 94: */ ! 95: static void asyclose(); ! 96: static void asyioctl(); ! 97: static void asyload(); ! 98: static void asyopen(); ! 99: static void asyread(); ! 100: static void asytimer(); ! 101: static void asyunload(); ! 102: static void asywrite(); ! 103: static int asypoll(); ! 104: static void cinit(); ! 105: ! 106: /* ! 107: * Support functions (local). ! 108: */ ! 109: static void add_irq(); ! 110: static void asy_irq(); ! 111: static int asy_send(); ! 112: static void asybreak(); ! 113: static void asyclock(); ! 114: static void asycycle(); ! 115: static void asydump(); ! 116: static int asyintr(); ! 117: static void asyparam(); ! 118: static void asysph(); ! 119: static void asyspr(); ! 120: static void asystart(); ! 121: static void endbrk(); ! 122: static void irqdummy(); ! 123: static void upd_irq1(); ! 124: ! 125: static void i2(),i3(),i4(),i5(),i6(),i7(),i8(),i9(); ! 126: static void i10(),i11(),i12(),i13(),i14(),i15(); ! 127: static int p1(),p2(),p3(),p4(); ! 128: ! 129: /* ! 130: * ----------------------------------------------------------------- ! 131: * Global Data. ! 132: * Import Variables. ! 133: * Export Variables. ! 134: * Local Variables. ! 135: */ ! 136: extern int albaud[], alp_rate[]; ! 137: ! 138: /* ! 139: * When asypatch runs, it checks whether its internal value for ! 140: * ASY_VERSION matches this driver's value, so as to prevent the patch ! 141: * utility and the driver from getting out of phase. ! 142: */ ! 143: int ASY_VER = ASY_VERSION; ! 144: int ASY_HPCL = 1; ! 145: int ASY_NUM = 0; ! 146: int ASYGP_NUM = 0; ! 147: asy0_t asy0[MAX_ASY] = { ! 148: { 0 } ! 149: }; ! 150: asy_gp_t asy_gp[MAX_ASYGP] = { ! 151: { 0 } ! 152: }; ! 153: ! 154: static asy1_t * asy1; /* unused entries have type US_NONE */ ! 155: static short dummy_port; /* used only during driver startup */ ! 156: static int poll_divisor; /* set by asyspr(), read by asyclk() */ ! 157: static char pptbl[MAX_ASY]; /* channel numbers of polled ports */ ! 158: static int ppnum; /* number of channels in pptbl */ ! 159: ! 160: /* ! 161: * itbl keeps function pointers for irq service routines, for ease of setting ! 162: * and clearing vectors. ! 163: * ! 164: * irq0[x] and irq1[x] are lists for irq number x. ! 165: * irq0 has nodes that may possibly cause an irq. ! 166: * irq1 contains nodes for active devices. ! 167: * Whenever a device becomes active or inactive, irq1 is rebuilt from irq0. ! 168: * ! 169: * nodespace is an array of available nodes used in making the lists. ! 170: * nextnode points to the next free node. ! 171: * Nodes are taken from nodespace only during driver load. ! 172: */ ! 173: static VPTR itbl[NUM_IRQ] = { ! 174: 0,0,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15 }; ! 175: static FPTR ptbl[PT_MAX] = { asyintr,p1,p2,p3,p4 }; ! 176: static struct irqnode *irq0[NUM_IRQ], *irq1[NUM_IRQ]; ! 177: static struct irqnode nodespace[MAX_ASY]; ! 178: static char need_wake[MAX_ASY]; ! 179: static char nextnode; ! 180: static int initialized; /* for asy_putchar() */ ! 181: ! 182: /* ! 183: * Configuration table (export data). ! 184: */ ! 185: CON asycon ={ ! 186: DFCHR|DFPOL, /* Flags */ ! 187: ASY_MAJOR, /* Major index */ ! 188: asyopen, /* Open */ ! 189: asyclose, /* Close */ ! 190: nulldev, /* Block */ ! 191: asyread, /* Read */ ! 192: asywrite, /* Write */ ! 193: asyioctl, /* Ioctl */ ! 194: nulldev, /* Powerfail */ ! 195: asytimer, /* Timeout */ ! 196: asyload, /* Load */ ! 197: asyunload, /* Unload */ ! 198: asypoll /* Poll */ ! 199: }; ! 200: ! 201: /* ! 202: * ----------------------------------------------------------------- ! 203: * Code. ! 204: */ ! 205: ! 206: /* ! 207: * asyload() ! 208: */ ! 209: static void ! 210: asyload() ! 211: { ! 212: int s, chan; ! 213: asy0_t *a0; ! 214: asy1_t *a1; ! 215: TTY *tp; ! 216: short port; ! 217: char irq; ! 218: char speed; ! 219: char g; ! 220: char sense_ct = 0; ! 221: ! 222: /* ! 223: * Allocate space for asy structs. Possible error return. ! 224: */ ! 225: asy1 = (asy1_t *)kalloc(ASY_NUM * sizeof(asy1_t)); ! 226: if (asy1 == 0) { ! 227: printf("asyload: can't allocate space for %d async devices\n", ! 228: ASY_NUM); ! 229: return; ! 230: } ! 231: kclear(asy1, ASY_NUM*sizeof(asy1_t)); ! 232: ! 233: /* ! 234: * For each non-null port: ! 235: * if port is uses irq ! 236: * set dummy routine in case uart_sense causes bogus irpts ! 237: * sense chip type ! 238: * write baud rate to sgtty/termio structs ! 239: * disable port interrupts ! 240: * hang up port ! 241: * set default baud rate (also resets UART) ! 242: * hook "start" function into line discipline module ! 243: * hook "param" function into line discipline module ! 244: * hook CS into line discipline module ! 245: * if port is uses irq ! 246: * release dummy routine ! 247: * if not in a port group ! 248: * add to irq list ! 249: */ ! 250: for (chan = 0; chan < ASY_NUM; chan++) { ! 251: a0 = asy0 + chan; ! 252: a1 = asy1 + chan; ! 253: tp = &a1->a_tty; ! 254: speed = a0->a_speed; ! 255: tp->t_sgttyb.sg_ispeed = tp->t_sgttyb.sg_ospeed = speed; ! 256: tp->t_dispeed = tp->t_dospeed = speed; ! 257: port = a0->a_port; ! 258: ! 259: /* ! 260: * A port address of zero means a skipped entry in the table. ! 261: * In this case a1->a_ut keeps its initial value of US_NONE. ! 262: */ ! 263: if (port) { ! 264: dummy_port = port; ! 265: if (a0->a_irqno) ! 266: setivec(a0->a_irqno, irqdummy); ! 267: /* ! 268: * uart_sense() prints port info. ! 269: * Do this four times per line. ! 270: */ ! 271: a1->a_ut = uart_sense(port); ! 272: sense_ct++; ! 273: if ((sense_ct & 1) == 0) ! 274: putchar('\n'); ! 275: else ! 276: putchar('\t'); ! 277: s = sphi(); ! 278: outb(port+MCR, 0); ! 279: outb(port+LCR, LC_DLAB); ! 280: outb(port+DLL, albaud[speed]); ! 281: outb(port+DLH, albaud[speed] >> 8); ! 282: outb(port+LCR, LC_CS8); ! 283: tp->t_start = asystart; ! 284: /* leave tp->t_param at 0 */ ! 285: tp->t_cs_sel = cs_sel(); ! 286: tp->t_ddp = (int *)chan; ! 287: spl(s); ! 288: if (a0->a_irqno) { ! 289: clrivec(a0->a_irqno); ! 290: if (a0->a_asy_gp == NO_ASYGP) ! 291: add_irq(a0->a_irqno, asyintr, chan); ! 292: } ! 293: } ! 294: } ! 295: if (sense_ct & 1) ! 296: putchar('\n'); ! 297: ! 298: /* ! 299: * for each port group ! 300: * add group to irq list ! 301: */ ! 302: for (g = 0; g < ASYGP_NUM; g++) { ! 303: add_irq(asy_gp[g].irq, ptbl[asy_gp[g].gp_type], g); ! 304: } ! 305: ! 306: /* ! 307: * Attach irq routines. ! 308: */ ! 309: for (irq = 0; irq < NUM_IRQ; irq++) ! 310: if (irq0[irq]) { ! 311: setivec(irq, itbl[irq]); ! 312: } ! 313: } ! 314: ! 315: /* ! 316: * asyunload() ! 317: */ ! 318: static void ! 319: asyunload() ! 320: { ! 321: char chan, irq; ! 322: ! 323: /* ! 324: * for each channel ! 325: * disable UART interrupts ! 326: * hangup port ! 327: * cancel timer ! 328: */ ! 329: for (chan = 0; chan < ASY_NUM; chan++) { ! 330: asy0_t * a0 = asy0 + chan; ! 331: asy1_t * a1 = asy1 + chan; ! 332: short port = a0->a_port; ! 333: TTY *tp = &a1->a_tty; ! 334: ! 335: outb(port+IER, 0); ! 336: outb(port+MCR, 0); ! 337: timeout(tp->t_rawtim, 0, NULL, 0); ! 338: } ! 339: ! 340: /* ! 341: * for each irq ! 342: * if irq routine was attached ! 343: * detach it ! 344: */ ! 345: for (irq = 0; irq < NUM_IRQ; irq++) ! 346: if (irq0[irq]) ! 347: clrivec(irq); ! 348: ! 349: /* ! 350: * Deallocate dynamic asy storage. ! 351: */ ! 352: if (asy1) ! 353: kfree(asy1); ! 354: } ! 355: ! 356: /* ! 357: * asyopen() ! 358: */ ! 359: static void ! 360: asyopen(dev, mode) ! 361: dev_t dev; ! 362: int mode; ! 363: { ! 364: int s; ! 365: char msr, mcr; ! 366: char chan = channel(dev); ! 367: asy0_t *a0 = asy0 + chan; ! 368: asy1_t *a1 = asy1 + chan; ! 369: TTY *tp = &a1->a_tty; ! 370: short port = a0->a_port; ! 371: ! 372: if (a1->a_ut == US_NONE) { /* chip not found */ ! 373: T_HAL(4, devmsg(dev, "no UART")); ! 374: u.u_error = ENXIO; ! 375: goto bad_open; ! 376: } ! 377: ! 378: if ((tp->t_flags & T_EXCL) && !super()) { ! 379: T_HAL(4, devmsg(dev, "exclusive use")); ! 380: u.u_error = ENODEV; ! 381: goto bad_open; ! 382: } ! 383: ! 384: #if 0 ! 385: if (drvl[major(dev)].d_time != 0) { /* Modem settling */ ! 386: T_HAL(4, devmsg(dev, "modem settling")); ! 387: u.u_error = EEBUSY; ! 388: goto bad_open; ! 389: } ! 390: #endif ! 391: ! 392: /* ! 393: * Can't open for hardware flow control if modem status ! 394: * interrupts are disallowed. ! 395: */ ! 396: if (a0->a_nms && (dev & CFLOW)) { ! 397: T_HAL(4, devmsg(dev, "no modem status irq's")); ! 398: u.u_error = ENXIO; ! 399: goto bad_open; ! 400: } ! 401: ! 402: /* ! 403: * Can't open a polled port if another driver is using polling. ! 404: */ ! 405: if (dev & CPOLL && poll_owner & ~ POLL_ASY) { ! 406: T_HAL(4, devmsg(dev, "polling unavailable")); ! 407: u.u_error = EEBUSY; ! 408: goto bad_open; ! 409: } ! 410: ! 411: /* ! 412: * Can't have both com[13] or both com[24] IRQ at once. ! 413: */ ! 414: if (!(dev & CPOLL) && a0->a_ixc) { ! 415: struct irqnode *np = irq1[a0->a_irqno]; ! 416: while (np) { ! 417: if (np->func != ptbl[0] || np->arg != chan) { ! 418: T_HAL(4, devmsg(dev, "irq conflict")); ! 419: u.u_error = EEBUSY; ! 420: goto bad_open; ! 421: } ! 422: np = np->next_actv; ! 423: } ! 424: } ! 425: ! 426: /* ! 427: * If port already in use, are new and old open modes compatible? ! 428: */ ! 429: if (a1->a_in_use) { ! 430: int oldmode = 0, newmode = 0; /* mctl:1 irq:2 flow:4 */ ! 431: ! 432: if (a1->a_modc) ! 433: oldmode += 1; ! 434: if (a1->a_irq) ! 435: oldmode += 2; ! 436: if (a1->a_flc) ! 437: oldmode += 4; ! 438: if ((dev & NMODC) == 0) ! 439: newmode += 1; ! 440: if ((dev & CPOLL) == 0) ! 441: newmode += 2; ! 442: if (dev & CFLOW) ! 443: newmode += 4; ! 444: if (oldmode != newmode) { ! 445: T_HAL(4, devmsg(dev, "conflicting open modes")); ! 446: u.u_error = EEBUSY; ! 447: goto bad_open; ! 448: } ! 449: } ! 450: ! 451: /* ! 452: * Sleep here if another process is opening or closing the port. ! 453: * This can happen if: ! 454: * another process is trying a first open and awaiting CD; ! 455: * another process is closing the port after losing CD; ! 456: * a remote process opened the port, spawned a daemon, ! 457: * and disconnected, and the daemon ignored SIGHUP and is ! 458: * improperly keeping the port open. ! 459: * Don't try to set tp->t_flags before this sleep! During ! 460: * the sleep, ttclose() may be called and clear the flags. ! 461: */ ! 462: while (a1->a_in_use && (a1->a_hcls || ! 463: ((dev & NMODC) == 0 && (inb(port+MSR) & MS_RLSD) == 0))) { ! 464: #ifdef _I386 ! 465: x_sleep((char *)(&tp->t_open), pritty, slpriSigCatch, "asyblk"); ! 466: #else ! 467: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, SVTTOUT, ! 468: "asyblk"); ! 469: #endif ! 470: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 471: u.u_error = EINTR; ! 472: goto bad_open; ! 473: } ! 474: } ! 475: ! 476: /* ! 477: * If channel not in use, mark it as such. ! 478: */ ! 479: if (a1->a_in_use == 0) { ! 480: /* ! 481: * Save modes for this open attempt to avoid future conflicts. ! 482: * Then start asycycle() for this port. ! 483: */ ! 484: if (dev & NMODC) { ! 485: tp->t_flags &= ~T_MODC; ! 486: a1->a_modc = 0; ! 487: } else { ! 488: tp->t_flags |= T_MODC; ! 489: a1->a_modc = 1; ! 490: } ! 491: if (dev & CPOLL) ! 492: a1->a_irq = 0; ! 493: else ! 494: a1->a_irq = 1; ! 495: if (dev & CFLOW) { ! 496: tp->t_flags |= T_CFLOW; ! 497: a1->a_flc = 1; ! 498: } else { ! 499: tp->t_flags &= ~T_CFLOW; ! 500: a1->a_flc = 0; ! 501: } ! 502: } ! 503: a1->a_in_use++; ! 504: ! 505: /* ! 506: * From here, error exit is bad_open_u. ! 507: */ ! 508: ! 509: if (tp->t_open == 0) { /* not already open */ ! 510: silo_t * in_silo = &a1->a_in; ! 511: ! 512: if (!(dev & CPOLL)) { ! 513: upd_irq1(a0->a_irqno); ! 514: a1->a_has_irq = 1; ! 515: } ! 516: ! 517: /* ! 518: * Need to start cycling to scan for CD. ! 519: */ ! 520: asycycle(chan); ! 521: ! 522: s = sphi(); ! 523: /* ! 524: * Raise basic modem control lines even if modem ! 525: * control hasn't been specified. ! 526: * MC_OUT2 turns on NON-open-collector IRQ line from the UART. ! 527: * since we can't have two UART's on same IRQ with MC_OUT2 on ! 528: */ ! 529: mcr = MC_RTS | MC_DTR; ! 530: if (dev & CPOLL) { ! 531: outb(port+MCR, mcr); ! 532: } else { ! 533: outb(port+MCR, mcr | a0->a_outs); ! 534: outb(port+IER, IEN); ! 535: } ! 536: ! 537: if ((dev & NMODC) == 0) { /* want modem control? */ ! 538: tp->t_flags |= T_HOPEN | T_STOP; ! 539: for (;;) { /* wait for carrier */ ! 540: msr = inb(port+MSR); ! 541: /* ! 542: * If carrier detect present ! 543: * if port not already open ! 544: * break out of loop and finish first open ! 545: * else ! 546: * do second (or third, etc.) open ! 547: */ ! 548: if (msr & MS_RLSD) ! 549: break; ! 550: /* wait for carrier */ ! 551: #ifdef _I386 ! 552: x_sleep((char *)(&tp->t_open), pritty, ! 553: slpriSigCatch, "need CD"); ! 554: #else ! 555: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, ! 556: SVTTOUT, "need CD"); ! 557: #endif ! 558: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 559: outb(port+MCR, 0); ! 560: outb(port+IER, 0); ! 561: u.u_error = EINTR; ! 562: tp->t_flags &= ~(T_HOPEN | T_STOP); ! 563: spl(s); ! 564: goto bad_open_u; ! 565: } ! 566: } ! 567: ! 568: /* ! 569: * Mark that we are no longer hanging in open. ! 570: * Allow output over the port unless hardware flow ! 571: * control says not to. ! 572: */ ! 573: tp->t_flags &= ~T_HOPEN; ! 574: tp->t_flags &= ~T_STOP; ! 575: if (!(tp->t_flags & T_CFLOW) || (msr & MS_CTS)) ! 576: a1->a_ohlt = 0; ! 577: else ! 578: a1->a_ohlt = 1; ! 579: ! 580: /* ! 581: * Awaken any other opens on same device. ! 582: */ ! 583: wakeup((char *)(&tp->t_open)); ! 584: } ! 585: ttopen(tp); /* stty inits */ ! 586: tp->t_flags |= T_CARR; ! 587: if (ASY_HPCL) ! 588: tp->t_flags |= T_HPCL; ! 589: ! 590: asyparam(tp); /* gimmick: do this while t_open is zero */ ! 591: ! 592: /* ! 593: * TO DO: flush UART input register(s). ! 594: */ ! 595: ! 596: spl(s); ! 597: ! 598: /* ! 599: * Turn on polling for the port. ! 600: */ ! 601: if (dev & CPOLL) { ! 602: a1->a_poll = 1; ! 603: asyspr(); ! 604: } ! 605: } /* end of first-open case */ ! 606: ! 607: tp->t_open++; ! 608: T_HAL(0x400, printf("ch%d open + %d\n", chan, tp->t_open)); ! 609: ttsetgrp(tp, dev, mode); ! 610: ! 611: return; ! 612: ! 613: bad_open_u: ! 614: a1->a_in_use--; ! 615: wakeup((char *)(&tp->t_open)); ! 616: bad_open: ! 617: return; ! 618: } ! 619: ! 620: /* ! 621: * asyclose() ! 622: */ ! 623: static void ! 624: asyclose(dev, mode) ! 625: dev_t dev; ! 626: int mode; ! 627: { ! 628: int chan = channel(dev); ! 629: asy0_t *a0 = asy0 + chan; ! 630: asy1_t *a1 = asy1 + chan; ! 631: TTY *tp = &a1->a_tty; ! 632: silo_t * out_silo = &a1->a_out; ! 633: silo_t * in_silo = &a1->a_in; ! 634: int flags, maj; ! 635: int s; ! 636: short port = a0->a_port; ! 637: char lsr; ! 638: ! 639: if (--tp->t_open) ! 640: goto not_last_close; ! 641: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open)); ! 642: s = sphi(); ! 643: ! 644: a1->a_hcls = 1; /* disallow reopen til done closing */ ! 645: flags = tp->t_flags; /* save flags - ttclose zeroes them */ ! 646: ttclose(tp); ! 647: ! 648: /* ! 649: * Wait for output silo and UART xmit buffer to empty. ! 650: * Allow signal to break the sleep. ! 651: */ ! 652: for (;;) { ! 653: int chipEmpty = 0, siloEmpty = 0; ! 654: ! 655: lsr = inb(port + LSR); ! 656: chipEmpty = (lsr & LS_TxIDLE); ! 657: T_HAL(0x400, printf("ch%d chipEmpty=%d\n", chan, chipEmpty)); ! 658: siloEmpty = (out_silo->si_ix == out_silo->si_ox); ! 659: T_HAL(0x400, printf("ch%d siloEmpty=%d\n", chan, siloEmpty)); ! 660: ! 661: if (chipEmpty && siloEmpty) ! 662: break; ! 663: need_wake[chan] |= NW_OUTSILO; ! 664: #ifdef _I386 ! 665: x_sleep((char *)out_silo, pritty, slpriSigCatch, "asyclose"); ! 666: #else ! 667: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT, ! 668: "asyclose"); ! 669: #endif ! 670: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 671: RAWOUT_FLUSH(out_silo); ! 672: break; ! 673: } ! 674: } ! 675: need_wake[chan] &= ~NW_OUTSILO; ! 676: ! 677: /* ! 678: * If not hanging in open ! 679: */ ! 680: if ((flags & T_HOPEN) == 0) { ! 681: /* ! 682: * Disable interrupts. ! 683: */ ! 684: outb(port+IER, 0); ! 685: outb(port+MCR, inb(port+MCR) & ~MC_OUTS); ! 686: } ! 687: ! 688: /* ! 689: * If hupcls ! 690: */ ! 691: if (flags & T_HPCL) { ! 692: T_HAL(0x400, printf("ch%d drop DTR\n", chan)); ! 693: /* ! 694: * Hangup port - drop DTR and RTS. ! 695: */ ! 696: outb(port+MCR, inb(port+MCR) & MC_OUTS); ! 697: ! 698: /* ! 699: * Hold dtr low for timeout ! 700: */ ! 701: maj = major(dev); ! 702: drvl[maj].d_time = 1; ! 703: #ifdef _I386 ! 704: x_sleep((char *)&drvl[maj].d_time, pritty, slpriNoSig, ! 705: "drop DTR"); ! 706: #else ! 707: v_sleep((char *)&drvl[maj].d_time, CVTTOUT, IVTTOUT, SVTTOUT, ! 708: "drop DTR"); ! 709: #endif ! 710: drvl[maj].d_time = 0; ! 711: } ! 712: ! 713: a1->a_poll = 0; ! 714: asyspr(); ! 715: RAWIN_FLUSH(in_silo); ! 716: a1->a_hcls = 0; /* allow reopen - done closing */ ! 717: wakeup((char *)(&tp->t_open)); ! 718: spl(s); ! 719: a1->a_in_use--; ! 720: ! 721: if (!(dev & CPOLL)) ! 722: upd_irq1(a0->a_irqno); ! 723: return; ! 724: ! 725: not_last_close: ! 726: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open)); ! 727: a1->a_in_use--; ! 728: wakeup((char *)(&tp->t_open)); ! 729: return; ! 730: } ! 731: ! 732: /* ! 733: * asyread() ! 734: */ ! 735: static void ! 736: asyread(dev, iop) ! 737: dev_t dev; ! 738: register IO * iop; ! 739: { ! 740: int chan = channel(dev); ! 741: asy1_t *a1 = asy1 + chan; ! 742: TTY *tp = &a1->a_tty; ! 743: ! 744: ttread(tp, iop); ! 745: } ! 746: ! 747: /* ! 748: * asytimer() ! 749: */ ! 750: static void ! 751: asytimer(dev) ! 752: dev_t dev; ! 753: { ! 754: if (++drvl[major(dev)].d_time > DTRTMOUT) ! 755: wakeup((char *)&drvl[major(dev)].d_time); ! 756: } ! 757: ! 758: /* ! 759: * asywrite() ! 760: */ ! 761: static void ! 762: asywrite(dev, iop) ! 763: dev_t dev; ! 764: register IO * iop; ! 765: { ! 766: int chan = channel(dev); ! 767: asy0_t *a0 = asy0 + chan; ! 768: asy1_t *a1 = asy1 + chan; ! 769: TTY *tp = &a1->a_tty; ! 770: short port = a0->a_port; ! 771: register int c; ! 772: ! 773: /* ! 774: * Treat user writes through tty driver. ! 775: */ ! 776: if (iop->io_seg != IOSYS) { ! 777: ttwrite(tp, iop); ! 778: return; ! 779: } ! 780: ! 781: /* ! 782: * Treat kernel writes by blocking on transmit buffer. ! 783: */ ! 784: while ((c = iogetc(iop)) >= 0) { ! 785: /* ! 786: * Wait until transmit buffer is empty. ! 787: * Check twice to prevent critical race with interrupt handler. ! 788: */ ! 789: for (;;) { ! 790: if (inb(port+LSR) & LS_TxRDY) ! 791: if (inb(port+LSR) & LS_TxRDY) ! 792: break; ! 793: } ! 794: ! 795: /* ! 796: * Output the next character. ! 797: */ ! 798: outb(port+DREG, c); ! 799: } ! 800: } ! 801: ! 802: /* ! 803: * asyioctl() ! 804: */ ! 805: static void ! 806: asyioctl(dev, com, vec) ! 807: dev_t dev; ! 808: int com; struct sgttyb *vec; ! 809: { ! 810: int chan = channel(dev); ! 811: asy0_t *a0 = asy0 + chan; ! 812: asy1_t *a1 = asy1 + chan; ! 813: TTY *tp = &a1->a_tty; ! 814: int s; ! 815: int temp; ! 816: silo_t *out_silo = &a1->a_out; ! 817: silo_t *in_silo = &a1->a_in; ! 818: short port = a0->a_port; ! 819: unsigned char msr, mcr, lcr, ier; ! 820: char do_ttioctl = 0; ! 821: char do_asyparam = 0; ! 822: ! 823: s = sphi(); ! 824: ier = inb(port+IER); ! 825: mcr = inb(port+MCR); /* get current MCR register status */ ! 826: lcr = inb(port+LCR); /* get current LCR register status */ ! 827: ! 828: #ifdef _I386 ! 829: /* ! 830: * If command will drain output, do the drain now ! 831: * before calling ttioctl(). ! 832: * Don't do this for 286 kernel: we're running out of code space. ! 833: */ ! 834: switch(com) { ! 835: case TCSETAW: ! 836: case TCSETAF: ! 837: case TCSBRK: ! 838: case TIOCSETP: ! 839: /* ! 840: * Wait for output silo and UART xmit buffer to empty. ! 841: * Allow signal to break the sleep. ! 842: */ ! 843: for (;;) { ! 844: if (!ttoutp(tp) ! 845: && (out_silo->si_ix == out_silo->si_ox) ! 846: && (inb(port + LSR) & LS_TxIDLE)) ! 847: break; ! 848: need_wake[chan] |= NW_OUTSILO; ! 849: #ifdef _I386 ! 850: x_sleep((char *)out_silo, pritty, slpriSigCatch, ! 851: "asydrain"); ! 852: #else ! 853: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT, ! 854: "asydrain"); ! 855: #endif ! 856: if (SELF->p_ssig && nondsig()) { /* signal? */ ! 857: break; ! 858: } ! 859: } ! 860: need_wake[chan] &= ~NW_OUTSILO; ! 861: } ! 862: #endif ! 863: ! 864: switch(com) { ! 865: case TIOCSBRK: /* set BREAK */ ! 866: outb(port+LCR, lcr|LC_SBRK); ! 867: break; ! 868: case TIOCCBRK: /* clear BREAK */ ! 869: outb(port+LCR, lcr & ~LC_SBRK); ! 870: break; ! 871: case TIOCSDTR: /* set DTR */ ! 872: outb(port+MCR, mcr|MC_DTR); ! 873: break; ! 874: case TIOCCDTR: /* clear DTR */ ! 875: outb(port+MCR, mcr & ~MC_DTR); ! 876: break; ! 877: case TIOCSRTS: /* set RTS */ ! 878: outb(port+MCR, mcr|MC_RTS); ! 879: break; ! 880: case TIOCCRTS: /* clear RTS */ ! 881: outb(port+MCR, mcr & ~MC_RTS); ! 882: break; ! 883: case TIOCRSPEED: /* set "raw" I/O speed divisor */ ! 884: outb(port+LCR, lcr|LC_DLAB); /* set speed latch bit */ ! 885: outb(port+DLL, (unsigned) vec); ! 886: outb(port+DLH, (unsigned) vec >> 8); ! 887: outb(port+LCR, lcr); /* reset latch bit */ ! 888: break; ! 889: case TIOCWORDL: /* set word length and stop bits */ ! 890: outb(port+LCR, ((lcr&~0x7) | ((unsigned) vec & 0x7))); ! 891: break; ! 892: case TIOCRMSR: /* get CTS/DSR/RI/RLSD (MSR) */ ! 893: msr = inb(port+MSR); ! 894: temp = msr >> 4; ! 895: kucopy(&temp, (unsigned *) vec, sizeof(unsigned)); ! 896: break; ! 897: case TIOCFLUSH: /* Flush silos here, queues in tty.c */ ! 898: RAWIN_FLUSH(in_silo); ! 899: RAWOUT_FLUSH(out_silo); ! 900: do_ttioctl = 1; ! 901: break; ! 902: ! 903: /* ! 904: * If port parameters change, plan to call asyparam(). ! 905: * Need to check now before structs are updated. ! 906: */ ! 907: #ifdef _I386 ! 908: case TCSETA: ! 909: case TCSETAW: ! 910: case TCSETAF: ! 911: { ! 912: struct termio trm; ! 913: ! 914: ukcopy(vec, &trm, sizeof(struct termio)); ! 915: if (trm.c_cflag != tp->t_termio.c_cflag) ! 916: do_asyparam = 1; ! 917: } ! 918: do_ttioctl = 1; ! 919: break; ! 920: #endif ! 921: case TIOCSETP: ! 922: case TIOCSETN: ! 923: { ! 924: struct sgttyb sg; ! 925: ! 926: ukcopy(vec, &sg, sizeof(struct sgttyb)); ! 927: if (sg.sg_ispeed != tp->t_sgttyb.sg_ispeed ! 928: || ((sg.sg_flags ^ tp->t_sgttyb.sg_flags) & ANYP)) ! 929: do_asyparam = 1; ! 930: } ! 931: do_ttioctl = 1; ! 932: break; ! 933: default: ! 934: do_ttioctl = 1; ! 935: } ! 936: outb(port+IER, ier); ! 937: if (do_ttioctl) ! 938: ttioctl(tp, com, vec); ! 939: spl(s); ! 940: if (do_asyparam) ! 941: asyparam(tp); ! 942: #ifdef _I386 ! 943: /* ! 944: * Things to be done after calling ttioctl(). ! 945: */ ! 946: switch(com) { ! 947: case TCSBRK: ! 948: /* ! 949: * Send 0.25 second break: ! 950: * 1. Turn on break level. ! 951: * 2. Set timer to turn off break level 0.25 sec later. ! 952: * 3. Sleep till timer expires. ! 953: * 4. Turn off break level. ! 954: */ ! 955: outb(port+LCR, lcr|LC_SBRK); ! 956: a1->a_brk = 1; ! 957: timeout(&tp->t_sbrk, HZ/4, endbrk, chan); ! 958: while(a1->a_brk) { ! 959: #ifdef _I386 ! 960: x_sleep(a1, pritty, slpriNoSig, "asybreak"); ! 961: #else ! 962: v_sleep(a1, CVTTOUT, IVTTOUT, SVTTOUT, "asybreak"); ! 963: #endif ! 964: } ! 965: outb(port+LCR, lcr & ~LC_SBRK); ! 966: } ! 967: #endif ! 968: } ! 969: ! 970: #ifdef _I386 ! 971: /* ! 972: * Turn off the break level. ! 973: * Called from timeout after ioctl(fd, TCSBRK, 0). ! 974: */ ! 975: void ! 976: endbrk(chan) ! 977: int chan; ! 978: { ! 979: asy1_t *a1 = asy1 + chan; ! 980: ! 981: a1->a_brk = 0; ! 982: wakeup(a1); ! 983: } ! 984: #endif ! 985: ! 986: /* ! 987: * asyparam() ! 988: */ ! 989: static void ! 990: asyparam(tp) ! 991: TTY * tp; ! 992: { ! 993: int chan = (int)tp->t_ddp; ! 994: asy0_t *a0 = asy0 + chan; ! 995: asy1_t *a1 = asy1 + chan; ! 996: short port = a0->a_port; ! 997: int s; ! 998: int write_baud=1, write_lcr=1; ! 999: unsigned char mcr, newlcr, speed, oldSpeed; ! 1000: ! 1001: #ifdef _I386 ! 1002: unsigned short cflag = tp->t_termio.c_cflag; ! 1003: ! 1004: T_HAL(4, printf("ch%d asyparam cflag=%x\n", chan, cflag)); ! 1005: speed = cflag & CBAUD; ! 1006: switch (cflag & CSIZE) { ! 1007: case CS5: newlcr = LC_CS5; break; ! 1008: case CS6: newlcr = LC_CS6; break; ! 1009: case CS7: newlcr = LC_CS7; break; ! 1010: case CS8: newlcr = LC_CS8; break; ! 1011: } ! 1012: if (cflag & CSTOPB) ! 1013: newlcr |= LC_STOPB; ! 1014: if (cflag & PARENB) { ! 1015: newlcr |= LC_PARENB; ! 1016: if ((cflag & PARODD) == 0) ! 1017: newlcr |= LC_PAREVEN; ! 1018: } ! 1019: #else ! 1020: speed = tp->t_sgttyb.sg_ispeed; ! 1021: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) { ! 1022: case ODDP: ! 1023: newlcr = LC_CS7|LC_PARENB; ! 1024: break; ! 1025: case EVENP: ! 1026: newlcr = LC_CS7|LC_PARENB|LC_PAREVEN; ! 1027: break; ! 1028: default: ! 1029: newlcr = LC_CS8; ! 1030: break; ! 1031: } ! 1032: #endif ! 1033: ! 1034: /* ! 1035: * Don't bang on the UART needlessly. ! 1036: * Writing baud rate resets the port, which loses characters. ! 1037: * You want this on first open, NOT on later opens. ! 1038: */ ! 1039: oldSpeed = a0->a_speed; ! 1040: if (speed == oldSpeed && tp->t_open) { ! 1041: write_baud = 0; ! 1042: if (newlcr == a1->a_lcr) { ! 1043: write_lcr = 0; ! 1044: } ! 1045: } ! 1046: a0->a_speed = speed; ! 1047: a1->a_lcr = newlcr; ! 1048: ! 1049: if (write_lcr) { ! 1050: char ier_save; ! 1051: s = sphi(); ! 1052: ier_save = inb(port+IER); ! 1053: if (write_baud) { ! 1054: if (speed) { ! 1055: short divisor = albaud[speed]; ! 1056: ! 1057: if (oldSpeed == 0) { ! 1058: /* if previous baud rate was zero, ! 1059: * need to go off hook. */ ! 1060: mcr = inb(port+MCR) | (MC_RTS | MC_DTR); ! 1061: outb(port+MCR, mcr); ! 1062: } ! 1063: T_HAL(4, printf("CH%d speed=%x\n", chan, speed)); ! 1064: outb(port+LCR, LC_DLAB); ! 1065: outb(port+DLL, divisor); ! 1066: outb(port+DLH, divisor >> 8); ! 1067: } else { ! 1068: /* Baud rate of zero means hang up. */ ! 1069: mcr = inb(port+MCR) & ~(MC_RTS | MC_DTR); ! 1070: outb(port+MCR, mcr); ! 1071: } ! 1072: } ! 1073: T_HAL(4, printf("CH%d newlcr=%x\n", chan, newlcr)); ! 1074: outb(port+LCR, newlcr); ! 1075: if (a1->a_ut == US_16550A) ! 1076: outb(port+FCR, FC_ENABLE | FC_Rx_RST | FC_Rx_08); ! 1077: outb(port+IER, ier_save); ! 1078: spl(s); ! 1079: } ! 1080: if (write_baud) ! 1081: asyspr(); ! 1082: } ! 1083: ! 1084: /* ! 1085: * asystart() ! 1086: */ ! 1087: static void ! 1088: asystart(tp) ! 1089: TTY * tp; ! 1090: { ! 1091: int chan = (int)tp->t_ddp; ! 1092: asy0_t *a0 = asy0 + chan; ! 1093: asy1_t *a1 = asy1 + chan; ! 1094: short port = a0->a_port; ! 1095: int s; ! 1096: int need_xmit = 1; /* True if should start sending data now. */ ! 1097: silo_t *out_silo = &a1->a_out; ! 1098: char lsr; ! 1099: ! 1100: /* ! 1101: * Read line status register AFTER disabling interrupts. ! 1102: */ ! 1103: s = sphi(); ! 1104: lsr = inb(port + LSR); ! 1105: ! 1106: /* ! 1107: * Process break indication. ! 1108: * NOTE: Break indication cleared when line status register was read. ! 1109: */ ! 1110: if (lsr & LS_BREAK) ! 1111: defer(asybreak, chan); ! 1112: ! 1113: /* ! 1114: * If no output data, it may be time to finish closing the port; ! 1115: * but won't need another xmit interrupt. ! 1116: */ ! 1117: if (out_silo->si_ix == out_silo->si_ox) { ! 1118: if (need_wake[chan] & NW_OUTSILO) { ! 1119: need_wake[chan] &= ~NW_OUTSILO; ! 1120: wakeup((char *)out_silo); ! 1121: } ! 1122: need_xmit = 0; ! 1123: } ! 1124: ! 1125: /* ! 1126: * Do nothing if output is stopped. ! 1127: */ ! 1128: if (tp->t_flags & T_STOP) ! 1129: need_xmit = 0; ! 1130: if (a1->a_ohlt) ! 1131: need_xmit = 0; ! 1132: ! 1133: /* ! 1134: * Start data transmission by writing to UART xmit reg. ! 1135: */ ! 1136: if ((lsr & LS_TxRDY) && need_xmit) { ! 1137: int xmit_count; ! 1138: xmit_count = (a1->a_ut == US_16550A)?16:1; ! 1139: asy_send(out_silo, port+DREG, xmit_count); ! 1140: } ! 1141: spl(s); ! 1142: } ! 1143: ! 1144: /* ! 1145: * asypoll() ! 1146: */ ! 1147: static int ! 1148: asypoll(dev, ev, msec) ! 1149: dev_t dev; ! 1150: int ev; ! 1151: int msec; ! 1152: { ! 1153: int chan = channel(dev); ! 1154: asy1_t *a1 = asy1 + chan; ! 1155: TTY *tp = &a1->a_tty; ! 1156: ! 1157: return ttpoll(tp, ev, msec); ! 1158: } ! 1159: ! 1160: /* ! 1161: * asycycle() ! 1162: * ! 1163: * Do a wakeup of any sleeping asy's at regular intervals. ! 1164: */ ! 1165: static void ! 1166: asycycle(chan) ! 1167: int chan; ! 1168: { ! 1169: asy0_t *a0 = asy0 + chan; ! 1170: asy1_t *a1 = asy1 + chan; ! 1171: TTY *tp = &a1->a_tty; ! 1172: short port = a0->a_port; ! 1173: int s; ! 1174: char msr, mcr; ! 1175: silo_t *out_silo = &a1->a_out; ! 1176: silo_t *in_silo = &a1->a_in; ! 1177: int n, ch; ! 1178: int do_start = 1; ! 1179: unsigned char iir; ! 1180: ! 1181: /* ! 1182: * Check Carrier Detect (RLSD). ! 1183: * ! 1184: * Modem status interrupts were not enabled due to 8250 hardware bug. ! 1185: * Enabling modem status and receive interrupts may cause lockup ! 1186: * on older parts. ! 1187: */ ! 1188: if (tp->t_flags & T_MODC) { ! 1189: ! 1190: /* ! 1191: * Get status ! 1192: */ ! 1193: msr = inb(port+MSR); ! 1194: ! 1195: /* ! 1196: * Carrier changed. ! 1197: */ ! 1198: if ((msr & MS_RLSD) && !(tp->t_flags & T_CARR)) { ! 1199: /* ! 1200: * Carrier is on - wakeup open. ! 1201: */ ! 1202: s = sphi(); ! 1203: tp->t_flags |= T_CARR; ! 1204: spl(s); ! 1205: wakeup((char *)(&tp->t_open)); ! 1206: } ! 1207: ! 1208: if (!(msr & MS_RLSD) && (tp->t_flags & T_CARR)) { ! 1209: s = sphi(); ! 1210: RAWIN_FLUSH(in_silo); ! 1211: RAWOUT_FLUSH(out_silo); ! 1212: tp->t_flags &= ~T_CARR; ! 1213: spl(s); ! 1214: tthup(tp); ! 1215: } ! 1216: } ! 1217: ! 1218: /* ! 1219: * Empty raw input buffer. ! 1220: * ! 1221: * The line discipline module (tty.c) will set T_ISTOP true when the ! 1222: * tt input queue is nearly full (tp->t_iq.cq_cc >= IHILIM), and make ! 1223: * T_ISTOP false when it's ready for more input. ! 1224: * ! 1225: * When T_ISTOP is true, ttin() simply discards the character passed. ! 1226: */ ! 1227: if (!(tp->t_flags & T_ISTOP)) { ! 1228: while (in_silo->SILO_CHAR_COUNT > 0) { ! 1229: s = sphi(); ! 1230: ttin(tp, in_silo->si_buf[in_silo->si_ox]); ! 1231: if (in_silo->si_ox < MAX_SILO_INDEX) ! 1232: in_silo->si_ox++; ! 1233: else ! 1234: in_silo->si_ox = 0; ! 1235: in_silo->SILO_CHAR_COUNT--; ! 1236: spl(s); ! 1237: } ! 1238: } ! 1239: ! 1240: /* ! 1241: * Hardware flow control. ! 1242: * Check CTS to see if we need to halt output. ! 1243: * (MS_INTR should have done this - repeat code here to be sure) ! 1244: * Check input silo to see if we need to raise RTS. ! 1245: */ ! 1246: if (tp->t_flags & T_CFLOW) { ! 1247: ! 1248: /* ! 1249: * Get status ! 1250: */ ! 1251: msr = inb(port+MSR); ! 1252: s = sphi(); ! 1253: if (msr & MS_CTS) ! 1254: a1->a_ohlt = 0; ! 1255: else ! 1256: a1->a_ohlt = 1; ! 1257: spl(s); ! 1258: T_HAL(4, {static cts = 0; if (!cts && (msr & MS_CTS)) { cts = 1; putchar('[');\ ! 1259: } else if (cts && !(msr & MS_CTS)) { cts = 0; putchar(']'); }}); ! 1260: ! 1261: /* ! 1262: * If using hardware flow control, see if we need to drop RTS. ! 1263: */ ! 1264: if ((tp->t_flags & T_CFLOW) ! 1265: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 1266: s = sphi(); ! 1267: mcr = inb(port+MCR); ! 1268: if (mcr & MC_RTS) { ! 1269: outb(port+MCR, mcr & ~MC_RTS); ! 1270: T_HAL(4, putchar('-')); ! 1271: } ! 1272: spl(s); ! 1273: } ! 1274: ! 1275: /* ! 1276: * If input silo below low mark, assert RTS. ! 1277: */ ! 1278: if (in_silo->SILO_CHAR_COUNT <= SILO_LOW_MARK) { ! 1279: s = sphi(); ! 1280: mcr = inb(port+MCR); ! 1281: if ((mcr & MC_RTS) == 0) { ! 1282: outb(port+MCR, mcr | MC_RTS); ! 1283: T_HAL(4, putchar('+')); ! 1284: } ! 1285: spl(s); ! 1286: } ! 1287: } ! 1288: ! 1289: /* ! 1290: * Calculate free output slot count. ! 1291: */ ! 1292: n = sizeof(out_silo->si_buf) - 1; ! 1293: n += out_silo->si_ox - out_silo->si_ix; ! 1294: n %= sizeof(out_silo->si_buf); ! 1295: ! 1296: /* ! 1297: * Fill raw output buffer. ! 1298: */ ! 1299: for (;;) { ! 1300: if (--n < 0) ! 1301: break; ! 1302: s = sphi(); ! 1303: ch = ttout(tp); ! 1304: spl(s); ! 1305: if (ch < 0) ! 1306: break; ! 1307: ! 1308: s = sphi(); ! 1309: out_silo->si_buf[out_silo->si_ix] = ch; ! 1310: if (out_silo->si_ix >= sizeof(out_silo->si_buf) - 1) ! 1311: out_silo->si_ix = 0; ! 1312: else ! 1313: out_silo->si_ix++; ! 1314: spl(s); ! 1315: } ! 1316: ! 1317: #ifdef _I386 ! 1318: /* ! 1319: * if port has an interrupt pending (probably missed an irq) ! 1320: * the following two loops should not be merged ! 1321: * - need ALL port irq's inactive at once ! 1322: * for each port on this irq line (use irq1 for this) ! 1323: * disable interrupts (clear IER) ! 1324: * for each port on this irq line ! 1325: * restore interrupts ! 1326: */ ! 1327: if (a1->a_has_irq && ((iir=inb(port+IIR)) & 1) == 0) { ! 1328: struct irqnode *ip; ! 1329: asy_gp_t *gp; ! 1330: int s; ! 1331: short p; ! 1332: char c, slot; ! 1333: ! 1334: T_HAL(4, printf("CH%d missed iir:x\n", chan, iir)); ! 1335: ! 1336: do_start = 0; ! 1337: s = sphi(); ! 1338: ip = irq1[a0->a_irqno]; ! 1339: while(ip) { ! 1340: if (ip->func == asyintr) { ! 1341: p = ip->arg; ! 1342: outb(p + IER, 0); ! 1343: } else { ! 1344: gp = asy_gp + ip->arg; ! 1345: for (slot = 0; slot < MAX_SLOTS; slot++) { ! 1346: if ((c=gp->chan_list[slot]) < MAX_ASY){ ! 1347: p = asy0[c].a_port; ! 1348: outb(p + IER, 0); ! 1349: } ! 1350: } ! 1351: } ! 1352: ip = ip->next_actv; ! 1353: } ! 1354: /* ! 1355: * Now, all ports on the offending irq line have irq off. ! 1356: */ ! 1357: ip = irq1[a0->a_irqno]; ! 1358: while(ip) { ! 1359: if (ip->func == asyintr) { ! 1360: p = ip->arg; ! 1361: outb(p + IER, IEN); ! 1362: } else { ! 1363: gp = asy_gp + ip->arg; ! 1364: for (slot = 0; slot < MAX_SLOTS; slot++) { ! 1365: if ((c=gp->chan_list[slot]) < MAX_ASY){ ! 1366: p = asy0[c].a_port; ! 1367: outb(p + IER, IEN); ! 1368: } ! 1369: } ! 1370: } ! 1371: ip = ip->next_actv; ! 1372: } ! 1373: spl(s); ! 1374: } ! 1375: #endif ! 1376: ! 1377: if(do_start) ! 1378: ttstart(tp); ! 1379: ! 1380: /* ! 1381: * Schedule next cycle. ! 1382: */ ! 1383: if (a1->a_in_use) { ! 1384: timeout(&tp->t_rawtim, HZ/10, asycycle, chan); ! 1385: } ! 1386: } ! 1387: ! 1388: /* ! 1389: * irqdummy() ! 1390: * ! 1391: * Suppress interrupts that may occur during chip sensing. ! 1392: */ ! 1393: static void ! 1394: irqdummy() ! 1395: { ! 1396: /* ! 1397: * Try to clear all pending interrupts. ! 1398: */ ! 1399: inb(dummy_port+IIR); ! 1400: inb(dummy_port+LSR); ! 1401: inb(dummy_port+MSR); ! 1402: inb(dummy_port+DREG); ! 1403: } ! 1404: ! 1405: /* ! 1406: * add_irq() ! 1407: * ! 1408: * Given channel number, add port info to irq0 list. ! 1409: */ ! 1410: static void ! 1411: add_irq(irq, func, arg) ! 1412: int irq; ! 1413: void (*func)(); ! 1414: int arg; ! 1415: { ! 1416: struct irqnode * np; ! 1417: ! 1418: /* ! 1419: * Sanity check. ! 1420: */ ! 1421: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0) ! 1422: return; ! 1423: ! 1424: if (nextnode < MAX_ASY) { ! 1425: np = nodespace + nextnode++; ! 1426: np->func = func; ! 1427: np->arg = arg; ! 1428: np->next = irq0[irq]; ! 1429: irq0[irq] = np; ! 1430: } else { ! 1431: printf("asy: too many irq nodes (%d)\n", nextnode); ! 1432: } ! 1433: } ! 1434: ! 1435: /* ! 1436: * Interrupt handlers. ! 1437: */ ! 1438: static void i2() { asy_irq(irq1[2]); } ! 1439: static void i3() { asy_irq(irq1[3]); } ! 1440: static void i4() { asy_irq(irq1[4]); } ! 1441: static void i5() { asy_irq(irq1[5]); } ! 1442: static void i6() { asy_irq(irq1[6]); } ! 1443: static void i7() { asy_irq(irq1[7]); } ! 1444: static void i8() { asy_irq(irq1[8]); } ! 1445: static void i9() { asy_irq(irq1[9]); } ! 1446: static void i10() { asy_irq(irq1[10]); } ! 1447: static void i11() { asy_irq(irq1[11]); } ! 1448: static void i12() { asy_irq(irq1[12]); } ! 1449: static void i13() { asy_irq(irq1[13]); } ! 1450: static void i14() { asy_irq(irq1[14]); } ! 1451: static void i15() { asy_irq(irq1[15]); } ! 1452: ! 1453: /* ! 1454: * asy_irq() ! 1455: * ! 1456: * Given pointer to node list, service async interrupt. ! 1457: */ ! 1458: static void ! 1459: asy_irq(ip) ! 1460: struct irqnode * ip; ! 1461: { ! 1462: struct irqnode *here; ! 1463: int doit; ! 1464: ! 1465: do { ! 1466: doit = 0; ! 1467: here = ip; ! 1468: while(here) { ! 1469: doit |= (*(here->func))(here->arg); ! 1470: here = here->next_actv; ! 1471: } ! 1472: } while(doit); ! 1473: } ! 1474: ! 1475: /* ! 1476: * upd_irq1() ! 1477: * ! 1478: * Given an irq number, rebuild the links for active devices. ! 1479: */ ! 1480: static void ! 1481: upd_irq1(irq) ! 1482: int irq; ! 1483: { ! 1484: struct irqnode *np; ! 1485: asy1_t *a1; ! 1486: int chan; ! 1487: int s; ! 1488: ! 1489: /* ! 1490: * Sanity check. ! 1491: */ ! 1492: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0) ! 1493: return; ! 1494: ! 1495: /* ! 1496: * For each node in the irq0 list ! 1497: * if node is for irq status port ! 1498: * for each channel using the status port ! 1499: * if channel in use, in irq mode ! 1500: * add node to irq1 list ! 1501: * skip rest of channels for this node ! 1502: * else - node is for simple UART ! 1503: * if channel in use, in irq mode ! 1504: * add node to irq1 list ! 1505: */ ! 1506: s = sphi(); ! 1507: np = irq0[irq]; ! 1508: irq1[irq] = 0; ! 1509: while (np) { ! 1510: if (np->func != asyintr) { ! 1511: char ix, loop = 1; ! 1512: asy_gp_t *gp = asy_gp + np->arg; ! 1513: ! 1514: for (ix = 0; ix < MAX_SLOTS && loop; ix++) { ! 1515: if ((chan = gp->chan_list[ix]) < MAX_ASY) { ! 1516: a1 = asy1 + chan; ! 1517: if (a1->a_in_use && a1->a_irq) { ! 1518: np->next_actv = irq1[irq]; ! 1519: irq1[irq] = np; ! 1520: loop = 0; ! 1521: } ! 1522: } ! 1523: } ! 1524: } else { ! 1525: a1 = asy1 + np->arg; ! 1526: if (a1->a_in_use && a1->a_irq) { ! 1527: np->next_actv = irq1[irq]; ! 1528: irq1[irq] = np; ! 1529: } ! 1530: } ! 1531: np = np->next; ! 1532: } ! 1533: spl(s); ! 1534: } ! 1535: ! 1536: /* ! 1537: * asybreak() ! 1538: */ ! 1539: static void ! 1540: asybreak(chan) ! 1541: int chan; ! 1542: { ! 1543: int s; ! 1544: asy1_t *a1 = asy1 + chan; ! 1545: silo_t *out_silo = &a1->a_out; ! 1546: silo_t *in_silo = &a1->a_in; ! 1547: TTY *tp = &a1->a_tty; ! 1548: ! 1549: s = sphi(); ! 1550: RAWIN_FLUSH(in_silo); ! 1551: RAWOUT_FLUSH(out_silo); ! 1552: spl(s); ! 1553: ttsignal(tp, SIGINT); ! 1554: } ! 1555: ! 1556: /* ! 1557: * asyintr() ! 1558: * ! 1559: * Handle interrupt for a single channel. ! 1560: */ ! 1561: static int ! 1562: asyintr(chan) ! 1563: int chan; ! 1564: { ! 1565: asy0_t *a0 = asy0 + chan; ! 1566: asy1_t *a1 = asy1 + chan; ! 1567: TTY *tp = &a1->a_tty; ! 1568: silo_t *out_silo = &a1->a_out; ! 1569: silo_t *in_silo = &a1->a_in; ! 1570: int c, xmit_count; ! 1571: int ret = 0; ! 1572: short port = a0->a_port; ! 1573: unsigned char msr, lsr; ! 1574: ! 1575: if (chan >= MAX_ASY) { ! 1576: printf("asy: irq on channel %d\n", chan); ! 1577: return 0; ! 1578: } ! 1579: ! 1580: rescan: ! 1581: switch (inb(port+IIR) & 0x07) { ! 1582: ! 1583: case LS_INTR: ! 1584: ret = 1; ! 1585: lsr = inb(port + LSR); ! 1586: T_HAL(0x800, printf("[%d:L%x]", chan, lsr)); ! 1587: if (lsr & LS_BREAK) ! 1588: defer(asybreak, chan); ! 1589: goto rescan; ! 1590: ! 1591: case Rx_INTR: ! 1592: T_HAL(0x800, printf("[%d:R]", chan)); ! 1593: ret = 1; ! 1594: c = inb(port+DREG); ! 1595: if (tp->t_open == 0) ! 1596: goto rescan; ! 1597: /* ! 1598: * Must recognize XOFF quickly to avoid transmit overrun. ! 1599: * Recognize XON here as well to avoid race conditions. ! 1600: */ ! 1601: if (ISIXON) { ! 1602: /* ! 1603: * XON. ! 1604: */ ! 1605: #if _I386 ! 1606: if (ISSTART || (ISIXANY && ISXSTOP)) { ! 1607: tp->t_flags &= ~(T_STOP | T_XSTOP); ! 1608: goto rescan; ! 1609: } ! 1610: #else ! 1611: if (ISSTART) { ! 1612: tp->t_flags &= ~T_STOP; ! 1613: goto rescan; ! 1614: } ! 1615: #endif ! 1616: ! 1617: /* ! 1618: * XOFF. ! 1619: */ ! 1620: if (ISSTOP) { ! 1621: tp->t_flags |= T_STOP; ! 1622: goto rescan; ! 1623: } ! 1624: } ! 1625: ! 1626: /* ! 1627: * Save char in raw input buffer. ! 1628: */ ! 1629: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) { ! 1630: in_silo->si_buf[in_silo->si_ix] = c; ! 1631: if (in_silo->si_ix < MAX_SILO_INDEX) ! 1632: in_silo->si_ix++; ! 1633: else ! 1634: in_silo->si_ix = 0; ! 1635: in_silo->SILO_CHAR_COUNT++; ! 1636: } ! 1637: ! 1638: /* ! 1639: * If using hardware flow control, see if we need to drop RTS. ! 1640: */ ! 1641: if ((tp->t_flags & T_CFLOW) ! 1642: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 1643: unsigned char mcr = inb(port+MCR); ! 1644: if (mcr & MC_RTS) { ! 1645: outb(port+MCR, mcr & ~MC_RTS); ! 1646: } ! 1647: } ! 1648: ! 1649: goto rescan; ! 1650: ! 1651: case Tx_INTR: ! 1652: T_HAL(0x800, printf("[%d:T]", chan)); ! 1653: ret = 1; ! 1654: /* ! 1655: * Do nothing if output is stopped. ! 1656: */ ! 1657: if (tp->t_flags & T_STOP) { ! 1658: goto rescan; ! 1659: } ! 1660: if (a1->a_ohlt) ! 1661: goto rescan; ! 1662: ! 1663: /* ! 1664: * Transmit next char in raw output buffer. ! 1665: */ ! 1666: xmit_count = (a1->a_ut == US_16550A)?16:1; ! 1667: asy_send(out_silo, port+DREG, xmit_count); ! 1668: goto rescan; ! 1669: ! 1670: case MS_INTR: ! 1671: ret = 1; ! 1672: /* ! 1673: * Get status (and clear interrupt). ! 1674: */ ! 1675: msr = inb(port+MSR); ! 1676: T_HAL(0x800, printf("[%d:M%x]", chan, msr)); ! 1677: ! 1678: /* ! 1679: * Hardware flow control. ! 1680: * Check CTS to see if we need to halt output. ! 1681: */ ! 1682: if (tp->t_flags & T_CFLOW) { ! 1683: if (msr & MS_CTS) ! 1684: a1->a_ohlt = 0; ! 1685: else ! 1686: a1->a_ohlt = 1; ! 1687: } ! 1688: ! 1689: goto rescan; ! 1690: default: ! 1691: return ret; ! 1692: } /* endswitch */ ! 1693: } ! 1694: ! 1695: /* ! 1696: * asyclk() ! 1697: * ! 1698: * Called every time T0 interrupts.- if it returns 0, ! 1699: * the usual system timer interrupt stuff is done. ! 1700: * Poll all pollable ports. ! 1701: */ ! 1702: static int ! 1703: asyclk() ! 1704: { ! 1705: static int count; ! 1706: int ix; ! 1707: ! 1708: for (ix = 0; ix < ppnum; ix++) ! 1709: asysph(pptbl[ix]); ! 1710: ! 1711: count++; ! 1712: if (count >= poll_divisor) ! 1713: count = 0; ! 1714: return count; ! 1715: } ! 1716: ! 1717: /* ! 1718: * asyspr() ! 1719: * ! 1720: * asyspr is called when a port is opened or closed or changes speed ! 1721: * It sets the polling rate only as fast as needed, and shuts off polling ! 1722: * whenever possible. ! 1723: * It updates the links in irq1[0], which lists polled-mode ports. ! 1724: */ ! 1725: static void ! 1726: asyspr() ! 1727: { ! 1728: asy0_t *a0; ! 1729: asy1_t *a1; ! 1730: int chan; ! 1731: int s; ! 1732: int ix, max_rate, port_rate; ! 1733: ! 1734: /* ! 1735: * Rebuild table of pollable ports. ! 1736: */ ! 1737: s = sphi(); ! 1738: ppnum = 0; ! 1739: for (chan = 0; chan < ASY_NUM; chan++) { ! 1740: a1 = asy1 + chan; ! 1741: if (a1->a_poll) ! 1742: pptbl[ppnum++] = chan; ! 1743: } ! 1744: spl(s); ! 1745: ! 1746: /* ! 1747: * If another driver has the polling clock, do nothing. ! 1748: */ ! 1749: if (poll_owner & ~ POLL_ASY) ! 1750: return; ! 1751: ! 1752: /* ! 1753: * Find highest valid polling rate in units of HZ/10. ! 1754: * If using FIFO chip, can poll at 1/16 the usual rate. ! 1755: */ ! 1756: max_rate = 0; ! 1757: for (ix = 0; ix < ppnum; ix++) { ! 1758: chan = pptbl[ix]; ! 1759: a0 = asy0 + chan; ! 1760: a1 = asy1 + chan; ! 1761: port_rate = alp_rate[a0->a_speed]; ! 1762: if (a1->a_ut == US_16550A) { ! 1763: port_rate /= 16; ! 1764: if (port_rate % HZ) ! 1765: port_rate += HZ - (port_rate % HZ); ! 1766: } ! 1767: if (max_rate < port_rate) ! 1768: max_rate = port_rate; ! 1769: } ! 1770: ! 1771: /* ! 1772: * if max_rate is not current rate, adjust the system clock ! 1773: */ ! 1774: if (max_rate != poll_rate) { ! 1775: poll_rate = max_rate; ! 1776: poll_divisor = poll_rate/HZ; /* used in asyclk() */ ! 1777: altclk_out(); /* stop previous polling */ ! 1778: poll_owner &= ~ POLL_ASY; ! 1779: if (poll_rate) { /* resume polling at new rate if needed */ ! 1780: poll_owner |= POLL_ASY; ! 1781: altclk_in(poll_rate, asyclk); ! 1782: } ! 1783: } ! 1784: } ! 1785: ! 1786: /* ! 1787: * asysph() ! 1788: * ! 1789: * Serial polling handler. ! 1790: */ ! 1791: static void ! 1792: asysph(chan) ! 1793: int chan; ! 1794: { ! 1795: asy0_t *a0 = asy0 + chan; ! 1796: asy1_t *a1 = asy1 + chan; ! 1797: TTY *tp = &a1->a_tty; ! 1798: silo_t *out_silo = &a1->a_out; ! 1799: silo_t *in_silo = &a1->a_in; ! 1800: int c, xmit_count; ! 1801: short port = a0->a_port; ! 1802: char lsr; ! 1803: ! 1804: /* ! 1805: * Check for received break first. ! 1806: * This status is wiped out on reading the LSR. ! 1807: */ ! 1808: lsr = inb(port + LSR); ! 1809: if (lsr & LS_BREAK) ! 1810: defer(asybreak, chan); ! 1811: ! 1812: /* ! 1813: * Handle all incoming characters. ! 1814: */ ! 1815: for (;;) { ! 1816: lsr = inb(port + LSR); ! 1817: if ((lsr & LS_RxRDY) == 0) ! 1818: break; ! 1819: c = inb(port+DREG); ! 1820: if (tp->t_open == 0) ! 1821: continue; ! 1822: /* ! 1823: * Must recognize XOFF quickly to avoid transmit overrun. ! 1824: * Recognize XON here as well to avoid race conditions. ! 1825: */ ! 1826: if (ISIXON) { ! 1827: /* ! 1828: * XOFF. ! 1829: */ ! 1830: if (ISSTOP) { ! 1831: tp->t_flags |= T_STOP; ! 1832: continue; ! 1833: } ! 1834: ! 1835: /* ! 1836: * XON. ! 1837: */ ! 1838: if (ISSTART) { ! 1839: tp->t_flags &= ~T_STOP; ! 1840: continue; ! 1841: } ! 1842: } ! 1843: ! 1844: /* ! 1845: * Save char in raw input buffer. ! 1846: */ ! 1847: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) { ! 1848: in_silo->si_buf[in_silo->si_ix] = c; ! 1849: if (in_silo->si_ix < MAX_SILO_INDEX) ! 1850: in_silo->si_ix++; ! 1851: else ! 1852: in_silo->si_ix = 0; ! 1853: in_silo->SILO_CHAR_COUNT++; ! 1854: } ! 1855: ! 1856: /* ! 1857: * If using hardware flow control, see if we need to drop RTS. ! 1858: */ ! 1859: if ((tp->t_flags & T_CFLOW) ! 1860: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 1861: unsigned char mcr = inb(port+MCR); ! 1862: if (mcr & MC_RTS) { ! 1863: outb(port+MCR, mcr & ~MC_RTS); ! 1864: } ! 1865: } ! 1866: } ! 1867: ! 1868: /* ! 1869: * Handle outgoing characters. ! 1870: * Do nothing if output is stopped. ! 1871: */ ! 1872: lsr = inb(port + LSR); ! 1873: if ((lsr & LS_TxRDY) ! 1874: && !(tp->t_flags & T_STOP) ! 1875: && !(a1->a_ohlt)) { ! 1876: /* ! 1877: * Transmit next char in raw output buffer. ! 1878: */ ! 1879: xmit_count = (a1->a_ut == US_16550A)?16:1; ! 1880: asy_send(out_silo, port+DREG, xmit_count); ! 1881: } ! 1882: ! 1883: /* ! 1884: * Hardware flow control. ! 1885: * Check CTS to see if we need to halt output. ! 1886: */ ! 1887: if (tp->t_flags & T_CFLOW) { ! 1888: if (inb(port+MSR) & MS_CTS) ! 1889: a1->a_ohlt = 0; ! 1890: else ! 1891: a1->a_ohlt = 1; ! 1892: } ! 1893: } ! 1894: ! 1895: /* ! 1896: * asy_send() ! 1897: * ! 1898: * Write to xmit data register of the UART. ! 1899: * Assume all checking about whether it's time to send has been done already. ! 1900: * Called by time-critical IRQ and polling routines! ! 1901: * ! 1902: * "rawout" is the output silo for the TTY struct supplying data to the port. ! 1903: * "dreg" is the i/o address of the UART xmit data register. ! 1904: * "xmit_count" is the max number of chars we can write (16 for FIFO parts). ! 1905: */ ! 1906: static int ! 1907: asy_send(rawout, dreg, xmit_count) ! 1908: register silo_t * rawout; ! 1909: int dreg, xmit_count; ! 1910: { ! 1911: /* ! 1912: * Transmit next chars in raw output buffer. ! 1913: */ ! 1914: for (;(rawout->si_ix != rawout->si_ox) && xmit_count; xmit_count--) { ! 1915: outb(dreg, rawout->si_buf[rawout->si_ox]); ! 1916: /* ! 1917: * Adjust raw output buffer output index. ! 1918: */ ! 1919: if (++rawout->si_ox >= sizeof(rawout->si_buf)) ! 1920: rawout->si_ox = 0; ! 1921: } ! 1922: return xmit_count; ! 1923: } ! 1924: ! 1925: /* ! 1926: * p1() ! 1927: * ! 1928: * Interrupt handler for Comtrol-type port groups. ! 1929: * Status register has 1 in bit positions for interrupting ports. ! 1930: */ ! 1931: static int ! 1932: p1(g) ! 1933: int g; ! 1934: { ! 1935: asy_gp_t *gp = asy_gp + g; ! 1936: short port = gp->stat_port; ! 1937: unsigned char status, index, chan; ! 1938: int safety = LOOP_LIMIT; ! 1939: int ret = 0; ! 1940: ! 1941: #if 0 /* DEBUG */ ! 1942: static int pxstat[2][8]; ! 1943: int ci; ! 1944: int change_found=0; ! 1945: ! 1946: for (ci=0; ci<1; ci++) { ! 1947: index = inb(port+ci); ! 1948: outb(port+ci, 0); ! 1949: if (index != pxstat[g][ci]) { ! 1950: if (!change_found) { ! 1951: change_found = 1; ! 1952: printf("<%d:", g); ! 1953: } else ! 1954: putchar(' '); ! 1955: printf("%x:%x", port+ci, index); ! 1956: pxstat[g][ci] = index; ! 1957: } ! 1958: } ! 1959: if (change_found) ! 1960: putchar('>'); ! 1961: for (ci=0; ci<8; ci++) ! 1962: asyintr(4+ci); ! 1963: putchar('.'); ! 1964: return 0; ! 1965: #endif /* DEBUG */ ! 1966: ! 1967: /* ! 1968: * while any port is active ! 1969: * call simple interrupt handler for active channel ! 1970: */ ! 1971: while (status = inb(port)) { ! 1972: ret = 1; ! 1973: index = 0; ! 1974: if (status & 0xf0) { ! 1975: status &= 0xf0; ! 1976: index +=4; ! 1977: } else ! 1978: status &= 0x0f; ! 1979: if (status & 0xcc) { ! 1980: status &= 0xcc; ! 1981: index +=2; ! 1982: } else ! 1983: status &= 0x33; ! 1984: if (status & 0xaa) ! 1985: index++; ! 1986: chan = gp->chan_list[index]; ! 1987: asyintr(chan); ! 1988: if (safety-- == 0) { ! 1989: printf("asy: p1 runaway - status %x\n", status); ! 1990: break; ! 1991: } ! 1992: } ! 1993: ! 1994: return ret; ! 1995: } ! 1996: ! 1997: /* ! 1998: * p2() ! 1999: * ! 2000: * Interrupt handler for Arnet-type port groups. ! 2001: * Status register has 0 in bit positions for interrupting ports. ! 2002: */ ! 2003: static int ! 2004: p2(g) ! 2005: int g; ! 2006: { ! 2007: asy_gp_t *gp = asy_gp + g; ! 2008: short port = gp->stat_port; ! 2009: unsigned char status, index, chan; ! 2010: int safety = LOOP_LIMIT; ! 2011: int ret = 0; ! 2012: ! 2013: /* ! 2014: * while any port is active ! 2015: * call simple interrupt handler for active channel ! 2016: */ ! 2017: while (status = ~inb(port)) { ! 2018: ret = 1; ! 2019: index = 0; ! 2020: if (status & 0xf0) { ! 2021: status &= 0xf0; ! 2022: index +=4; ! 2023: } else ! 2024: status &= 0x0f; ! 2025: if (status & 0xcc) { ! 2026: status &= 0xcc; ! 2027: index +=2; ! 2028: } else ! 2029: status &= 0x33; ! 2030: if (status & 0xaa) ! 2031: index++; ! 2032: chan = gp->chan_list[index]; ! 2033: asyintr(chan); ! 2034: if (safety-- == 0) { ! 2035: printf("asy: p2 runaway - status %x\n", status); ! 2036: break; ! 2037: } ! 2038: } ! 2039: return ret; ! 2040: } ! 2041: ! 2042: /* ! 2043: * p3() ! 2044: * ! 2045: * Interrupt handler for GTEK-type port groups. ! 2046: */ ! 2047: static int ! 2048: p3(g) ! 2049: int g; ! 2050: { ! 2051: asy_gp_t *gp = asy_gp + g; ! 2052: short port = gp->stat_port; ! 2053: unsigned char index, chan; ! 2054: ! 2055: /* ! 2056: * Call simple interrupt handler for active channel. ! 2057: */ ! 2058: index = inb(port) & 7; ! 2059: chan = gp->chan_list[index]; ! 2060: return asyintr(chan); ! 2061: } ! 2062: ! 2063: /* ! 2064: * p4() ! 2065: * ! 2066: * Interrupt handler for DigiBoard-type port groups. ! 2067: */ ! 2068: static int ! 2069: p4(g) ! 2070: int g; ! 2071: { ! 2072: asy_gp_t *gp = asy_gp + g; ! 2073: short port = gp->stat_port; ! 2074: unsigned char index, chan; ! 2075: int ret = 0; ! 2076: int safety = LOOP_LIMIT; ! 2077: ! 2078: /* ! 2079: * Status register has slot number for active port, ! 2080: * or 0xFF if no port is active. ! 2081: */ ! 2082: ! 2083: for (;;) { ! 2084: index = inb(port); ! 2085: if (index == 0xFF) ! 2086: break; ! 2087: if (safety-- == 0) { ! 2088: printf("asy: p4 runaway - status %x\n", index); ! 2089: break; ! 2090: } ! 2091: ret = 1; ! 2092: chan = gp->chan_list[index&0xF]; ! 2093: asyintr(chan); ! 2094: } ! 2095: return ret; ! 2096: } ! 2097: ! 2098: #ifdef TRACER ! 2099: void ! 2100: asydump(chan, tag) ! 2101: int chan; ! 2102: char *tag; ! 2103: { ! 2104: asy0_t *a0 = asy0 + chan; ! 2105: asy1_t *a1 = asy1 + chan; ! 2106: TTY *tp = &a1->a_tty; ! 2107: ! 2108: printf("ch=%d %s\n", chan, tag); ! 2109: printf("port=%x irqno=%x speed=%d ", ! 2110: a0->a_port, a0->a_irqno, a0->a_speed); ! 2111: printf("outs=%x gp=%d xcl=%d\n", ! 2112: a0->a_outs, a0->a_asy_gp, a0->a_ixc); ! 2113: printf("in_use=%d lcr=%x irq=%d has_irq=%d ", ! 2114: a1->a_in_use, a1->a_lcr, a1->a_irq, a1->a_has_irq); ! 2115: printf("hop=%d hcl=%d ", a1->a_hopn, a1->a_hcls); ! 2116: printf("opn=%d ier=%x\n", tp->t_open, inb(a0->a_port+IER)); ! 2117: } ! 2118: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.