|
|
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 <sys/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: if (x_sleep ((char *) & tp->t_open, pritty, slpriSigCatch, ! 466: "asyblk") == PROCESS_SIGNALLED) { ! 467: #else ! 468: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, SVTTOUT, ! 469: "asyblk"); ! 470: if (nondsig ()) { /* signal? */ ! 471: #endif ! 472: u.u_error = EINTR; ! 473: goto bad_open; ! 474: } ! 475: } ! 476: ! 477: /* ! 478: * If channel not in use, mark it as such. ! 479: */ ! 480: if (a1->a_in_use == 0) { ! 481: /* ! 482: * Save modes for this open attempt to avoid future conflicts. ! 483: * Then start asycycle() for this port. ! 484: */ ! 485: if (dev & NMODC) { ! 486: tp->t_flags &= ~T_MODC; ! 487: a1->a_modc = 0; ! 488: } else { ! 489: tp->t_flags |= T_MODC; ! 490: a1->a_modc = 1; ! 491: } ! 492: if (dev & CPOLL) ! 493: a1->a_irq = 0; ! 494: else ! 495: a1->a_irq = 1; ! 496: if (dev & CFLOW) { ! 497: tp->t_flags |= T_CFLOW; ! 498: a1->a_flc = 1; ! 499: } else { ! 500: tp->t_flags &= ~T_CFLOW; ! 501: a1->a_flc = 0; ! 502: } ! 503: } ! 504: a1->a_in_use++; ! 505: ! 506: /* ! 507: * From here, error exit is bad_open_u. ! 508: */ ! 509: ! 510: if (tp->t_open == 0) { /* not already open */ ! 511: silo_t * in_silo = &a1->a_in; ! 512: ! 513: if (!(dev & CPOLL)) { ! 514: upd_irq1(a0->a_irqno); ! 515: a1->a_has_irq = 1; ! 516: } ! 517: ! 518: /* ! 519: * Need to start cycling to scan for CD. ! 520: */ ! 521: asycycle(chan); ! 522: ! 523: s = sphi(); ! 524: /* ! 525: * Raise basic modem control lines even if modem ! 526: * control hasn't been specified. ! 527: * MC_OUT2 turns on NON-open-collector IRQ line from the UART. ! 528: * since we can't have two UART's on same IRQ with MC_OUT2 on ! 529: */ ! 530: mcr = MC_RTS | MC_DTR; ! 531: if (dev & CPOLL) { ! 532: outb(port+MCR, mcr); ! 533: } else { ! 534: outb(port+MCR, mcr | a0->a_outs); ! 535: outb(port+IER, IEN); ! 536: } ! 537: ! 538: if ((dev & NMODC) == 0) { /* want modem control? */ ! 539: tp->t_flags |= T_HOPEN | T_STOP; ! 540: for (;;) { /* wait for carrier */ ! 541: msr = inb(port+MSR); ! 542: /* ! 543: * If carrier detect present ! 544: * if port not already open ! 545: * break out of loop and finish first open ! 546: * else ! 547: * do second (or third, etc.) open ! 548: */ ! 549: if (msr & MS_RLSD) ! 550: break; ! 551: /* wait for carrier */ ! 552: #ifdef _I386 ! 553: if (x_sleep ((char *) & tp->t_open, pritty, ! 554: slpriSigCatch, "need CD") ! 555: == PROCESS_SIGNALLED) { ! 556: #else ! 557: v_sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, ! 558: SVTTOUT, "need CD"); ! 559: if (nondsig ()) { /* signal? */ ! 560: #endif ! 561: outb(port+MCR, 0); ! 562: outb(port+IER, 0); ! 563: u.u_error = EINTR; ! 564: tp->t_flags &= ~(T_HOPEN | T_STOP); ! 565: spl(s); ! 566: goto bad_open_u; ! 567: } ! 568: } ! 569: ! 570: /* ! 571: * Mark that we are no longer hanging in open. ! 572: * Allow output over the port unless hardware flow ! 573: * control says not to. ! 574: */ ! 575: tp->t_flags &= ~T_HOPEN; ! 576: tp->t_flags &= ~T_STOP; ! 577: if (!(tp->t_flags & T_CFLOW) || (msr & MS_CTS)) ! 578: a1->a_ohlt = 0; ! 579: else ! 580: a1->a_ohlt = 1; ! 581: ! 582: /* ! 583: * Awaken any other opens on same device. ! 584: */ ! 585: wakeup((char *)(&tp->t_open)); ! 586: } ! 587: ttopen(tp); /* stty inits */ ! 588: tp->t_flags |= T_CARR; ! 589: if (ASY_HPCL) ! 590: tp->t_flags |= T_HPCL; ! 591: ! 592: asyparam(tp); /* gimmick: do this while t_open is zero */ ! 593: ! 594: /* ! 595: * TO DO: flush UART input register(s). ! 596: */ ! 597: ! 598: spl(s); ! 599: ! 600: /* ! 601: * Turn on polling for the port. ! 602: */ ! 603: if (dev & CPOLL) { ! 604: a1->a_poll = 1; ! 605: asyspr(); ! 606: } ! 607: } /* end of first-open case */ ! 608: ! 609: tp->t_open++; ! 610: T_HAL(0x400, printf("ch%d open + %d\n", chan, tp->t_open)); ! 611: ttsetgrp(tp, dev, mode); ! 612: ! 613: return; ! 614: ! 615: bad_open_u: ! 616: a1->a_in_use--; ! 617: wakeup((char *)(&tp->t_open)); ! 618: bad_open: ! 619: return; ! 620: } ! 621: ! 622: /* ! 623: * asyclose() ! 624: */ ! 625: static void ! 626: asyclose(dev, mode) ! 627: dev_t dev; ! 628: int mode; ! 629: { ! 630: int chan = channel(dev); ! 631: asy0_t *a0 = asy0 + chan; ! 632: asy1_t *a1 = asy1 + chan; ! 633: TTY *tp = &a1->a_tty; ! 634: silo_t * out_silo = &a1->a_out; ! 635: silo_t * in_silo = &a1->a_in; ! 636: int flags, maj; ! 637: int s; ! 638: short port = a0->a_port; ! 639: char lsr; ! 640: ! 641: if (--tp->t_open) ! 642: goto not_last_close; ! 643: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open)); ! 644: s = sphi(); ! 645: ! 646: a1->a_hcls = 1; /* disallow reopen til done closing */ ! 647: flags = tp->t_flags; /* save flags - ttclose zeroes them */ ! 648: ttclose(tp); ! 649: ! 650: /* ! 651: * Wait for output silo and UART xmit buffer to empty. ! 652: * Allow signal to break the sleep. ! 653: */ ! 654: for (;;) { ! 655: int chipEmpty = 0, siloEmpty = 0; ! 656: ! 657: lsr = inb(port + LSR); ! 658: chipEmpty = (lsr & LS_TxIDLE); ! 659: T_HAL(0x400, printf("ch%d chipEmpty=%d\n", chan, chipEmpty)); ! 660: siloEmpty = (out_silo->si_ix == out_silo->si_ox); ! 661: T_HAL(0x400, printf("ch%d siloEmpty=%d\n", chan, siloEmpty)); ! 662: ! 663: if (chipEmpty && siloEmpty) ! 664: break; ! 665: need_wake[chan] |= NW_OUTSILO; ! 666: #ifdef _I386 ! 667: if (x_sleep ((char *) out_silo, pritty, slpriSigCatch, ! 668: "asyclose") == PROCESS_SIGNALLED) { ! 669: #else ! 670: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT, ! 671: "asyclose"); ! 672: if (nondsig ()) { /* signal? */ ! 673: #endif ! 674: RAWOUT_FLUSH(out_silo); ! 675: break; ! 676: } ! 677: } ! 678: need_wake[chan] &= ~NW_OUTSILO; ! 679: ! 680: /* ! 681: * If not hanging in open ! 682: */ ! 683: if ((flags & T_HOPEN) == 0) { ! 684: /* ! 685: * Disable interrupts. ! 686: */ ! 687: outb(port+IER, 0); ! 688: outb(port+MCR, inb(port+MCR) & ~MC_OUTS); ! 689: } ! 690: ! 691: /* ! 692: * If hupcls ! 693: */ ! 694: if (flags & T_HPCL) { ! 695: T_HAL(0x400, printf("ch%d drop DTR\n", chan)); ! 696: /* ! 697: * Hangup port - drop DTR and RTS. ! 698: */ ! 699: outb(port+MCR, inb(port+MCR) & MC_OUTS); ! 700: ! 701: /* ! 702: * Hold dtr low for timeout ! 703: */ ! 704: maj = major(dev); ! 705: drvl[maj].d_time = 1; ! 706: #ifdef _I386 ! 707: x_sleep ((char *) & drvl [maj].d_time, pritty, slpriNoSig, ! 708: "drop DTR"); ! 709: #else ! 710: v_sleep((char *)&drvl[maj].d_time, CVTTOUT, IVTTOUT, SVTTOUT, ! 711: "drop DTR"); ! 712: #endif ! 713: drvl[maj].d_time = 0; ! 714: } ! 715: ! 716: a1->a_poll = 0; ! 717: asyspr(); ! 718: RAWIN_FLUSH(in_silo); ! 719: a1->a_hcls = 0; /* allow reopen - done closing */ ! 720: wakeup((char *)(&tp->t_open)); ! 721: spl(s); ! 722: a1->a_in_use--; ! 723: ! 724: if (!(dev & CPOLL)) ! 725: upd_irq1(a0->a_irqno); ! 726: return; ! 727: ! 728: not_last_close: ! 729: T_HAL(0x400, printf("ch%d open - %d\n", chan, tp->t_open)); ! 730: a1->a_in_use--; ! 731: wakeup((char *)(&tp->t_open)); ! 732: return; ! 733: } ! 734: ! 735: /* ! 736: * asyread() ! 737: */ ! 738: static void ! 739: asyread(dev, iop) ! 740: dev_t dev; ! 741: register IO * iop; ! 742: { ! 743: int chan = channel(dev); ! 744: asy1_t *a1 = asy1 + chan; ! 745: TTY *tp = &a1->a_tty; ! 746: ! 747: ttread(tp, iop); ! 748: } ! 749: ! 750: /* ! 751: * asytimer() ! 752: */ ! 753: static void ! 754: asytimer(dev) ! 755: dev_t dev; ! 756: { ! 757: if (++drvl[major(dev)].d_time > DTRTMOUT) ! 758: wakeup((char *)&drvl[major(dev)].d_time); ! 759: } ! 760: ! 761: /* ! 762: * asywrite() ! 763: */ ! 764: static void ! 765: asywrite(dev, iop) ! 766: dev_t dev; ! 767: register IO * iop; ! 768: { ! 769: int chan = channel(dev); ! 770: asy0_t *a0 = asy0 + chan; ! 771: asy1_t *a1 = asy1 + chan; ! 772: TTY *tp = &a1->a_tty; ! 773: short port = a0->a_port; ! 774: register int c; ! 775: ! 776: /* ! 777: * Treat user writes through tty driver. ! 778: */ ! 779: if (iop->io_seg != IOSYS) { ! 780: ttwrite(tp, iop); ! 781: return; ! 782: } ! 783: ! 784: /* ! 785: * Treat kernel writes by blocking on transmit buffer. ! 786: */ ! 787: while ((c = iogetc(iop)) >= 0) { ! 788: /* ! 789: * Wait until transmit buffer is empty. ! 790: * Check twice to prevent critical race with interrupt handler. ! 791: */ ! 792: for (;;) { ! 793: if (inb(port+LSR) & LS_TxRDY) ! 794: if (inb(port+LSR) & LS_TxRDY) ! 795: break; ! 796: } ! 797: ! 798: /* ! 799: * Output the next character. ! 800: */ ! 801: outb(port+DREG, c); ! 802: } ! 803: } ! 804: ! 805: /* ! 806: * asyioctl() ! 807: */ ! 808: static void ! 809: asyioctl(dev, com, vec) ! 810: dev_t dev; ! 811: int com; struct sgttyb *vec; ! 812: { ! 813: int chan = channel(dev); ! 814: asy0_t *a0 = asy0 + chan; ! 815: asy1_t *a1 = asy1 + chan; ! 816: TTY *tp = &a1->a_tty; ! 817: int s; ! 818: int temp; ! 819: silo_t *out_silo = &a1->a_out; ! 820: silo_t *in_silo = &a1->a_in; ! 821: short port = a0->a_port; ! 822: unsigned char msr, mcr, lcr, ier; ! 823: char do_ttioctl = 0; ! 824: char do_asyparam = 0; ! 825: ! 826: s = sphi(); ! 827: ier = inb(port+IER); ! 828: mcr = inb(port+MCR); /* get current MCR register status */ ! 829: lcr = inb(port+LCR); /* get current LCR register status */ ! 830: ! 831: #ifdef _I386 ! 832: /* ! 833: * If command will drain output, do the drain now ! 834: * before calling ttioctl(). ! 835: * Don't do this for 286 kernel: we're running out of code space. ! 836: */ ! 837: switch(com) { ! 838: case TCSETAW: ! 839: case TCSETAF: ! 840: case TCSBRK: ! 841: case TIOCSETP: ! 842: /* ! 843: * Wait for output silo and UART xmit buffer to empty. ! 844: * Allow signal to break the sleep. ! 845: */ ! 846: for (;;) { ! 847: if (!ttoutp(tp) ! 848: && (out_silo->si_ix == out_silo->si_ox) ! 849: && (inb(port + LSR) & LS_TxIDLE)) ! 850: break; ! 851: need_wake[chan] |= NW_OUTSILO; ! 852: #ifdef _I386 ! 853: if (x_sleep ((char *) out_silo, pritty, slpriSigCatch, ! 854: "asydrain") == PROCESS_SIGNALLED) { ! 855: #else ! 856: v_sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT, ! 857: "asydrain"); ! 858: if (nondsig ()) { /* signal? */ ! 859: #endif ! 860: break; ! 861: } ! 862: } ! 863: need_wake[chan] &= ~NW_OUTSILO; ! 864: } ! 865: #endif ! 866: ! 867: switch(com) { ! 868: case TIOCSBRK: /* set BREAK */ ! 869: outb(port+LCR, lcr|LC_SBRK); ! 870: break; ! 871: case TIOCCBRK: /* clear BREAK */ ! 872: outb(port+LCR, lcr & ~LC_SBRK); ! 873: break; ! 874: case TIOCSDTR: /* set DTR */ ! 875: outb(port+MCR, mcr|MC_DTR); ! 876: break; ! 877: case TIOCCDTR: /* clear DTR */ ! 878: outb(port+MCR, mcr & ~MC_DTR); ! 879: break; ! 880: case TIOCSRTS: /* set RTS */ ! 881: outb(port+MCR, mcr|MC_RTS); ! 882: break; ! 883: case TIOCCRTS: /* clear RTS */ ! 884: outb(port+MCR, mcr & ~MC_RTS); ! 885: break; ! 886: case TIOCRSPEED: /* set "raw" I/O speed divisor */ ! 887: outb(port+LCR, lcr|LC_DLAB); /* set speed latch bit */ ! 888: outb(port+DLL, (unsigned) vec); ! 889: outb(port+DLH, (unsigned) vec >> 8); ! 890: outb(port+LCR, lcr); /* reset latch bit */ ! 891: break; ! 892: case TIOCWORDL: /* set word length and stop bits */ ! 893: outb(port+LCR, ((lcr&~0x7) | ((unsigned) vec & 0x7))); ! 894: break; ! 895: case TIOCRMSR: /* get CTS/DSR/RI/RLSD (MSR) */ ! 896: msr = inb(port+MSR); ! 897: temp = msr >> 4; ! 898: kucopy(&temp, (unsigned *) vec, sizeof(unsigned)); ! 899: break; ! 900: case TIOCFLUSH: /* Flush silos here, queues in tty.c */ ! 901: RAWIN_FLUSH(in_silo); ! 902: RAWOUT_FLUSH(out_silo); ! 903: do_ttioctl = 1; ! 904: break; ! 905: ! 906: /* ! 907: * If port parameters change, plan to call asyparam(). ! 908: * Need to check now before structs are updated. ! 909: */ ! 910: #ifdef _I386 ! 911: case TCSETA: ! 912: case TCSETAW: ! 913: case TCSETAF: ! 914: { ! 915: struct termio trm; ! 916: ! 917: ukcopy(vec, &trm, sizeof(struct termio)); ! 918: if (trm.c_cflag != tp->t_termio.c_cflag) ! 919: do_asyparam = 1; ! 920: } ! 921: do_ttioctl = 1; ! 922: break; ! 923: #endif ! 924: case TIOCSETP: ! 925: case TIOCSETN: ! 926: { ! 927: struct sgttyb sg; ! 928: ! 929: ukcopy(vec, &sg, sizeof(struct sgttyb)); ! 930: if (sg.sg_ispeed != tp->t_sgttyb.sg_ispeed ! 931: || ((sg.sg_flags ^ tp->t_sgttyb.sg_flags) & ANYP)) ! 932: do_asyparam = 1; ! 933: } ! 934: do_ttioctl = 1; ! 935: break; ! 936: default: ! 937: do_ttioctl = 1; ! 938: } ! 939: outb(port+IER, ier); ! 940: if (do_ttioctl) ! 941: ttioctl(tp, com, vec); ! 942: spl(s); ! 943: if (do_asyparam) ! 944: asyparam(tp); ! 945: #ifdef _I386 ! 946: /* ! 947: * Things to be done after calling ttioctl(). ! 948: */ ! 949: switch(com) { ! 950: case TCSBRK: ! 951: /* ! 952: * Send 0.25 second break: ! 953: * 1. Turn on break level. ! 954: * 2. Set timer to turn off break level 0.25 sec later. ! 955: * 3. Sleep till timer expires. ! 956: * 4. Turn off break level. ! 957: */ ! 958: outb(port+LCR, lcr|LC_SBRK); ! 959: a1->a_brk = 1; ! 960: timeout(&tp->t_sbrk, HZ/4, endbrk, chan); ! 961: while(a1->a_brk) { ! 962: #ifdef _I386 ! 963: x_sleep (a1, pritty, slpriNoSig, "asybreak"); ! 964: #else ! 965: v_sleep(a1, CVTTOUT, IVTTOUT, SVTTOUT, "asybreak"); ! 966: #endif ! 967: } ! 968: outb(port+LCR, lcr & ~LC_SBRK); ! 969: } ! 970: #endif ! 971: } ! 972: ! 973: #ifdef _I386 ! 974: /* ! 975: * Turn off the break level. ! 976: * Called from timeout after ioctl(fd, TCSBRK, 0). ! 977: */ ! 978: void ! 979: endbrk(chan) ! 980: int chan; ! 981: { ! 982: asy1_t *a1 = asy1 + chan; ! 983: ! 984: a1->a_brk = 0; ! 985: wakeup(a1); ! 986: } ! 987: #endif ! 988: ! 989: /* ! 990: * asyparam() ! 991: */ ! 992: static void ! 993: asyparam(tp) ! 994: TTY * tp; ! 995: { ! 996: int chan = (int)tp->t_ddp; ! 997: asy0_t *a0 = asy0 + chan; ! 998: asy1_t *a1 = asy1 + chan; ! 999: short port = a0->a_port; ! 1000: int s; ! 1001: int write_baud=1, write_lcr=1; ! 1002: unsigned char mcr, newlcr, speed, oldSpeed; ! 1003: ! 1004: #ifdef _I386 ! 1005: unsigned short cflag = tp->t_termio.c_cflag; ! 1006: ! 1007: T_HAL(4, printf("ch%d asyparam cflag=%x\n", chan, cflag)); ! 1008: speed = cflag & CBAUD; ! 1009: switch (cflag & CSIZE) { ! 1010: case CS5: newlcr = LC_CS5; break; ! 1011: case CS6: newlcr = LC_CS6; break; ! 1012: case CS7: newlcr = LC_CS7; break; ! 1013: case CS8: newlcr = LC_CS8; break; ! 1014: } ! 1015: if (cflag & CSTOPB) ! 1016: newlcr |= LC_STOPB; ! 1017: if (cflag & PARENB) { ! 1018: newlcr |= LC_PARENB; ! 1019: if ((cflag & PARODD) == 0) ! 1020: newlcr |= LC_PAREVEN; ! 1021: } ! 1022: #else ! 1023: speed = tp->t_sgttyb.sg_ispeed; ! 1024: switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) { ! 1025: case ODDP: ! 1026: newlcr = LC_CS7|LC_PARENB; ! 1027: break; ! 1028: case EVENP: ! 1029: newlcr = LC_CS7|LC_PARENB|LC_PAREVEN; ! 1030: break; ! 1031: default: ! 1032: newlcr = LC_CS8; ! 1033: break; ! 1034: } ! 1035: #endif ! 1036: ! 1037: /* ! 1038: * Don't bang on the UART needlessly. ! 1039: * Writing baud rate resets the port, which loses characters. ! 1040: * You want this on first open, NOT on later opens. ! 1041: */ ! 1042: oldSpeed = a0->a_speed; ! 1043: if (speed == oldSpeed && tp->t_open) { ! 1044: write_baud = 0; ! 1045: if (newlcr == a1->a_lcr) { ! 1046: write_lcr = 0; ! 1047: } ! 1048: } ! 1049: a0->a_speed = speed; ! 1050: a1->a_lcr = newlcr; ! 1051: ! 1052: if (write_lcr) { ! 1053: char ier_save; ! 1054: s = sphi(); ! 1055: ier_save = inb(port+IER); ! 1056: if (write_baud) { ! 1057: if (speed) { ! 1058: short divisor = albaud[speed]; ! 1059: ! 1060: if (oldSpeed == 0) { ! 1061: /* if previous baud rate was zero, ! 1062: * need to go off hook. */ ! 1063: mcr = inb(port+MCR) | (MC_RTS | MC_DTR); ! 1064: outb(port+MCR, mcr); ! 1065: } ! 1066: T_HAL(4, printf("CH%d speed=%x\n", chan, speed)); ! 1067: outb(port+LCR, LC_DLAB); ! 1068: outb(port+DLL, divisor); ! 1069: outb(port+DLH, divisor >> 8); ! 1070: } else { ! 1071: /* Baud rate of zero means hang up. */ ! 1072: mcr = inb(port+MCR) & ~(MC_RTS | MC_DTR); ! 1073: outb(port+MCR, mcr); ! 1074: } ! 1075: } ! 1076: T_HAL(4, printf("CH%d newlcr=%x\n", chan, newlcr)); ! 1077: outb(port+LCR, newlcr); ! 1078: if (a1->a_ut == US_16550A) ! 1079: outb(port+FCR, FC_ENABLE | FC_Rx_RST | FC_Rx_08); ! 1080: outb(port+IER, ier_save); ! 1081: spl(s); ! 1082: } ! 1083: if (write_baud) ! 1084: asyspr(); ! 1085: } ! 1086: ! 1087: /* ! 1088: * asystart() ! 1089: */ ! 1090: static void ! 1091: asystart(tp) ! 1092: TTY * tp; ! 1093: { ! 1094: int chan = (int)tp->t_ddp; ! 1095: asy0_t *a0 = asy0 + chan; ! 1096: asy1_t *a1 = asy1 + chan; ! 1097: short port = a0->a_port; ! 1098: int s; ! 1099: int need_xmit = 1; /* True if should start sending data now. */ ! 1100: silo_t *out_silo = &a1->a_out; ! 1101: char lsr; ! 1102: ! 1103: /* ! 1104: * Read line status register AFTER disabling interrupts. ! 1105: */ ! 1106: s = sphi(); ! 1107: lsr = inb(port + LSR); ! 1108: ! 1109: /* ! 1110: * Process break indication. ! 1111: * NOTE: Break indication cleared when line status register was read. ! 1112: */ ! 1113: if (lsr & LS_BREAK) ! 1114: defer(asybreak, chan); ! 1115: ! 1116: /* ! 1117: * If no output data, it may be time to finish closing the port; ! 1118: * but won't need another xmit interrupt. ! 1119: */ ! 1120: if (out_silo->si_ix == out_silo->si_ox) { ! 1121: if (need_wake[chan] & NW_OUTSILO) { ! 1122: need_wake[chan] &= ~NW_OUTSILO; ! 1123: wakeup((char *)out_silo); ! 1124: } ! 1125: need_xmit = 0; ! 1126: } ! 1127: ! 1128: /* ! 1129: * Do nothing if output is stopped. ! 1130: */ ! 1131: if (tp->t_flags & T_STOP) ! 1132: need_xmit = 0; ! 1133: if (a1->a_ohlt) ! 1134: need_xmit = 0; ! 1135: ! 1136: /* ! 1137: * Start data transmission by writing to UART xmit reg. ! 1138: */ ! 1139: if ((lsr & LS_TxRDY) && need_xmit) { ! 1140: int xmit_count; ! 1141: xmit_count = (a1->a_ut == US_16550A)?16:1; ! 1142: asy_send(out_silo, port+DREG, xmit_count); ! 1143: } ! 1144: spl(s); ! 1145: } ! 1146: ! 1147: /* ! 1148: * asypoll() ! 1149: */ ! 1150: static int ! 1151: asypoll(dev, ev, msec) ! 1152: dev_t dev; ! 1153: int ev; ! 1154: int msec; ! 1155: { ! 1156: int chan = channel(dev); ! 1157: asy1_t *a1 = asy1 + chan; ! 1158: TTY *tp = &a1->a_tty; ! 1159: ! 1160: return ttpoll(tp, ev, msec); ! 1161: } ! 1162: ! 1163: /* ! 1164: * asycycle() ! 1165: * ! 1166: * Do a wakeup of any sleeping asy's at regular intervals. ! 1167: */ ! 1168: static void ! 1169: asycycle(chan) ! 1170: int chan; ! 1171: { ! 1172: asy0_t *a0 = asy0 + chan; ! 1173: asy1_t *a1 = asy1 + chan; ! 1174: TTY *tp = &a1->a_tty; ! 1175: short port = a0->a_port; ! 1176: int s; ! 1177: char msr, mcr; ! 1178: silo_t *out_silo = &a1->a_out; ! 1179: silo_t *in_silo = &a1->a_in; ! 1180: int n, ch; ! 1181: int do_start = 1; ! 1182: unsigned char iir; ! 1183: ! 1184: /* ! 1185: * Check Carrier Detect (RLSD). ! 1186: * ! 1187: * Modem status interrupts were not enabled due to 8250 hardware bug. ! 1188: * Enabling modem status and receive interrupts may cause lockup ! 1189: * on older parts. ! 1190: */ ! 1191: if (tp->t_flags & T_MODC) { ! 1192: ! 1193: /* ! 1194: * Get status ! 1195: */ ! 1196: msr = inb(port+MSR); ! 1197: ! 1198: /* ! 1199: * Carrier changed. ! 1200: */ ! 1201: if ((msr & MS_RLSD) && !(tp->t_flags & T_CARR)) { ! 1202: /* ! 1203: * Carrier is on - wakeup open. ! 1204: */ ! 1205: s = sphi(); ! 1206: tp->t_flags |= T_CARR; ! 1207: spl(s); ! 1208: wakeup((char *)(&tp->t_open)); ! 1209: } ! 1210: ! 1211: if (!(msr & MS_RLSD) && (tp->t_flags & T_CARR)) { ! 1212: s = sphi(); ! 1213: RAWIN_FLUSH(in_silo); ! 1214: RAWOUT_FLUSH(out_silo); ! 1215: tp->t_flags &= ~T_CARR; ! 1216: spl(s); ! 1217: tthup(tp); ! 1218: } ! 1219: } ! 1220: ! 1221: /* ! 1222: * Empty raw input buffer. ! 1223: * ! 1224: * The line discipline module (tty.c) will set T_ISTOP true when the ! 1225: * tt input queue is nearly full (tp->t_iq.cq_cc >= IHILIM), and make ! 1226: * T_ISTOP false when it's ready for more input. ! 1227: * ! 1228: * When T_ISTOP is true, ttin() simply discards the character passed. ! 1229: */ ! 1230: if (!(tp->t_flags & T_ISTOP)) { ! 1231: while (in_silo->SILO_CHAR_COUNT > 0) { ! 1232: s = sphi(); ! 1233: ttin(tp, in_silo->si_buf[in_silo->si_ox]); ! 1234: if (in_silo->si_ox < MAX_SILO_INDEX) ! 1235: in_silo->si_ox++; ! 1236: else ! 1237: in_silo->si_ox = 0; ! 1238: in_silo->SILO_CHAR_COUNT--; ! 1239: spl(s); ! 1240: } ! 1241: } ! 1242: ! 1243: /* ! 1244: * Hardware flow control. ! 1245: * Check CTS to see if we need to halt output. ! 1246: * (MS_INTR should have done this - repeat code here to be sure) ! 1247: * Check input silo to see if we need to raise RTS. ! 1248: */ ! 1249: if (tp->t_flags & T_CFLOW) { ! 1250: ! 1251: /* ! 1252: * Get status ! 1253: */ ! 1254: msr = inb(port+MSR); ! 1255: s = sphi(); ! 1256: if (msr & MS_CTS) ! 1257: a1->a_ohlt = 0; ! 1258: else ! 1259: a1->a_ohlt = 1; ! 1260: spl(s); ! 1261: #if 0 ! 1262: /* ! 1263: * NIGEL: From now on, trace macros need to be given expressions. This ! 1264: * one needs some work to fix... ! 1265: */ ! 1266: T_HAL(4, {static cts = 0; if (!cts && (msr & MS_CTS)) { cts = 1; putchar('[');\ ! 1267: } else if (cts && !(msr & MS_CTS)) { cts = 0; putchar(']'); }}); ! 1268: #endif ! 1269: ! 1270: /* ! 1271: * If using hardware flow control, see if we need to drop RTS. ! 1272: */ ! 1273: if ((tp->t_flags & T_CFLOW) ! 1274: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 1275: s = sphi(); ! 1276: mcr = inb(port+MCR); ! 1277: if (mcr & MC_RTS) { ! 1278: outb(port+MCR, mcr & ~MC_RTS); ! 1279: T_HAL(4, putchar('-')); ! 1280: } ! 1281: spl(s); ! 1282: } ! 1283: ! 1284: /* ! 1285: * If input silo below low mark, assert RTS. ! 1286: */ ! 1287: if (in_silo->SILO_CHAR_COUNT <= SILO_LOW_MARK) { ! 1288: s = sphi(); ! 1289: mcr = inb(port+MCR); ! 1290: if ((mcr & MC_RTS) == 0) { ! 1291: outb(port+MCR, mcr | MC_RTS); ! 1292: T_HAL(4, putchar('+')); ! 1293: } ! 1294: spl(s); ! 1295: } ! 1296: } ! 1297: ! 1298: /* ! 1299: * Calculate free output slot count. ! 1300: */ ! 1301: n = sizeof(out_silo->si_buf) - 1; ! 1302: n += out_silo->si_ox - out_silo->si_ix; ! 1303: n %= sizeof(out_silo->si_buf); ! 1304: ! 1305: /* ! 1306: * Fill raw output buffer. ! 1307: */ ! 1308: for (;;) { ! 1309: if (--n < 0) ! 1310: break; ! 1311: s = sphi(); ! 1312: ch = ttout(tp); ! 1313: spl(s); ! 1314: if (ch < 0) ! 1315: break; ! 1316: ! 1317: s = sphi(); ! 1318: out_silo->si_buf[out_silo->si_ix] = ch; ! 1319: if (out_silo->si_ix >= sizeof(out_silo->si_buf) - 1) ! 1320: out_silo->si_ix = 0; ! 1321: else ! 1322: out_silo->si_ix++; ! 1323: spl(s); ! 1324: } ! 1325: ! 1326: #ifdef _I386 ! 1327: /* ! 1328: * if port has an interrupt pending (probably missed an irq) ! 1329: * the following two loops should not be merged ! 1330: * - need ALL port irq's inactive at once ! 1331: * for each port on this irq line (use irq1 for this) ! 1332: * disable interrupts (clear IER) ! 1333: * for each port on this irq line ! 1334: * restore interrupts ! 1335: */ ! 1336: if (a1->a_has_irq && ((iir=inb(port+IIR)) & 1) == 0) { ! 1337: struct irqnode *ip; ! 1338: asy_gp_t *gp; ! 1339: int s; ! 1340: short p; ! 1341: char c, slot; ! 1342: ! 1343: T_HAL(4, printf("CH%d missed iir:x\n", chan, iir)); ! 1344: ! 1345: do_start = 0; ! 1346: s = sphi(); ! 1347: ip = irq1[a0->a_irqno]; ! 1348: while(ip) { ! 1349: if (ip->func == asyintr) { ! 1350: p = ip->arg; ! 1351: outb(p + IER, 0); ! 1352: } else { ! 1353: gp = asy_gp + ip->arg; ! 1354: for (slot = 0; slot < MAX_SLOTS; slot++) { ! 1355: if ((c=gp->chan_list[slot]) < MAX_ASY){ ! 1356: p = asy0[c].a_port; ! 1357: outb(p + IER, 0); ! 1358: } ! 1359: } ! 1360: } ! 1361: ip = ip->next_actv; ! 1362: } ! 1363: /* ! 1364: * Now, all ports on the offending irq line have irq off. ! 1365: */ ! 1366: ip = irq1[a0->a_irqno]; ! 1367: while(ip) { ! 1368: if (ip->func == asyintr) { ! 1369: p = ip->arg; ! 1370: outb(p + IER, IEN); ! 1371: } else { ! 1372: gp = asy_gp + ip->arg; ! 1373: for (slot = 0; slot < MAX_SLOTS; slot++) { ! 1374: if ((c=gp->chan_list[slot]) < MAX_ASY){ ! 1375: p = asy0[c].a_port; ! 1376: outb(p + IER, IEN); ! 1377: } ! 1378: } ! 1379: } ! 1380: ip = ip->next_actv; ! 1381: } ! 1382: spl(s); ! 1383: } ! 1384: #endif ! 1385: ! 1386: if(do_start) ! 1387: ttstart(tp); ! 1388: ! 1389: /* ! 1390: * Schedule next cycle. ! 1391: */ ! 1392: if (a1->a_in_use) { ! 1393: timeout(&tp->t_rawtim, HZ/10, asycycle, chan); ! 1394: } ! 1395: } ! 1396: ! 1397: /* ! 1398: * irqdummy() ! 1399: * ! 1400: * Suppress interrupts that may occur during chip sensing. ! 1401: */ ! 1402: static void ! 1403: irqdummy() ! 1404: { ! 1405: /* ! 1406: * Try to clear all pending interrupts. ! 1407: */ ! 1408: inb(dummy_port+IIR); ! 1409: inb(dummy_port+LSR); ! 1410: inb(dummy_port+MSR); ! 1411: inb(dummy_port+DREG); ! 1412: } ! 1413: ! 1414: /* ! 1415: * add_irq() ! 1416: * ! 1417: * Given channel number, add port info to irq0 list. ! 1418: */ ! 1419: static void ! 1420: add_irq(irq, func, arg) ! 1421: int irq; ! 1422: void (*func)(); ! 1423: int arg; ! 1424: { ! 1425: struct irqnode * np; ! 1426: ! 1427: /* ! 1428: * Sanity check. ! 1429: */ ! 1430: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0) ! 1431: return; ! 1432: ! 1433: if (nextnode < MAX_ASY) { ! 1434: np = nodespace + nextnode++; ! 1435: np->func = func; ! 1436: np->arg = arg; ! 1437: np->next = irq0[irq]; ! 1438: irq0[irq] = np; ! 1439: } else { ! 1440: printf("asy: too many irq nodes (%d)\n", nextnode); ! 1441: } ! 1442: } ! 1443: ! 1444: /* ! 1445: * Interrupt handlers. ! 1446: */ ! 1447: static void i2() { asy_irq(irq1[2]); } ! 1448: static void i3() { asy_irq(irq1[3]); } ! 1449: static void i4() { asy_irq(irq1[4]); } ! 1450: static void i5() { asy_irq(irq1[5]); } ! 1451: static void i6() { asy_irq(irq1[6]); } ! 1452: static void i7() { asy_irq(irq1[7]); } ! 1453: static void i8() { asy_irq(irq1[8]); } ! 1454: static void i9() { asy_irq(irq1[9]); } ! 1455: static void i10() { asy_irq(irq1[10]); } ! 1456: static void i11() { asy_irq(irq1[11]); } ! 1457: static void i12() { asy_irq(irq1[12]); } ! 1458: static void i13() { asy_irq(irq1[13]); } ! 1459: static void i14() { asy_irq(irq1[14]); } ! 1460: static void i15() { asy_irq(irq1[15]); } ! 1461: ! 1462: /* ! 1463: * asy_irq() ! 1464: * ! 1465: * Given pointer to node list, service async interrupt. ! 1466: */ ! 1467: static void ! 1468: asy_irq(ip) ! 1469: struct irqnode * ip; ! 1470: { ! 1471: struct irqnode *here; ! 1472: int doit; ! 1473: ! 1474: do { ! 1475: doit = 0; ! 1476: here = ip; ! 1477: while(here) { ! 1478: doit |= (*(here->func))(here->arg); ! 1479: here = here->next_actv; ! 1480: } ! 1481: } while(doit); ! 1482: } ! 1483: ! 1484: /* ! 1485: * upd_irq1() ! 1486: * ! 1487: * Given an irq number, rebuild the links for active devices. ! 1488: */ ! 1489: static void ! 1490: upd_irq1(irq) ! 1491: int irq; ! 1492: { ! 1493: struct irqnode *np; ! 1494: asy1_t *a1; ! 1495: int chan; ! 1496: int s; ! 1497: ! 1498: /* ! 1499: * Sanity check. ! 1500: */ ! 1501: if (irq <=0 || irq >= NUM_IRQ || itbl[irq] == 0) ! 1502: return; ! 1503: ! 1504: /* ! 1505: * For each node in the irq0 list ! 1506: * if node is for irq status port ! 1507: * for each channel using the status port ! 1508: * if channel in use, in irq mode ! 1509: * add node to irq1 list ! 1510: * skip rest of channels for this node ! 1511: * else - node is for simple UART ! 1512: * if channel in use, in irq mode ! 1513: * add node to irq1 list ! 1514: */ ! 1515: s = sphi(); ! 1516: np = irq0[irq]; ! 1517: irq1[irq] = 0; ! 1518: while (np) { ! 1519: if (np->func != asyintr) { ! 1520: char ix, loop = 1; ! 1521: asy_gp_t *gp = asy_gp + np->arg; ! 1522: ! 1523: for (ix = 0; ix < MAX_SLOTS && loop; ix++) { ! 1524: if ((chan = gp->chan_list[ix]) < MAX_ASY) { ! 1525: a1 = asy1 + chan; ! 1526: if (a1->a_in_use && a1->a_irq) { ! 1527: np->next_actv = irq1[irq]; ! 1528: irq1[irq] = np; ! 1529: loop = 0; ! 1530: } ! 1531: } ! 1532: } ! 1533: } else { ! 1534: a1 = asy1 + np->arg; ! 1535: if (a1->a_in_use && a1->a_irq) { ! 1536: np->next_actv = irq1[irq]; ! 1537: irq1[irq] = np; ! 1538: } ! 1539: } ! 1540: np = np->next; ! 1541: } ! 1542: spl(s); ! 1543: } ! 1544: ! 1545: /* ! 1546: * asybreak() ! 1547: */ ! 1548: static void ! 1549: asybreak(chan) ! 1550: int chan; ! 1551: { ! 1552: int s; ! 1553: asy1_t *a1 = asy1 + chan; ! 1554: silo_t *out_silo = &a1->a_out; ! 1555: silo_t *in_silo = &a1->a_in; ! 1556: TTY *tp = &a1->a_tty; ! 1557: ! 1558: s = sphi(); ! 1559: RAWIN_FLUSH(in_silo); ! 1560: RAWOUT_FLUSH(out_silo); ! 1561: spl(s); ! 1562: ttsignal(tp, SIGINT); ! 1563: } ! 1564: ! 1565: /* ! 1566: * asyintr() ! 1567: * ! 1568: * Handle interrupt for a single channel. ! 1569: */ ! 1570: static int ! 1571: asyintr(chan) ! 1572: int chan; ! 1573: { ! 1574: asy0_t *a0 = asy0 + chan; ! 1575: asy1_t *a1 = asy1 + chan; ! 1576: TTY *tp = &a1->a_tty; ! 1577: silo_t *out_silo = &a1->a_out; ! 1578: silo_t *in_silo = &a1->a_in; ! 1579: int c, xmit_count; ! 1580: int ret = 0; ! 1581: short port = a0->a_port; ! 1582: unsigned char msr, lsr; ! 1583: ! 1584: if (chan >= MAX_ASY) { ! 1585: printf("asy: irq on channel %d\n", chan); ! 1586: return 0; ! 1587: } ! 1588: ! 1589: rescan: ! 1590: switch (inb(port+IIR) & 0x07) { ! 1591: ! 1592: case LS_INTR: ! 1593: ret = 1; ! 1594: lsr = inb(port + LSR); ! 1595: T_HAL(0x800, printf("[%d:L%x]", chan, lsr)); ! 1596: if (lsr & LS_BREAK) ! 1597: defer(asybreak, chan); ! 1598: goto rescan; ! 1599: ! 1600: case Rx_INTR: ! 1601: T_HAL(0x800, printf("[%d:R]", chan)); ! 1602: ret = 1; ! 1603: c = inb(port+DREG); ! 1604: if (tp->t_open == 0) ! 1605: goto rescan; ! 1606: /* ! 1607: * Must recognize XOFF quickly to avoid transmit overrun. ! 1608: * Recognize XON here as well to avoid race conditions. ! 1609: */ ! 1610: if (_IS_IXON_MODE (tp)) { ! 1611: /* ! 1612: * XON. ! 1613: */ ! 1614: #if _I386 ! 1615: if (_IS_START_CHAR (tp, c) || ! 1616: (_IS_IXANY_MODE (tp) && ! 1617: (tp->t_flags & T_STOP) != 0)) { ! 1618: tp->t_flags &= ~(T_STOP | T_XSTOP); ! 1619: goto rescan; ! 1620: } ! 1621: #else ! 1622: if (_IS_START_CHAR (tp, c)) { ! 1623: tp->t_flags &= ~T_STOP; ! 1624: goto rescan; ! 1625: } ! 1626: #endif ! 1627: ! 1628: /* ! 1629: * XOFF. ! 1630: */ ! 1631: if (_IS_STOP_CHAR (tp, c)) { ! 1632: tp->t_flags |= T_STOP; ! 1633: goto rescan; ! 1634: } ! 1635: } ! 1636: ! 1637: /* ! 1638: * Save char in raw input buffer. ! 1639: */ ! 1640: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) { ! 1641: in_silo->si_buf[in_silo->si_ix] = c; ! 1642: if (in_silo->si_ix < MAX_SILO_INDEX) ! 1643: in_silo->si_ix++; ! 1644: else ! 1645: in_silo->si_ix = 0; ! 1646: in_silo->SILO_CHAR_COUNT++; ! 1647: } ! 1648: ! 1649: /* ! 1650: * If using hardware flow control, see if we need to drop RTS. ! 1651: */ ! 1652: if ((tp->t_flags & T_CFLOW) ! 1653: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 1654: unsigned char mcr = inb(port+MCR); ! 1655: if (mcr & MC_RTS) { ! 1656: outb(port+MCR, mcr & ~MC_RTS); ! 1657: } ! 1658: } ! 1659: ! 1660: goto rescan; ! 1661: ! 1662: case Tx_INTR: ! 1663: T_HAL(0x800, printf("[%d:T]", chan)); ! 1664: ret = 1; ! 1665: /* ! 1666: * Do nothing if output is stopped. ! 1667: */ ! 1668: if (tp->t_flags & T_STOP) { ! 1669: goto rescan; ! 1670: } ! 1671: if (a1->a_ohlt) ! 1672: goto rescan; ! 1673: ! 1674: /* ! 1675: * Transmit next char in raw output buffer. ! 1676: */ ! 1677: xmit_count = (a1->a_ut == US_16550A)?16:1; ! 1678: asy_send(out_silo, port+DREG, xmit_count); ! 1679: goto rescan; ! 1680: ! 1681: case MS_INTR: ! 1682: ret = 1; ! 1683: /* ! 1684: * Get status (and clear interrupt). ! 1685: */ ! 1686: msr = inb(port+MSR); ! 1687: T_HAL(0x800, printf("[%d:M%x]", chan, msr)); ! 1688: ! 1689: /* ! 1690: * Hardware flow control. ! 1691: * Check CTS to see if we need to halt output. ! 1692: */ ! 1693: if (tp->t_flags & T_CFLOW) { ! 1694: if (msr & MS_CTS) ! 1695: a1->a_ohlt = 0; ! 1696: else ! 1697: a1->a_ohlt = 1; ! 1698: } ! 1699: ! 1700: goto rescan; ! 1701: default: ! 1702: return ret; ! 1703: } /* endswitch */ ! 1704: } ! 1705: ! 1706: /* ! 1707: * asyclk() ! 1708: * ! 1709: * Called every time T0 interrupts.- if it returns 0, ! 1710: * the usual system timer interrupt stuff is done. ! 1711: * Poll all pollable ports. ! 1712: */ ! 1713: static int ! 1714: asyclk() ! 1715: { ! 1716: static int count; ! 1717: int ix; ! 1718: ! 1719: for (ix = 0; ix < ppnum; ix++) ! 1720: asysph(pptbl[ix]); ! 1721: ! 1722: count++; ! 1723: if (count >= poll_divisor) ! 1724: count = 0; ! 1725: return count; ! 1726: } ! 1727: ! 1728: /* ! 1729: * asyspr() ! 1730: * ! 1731: * asyspr is called when a port is opened or closed or changes speed ! 1732: * It sets the polling rate only as fast as needed, and shuts off polling ! 1733: * whenever possible. ! 1734: * It updates the links in irq1[0], which lists polled-mode ports. ! 1735: */ ! 1736: static void ! 1737: asyspr() ! 1738: { ! 1739: asy0_t *a0; ! 1740: asy1_t *a1; ! 1741: int chan; ! 1742: int s; ! 1743: int ix, max_rate, port_rate; ! 1744: ! 1745: /* ! 1746: * Rebuild table of pollable ports. ! 1747: */ ! 1748: s = sphi(); ! 1749: ppnum = 0; ! 1750: for (chan = 0; chan < ASY_NUM; chan++) { ! 1751: a1 = asy1 + chan; ! 1752: if (a1->a_poll) ! 1753: pptbl[ppnum++] = chan; ! 1754: } ! 1755: spl(s); ! 1756: ! 1757: /* ! 1758: * If another driver has the polling clock, do nothing. ! 1759: */ ! 1760: if (poll_owner & ~ POLL_ASY) ! 1761: return; ! 1762: ! 1763: /* ! 1764: * Find highest valid polling rate in units of HZ/10. ! 1765: * If using FIFO chip, can poll at 1/16 the usual rate. ! 1766: */ ! 1767: max_rate = 0; ! 1768: for (ix = 0; ix < ppnum; ix++) { ! 1769: chan = pptbl[ix]; ! 1770: a0 = asy0 + chan; ! 1771: a1 = asy1 + chan; ! 1772: port_rate = alp_rate[a0->a_speed]; ! 1773: if (a1->a_ut == US_16550A) { ! 1774: port_rate /= 16; ! 1775: if (port_rate % HZ) ! 1776: port_rate += HZ - (port_rate % HZ); ! 1777: } ! 1778: if (max_rate < port_rate) ! 1779: max_rate = port_rate; ! 1780: } ! 1781: ! 1782: /* ! 1783: * if max_rate is not current rate, adjust the system clock ! 1784: */ ! 1785: if (max_rate != poll_rate) { ! 1786: poll_rate = max_rate; ! 1787: poll_divisor = poll_rate/HZ; /* used in asyclk() */ ! 1788: altclk_out(); /* stop previous polling */ ! 1789: poll_owner &= ~ POLL_ASY; ! 1790: if (poll_rate) { /* resume polling at new rate if needed */ ! 1791: poll_owner |= POLL_ASY; ! 1792: altclk_in(poll_rate, asyclk); ! 1793: } ! 1794: } ! 1795: } ! 1796: ! 1797: /* ! 1798: * asysph() ! 1799: * ! 1800: * Serial polling handler. ! 1801: */ ! 1802: static void ! 1803: asysph(chan) ! 1804: int chan; ! 1805: { ! 1806: asy0_t *a0 = asy0 + chan; ! 1807: asy1_t *a1 = asy1 + chan; ! 1808: TTY *tp = &a1->a_tty; ! 1809: silo_t *out_silo = &a1->a_out; ! 1810: silo_t *in_silo = &a1->a_in; ! 1811: int c, xmit_count; ! 1812: short port = a0->a_port; ! 1813: char lsr; ! 1814: ! 1815: /* ! 1816: * Check for received break first. ! 1817: * This status is wiped out on reading the LSR. ! 1818: */ ! 1819: lsr = inb(port + LSR); ! 1820: if (lsr & LS_BREAK) ! 1821: defer(asybreak, chan); ! 1822: ! 1823: /* ! 1824: * Handle all incoming characters. ! 1825: */ ! 1826: for (;;) { ! 1827: lsr = inb(port + LSR); ! 1828: if ((lsr & LS_RxRDY) == 0) ! 1829: break; ! 1830: c = inb(port+DREG); ! 1831: if (tp->t_open == 0) ! 1832: continue; ! 1833: /* ! 1834: * Must recognize XOFF quickly to avoid transmit overrun. ! 1835: * Recognize XON here as well to avoid race conditions. ! 1836: */ ! 1837: if (_IS_IXON_MODE (tp)) { ! 1838: /* ! 1839: * XOFF. ! 1840: */ ! 1841: if (_IS_STOP_CHAR (tp, c)) { ! 1842: tp->t_flags |= T_STOP; ! 1843: continue; ! 1844: } ! 1845: ! 1846: /* ! 1847: * XON. ! 1848: */ ! 1849: if (_IS_START_CHAR (tp, c)) { ! 1850: tp->t_flags &= ~T_STOP; ! 1851: continue; ! 1852: } ! 1853: } ! 1854: ! 1855: /* ! 1856: * Save char in raw input buffer. ! 1857: */ ! 1858: if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) { ! 1859: in_silo->si_buf[in_silo->si_ix] = c; ! 1860: if (in_silo->si_ix < MAX_SILO_INDEX) ! 1861: in_silo->si_ix++; ! 1862: else ! 1863: in_silo->si_ix = 0; ! 1864: in_silo->SILO_CHAR_COUNT++; ! 1865: } ! 1866: ! 1867: /* ! 1868: * If using hardware flow control, see if we need to drop RTS. ! 1869: */ ! 1870: if ((tp->t_flags & T_CFLOW) ! 1871: && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) { ! 1872: unsigned char mcr = inb(port+MCR); ! 1873: if (mcr & MC_RTS) { ! 1874: outb(port+MCR, mcr & ~MC_RTS); ! 1875: } ! 1876: } ! 1877: } ! 1878: ! 1879: /* ! 1880: * Handle outgoing characters. ! 1881: * Do nothing if output is stopped. ! 1882: */ ! 1883: lsr = inb(port + LSR); ! 1884: if ((lsr & LS_TxRDY) ! 1885: && !(tp->t_flags & T_STOP) ! 1886: && !(a1->a_ohlt)) { ! 1887: /* ! 1888: * Transmit next char in raw output buffer. ! 1889: */ ! 1890: xmit_count = (a1->a_ut == US_16550A)?16:1; ! 1891: asy_send(out_silo, port+DREG, xmit_count); ! 1892: } ! 1893: ! 1894: /* ! 1895: * Hardware flow control. ! 1896: * Check CTS to see if we need to halt output. ! 1897: */ ! 1898: if (tp->t_flags & T_CFLOW) { ! 1899: if (inb(port+MSR) & MS_CTS) ! 1900: a1->a_ohlt = 0; ! 1901: else ! 1902: a1->a_ohlt = 1; ! 1903: } ! 1904: } ! 1905: ! 1906: /* ! 1907: * asy_send() ! 1908: * ! 1909: * Write to xmit data register of the UART. ! 1910: * Assume all checking about whether it's time to send has been done already. ! 1911: * Called by time-critical IRQ and polling routines! ! 1912: * ! 1913: * "rawout" is the output silo for the TTY struct supplying data to the port. ! 1914: * "dreg" is the i/o address of the UART xmit data register. ! 1915: * "xmit_count" is the max number of chars we can write (16 for FIFO parts). ! 1916: */ ! 1917: static int ! 1918: asy_send(rawout, dreg, xmit_count) ! 1919: register silo_t * rawout; ! 1920: int dreg, xmit_count; ! 1921: { ! 1922: /* ! 1923: * Transmit next chars in raw output buffer. ! 1924: */ ! 1925: for (;(rawout->si_ix != rawout->si_ox) && xmit_count; xmit_count--) { ! 1926: outb(dreg, rawout->si_buf[rawout->si_ox]); ! 1927: /* ! 1928: * Adjust raw output buffer output index. ! 1929: */ ! 1930: if (++rawout->si_ox >= sizeof(rawout->si_buf)) ! 1931: rawout->si_ox = 0; ! 1932: } ! 1933: return xmit_count; ! 1934: } ! 1935: ! 1936: /* ! 1937: * p1() ! 1938: * ! 1939: * Interrupt handler for Comtrol-type port groups. ! 1940: * Status register has 1 in bit positions for interrupting ports. ! 1941: */ ! 1942: static int ! 1943: p1(g) ! 1944: int g; ! 1945: { ! 1946: asy_gp_t *gp = asy_gp + g; ! 1947: short port = gp->stat_port; ! 1948: unsigned char status, index, chan; ! 1949: int safety = LOOP_LIMIT; ! 1950: int ret = 0; ! 1951: ! 1952: #if 0 /* DEBUG */ ! 1953: static int pxstat[2][8]; ! 1954: int ci; ! 1955: int change_found=0; ! 1956: ! 1957: for (ci=0; ci<1; ci++) { ! 1958: index = inb(port+ci); ! 1959: outb(port+ci, 0); ! 1960: if (index != pxstat[g][ci]) { ! 1961: if (!change_found) { ! 1962: change_found = 1; ! 1963: printf("<%d:", g); ! 1964: } else ! 1965: putchar(' '); ! 1966: printf("%x:%x", port+ci, index); ! 1967: pxstat[g][ci] = index; ! 1968: } ! 1969: } ! 1970: if (change_found) ! 1971: putchar('>'); ! 1972: for (ci=0; ci<8; ci++) ! 1973: asyintr(4+ci); ! 1974: putchar('.'); ! 1975: return 0; ! 1976: #endif /* DEBUG */ ! 1977: ! 1978: /* ! 1979: * while any port is active ! 1980: * call simple interrupt handler for active channel ! 1981: */ ! 1982: while (status = inb(port)) { ! 1983: ret = 1; ! 1984: index = 0; ! 1985: if (status & 0xf0) { ! 1986: status &= 0xf0; ! 1987: index +=4; ! 1988: } else ! 1989: status &= 0x0f; ! 1990: if (status & 0xcc) { ! 1991: status &= 0xcc; ! 1992: index +=2; ! 1993: } else ! 1994: status &= 0x33; ! 1995: if (status & 0xaa) ! 1996: index++; ! 1997: chan = gp->chan_list[index]; ! 1998: asyintr(chan); ! 1999: if (safety-- == 0) { ! 2000: printf("asy: p1 runaway - status %x\n", status); ! 2001: break; ! 2002: } ! 2003: } ! 2004: ! 2005: return ret; ! 2006: } ! 2007: ! 2008: /* ! 2009: * p2() ! 2010: * ! 2011: * Interrupt handler for Arnet-type port groups. ! 2012: * Status register has 0 in bit positions for interrupting ports. ! 2013: */ ! 2014: static int ! 2015: p2(g) ! 2016: int g; ! 2017: { ! 2018: asy_gp_t *gp = asy_gp + g; ! 2019: short port = gp->stat_port; ! 2020: unsigned char status, index, chan; ! 2021: int safety = LOOP_LIMIT; ! 2022: int ret = 0; ! 2023: ! 2024: /* ! 2025: * while any port is active ! 2026: * call simple interrupt handler for active channel ! 2027: */ ! 2028: while (status = ~inb(port)) { ! 2029: ret = 1; ! 2030: index = 0; ! 2031: if (status & 0xf0) { ! 2032: status &= 0xf0; ! 2033: index +=4; ! 2034: } else ! 2035: status &= 0x0f; ! 2036: if (status & 0xcc) { ! 2037: status &= 0xcc; ! 2038: index +=2; ! 2039: } else ! 2040: status &= 0x33; ! 2041: if (status & 0xaa) ! 2042: index++; ! 2043: chan = gp->chan_list[index]; ! 2044: asyintr(chan); ! 2045: if (safety-- == 0) { ! 2046: printf("asy: p2 runaway - status %x\n", status); ! 2047: break; ! 2048: } ! 2049: } ! 2050: return ret; ! 2051: } ! 2052: ! 2053: /* ! 2054: * p3() ! 2055: * ! 2056: * Interrupt handler for GTEK-type port groups. ! 2057: */ ! 2058: static int ! 2059: p3(g) ! 2060: int g; ! 2061: { ! 2062: asy_gp_t *gp = asy_gp + g; ! 2063: short port = gp->stat_port; ! 2064: unsigned char index, chan; ! 2065: ! 2066: /* ! 2067: * Call simple interrupt handler for active channel. ! 2068: */ ! 2069: index = inb(port) & 7; ! 2070: chan = gp->chan_list[index]; ! 2071: return asyintr(chan); ! 2072: } ! 2073: ! 2074: /* ! 2075: * p4() ! 2076: * ! 2077: * Interrupt handler for DigiBoard-type port groups. ! 2078: */ ! 2079: static int ! 2080: p4(g) ! 2081: int g; ! 2082: { ! 2083: asy_gp_t *gp = asy_gp + g; ! 2084: short port = gp->stat_port; ! 2085: unsigned char index, chan; ! 2086: int ret = 0; ! 2087: int safety = LOOP_LIMIT; ! 2088: ! 2089: /* ! 2090: * Status register has slot number for active port, ! 2091: * or 0xFF if no port is active. ! 2092: */ ! 2093: ! 2094: for (;;) { ! 2095: index = inb(port); ! 2096: if (index == 0xFF) ! 2097: break; ! 2098: if (safety-- == 0) { ! 2099: printf("asy: p4 runaway - status %x\n", index); ! 2100: break; ! 2101: } ! 2102: ret = 1; ! 2103: chan = gp->chan_list[index&0xF]; ! 2104: asyintr(chan); ! 2105: } ! 2106: return ret; ! 2107: } ! 2108: ! 2109: #ifdef TRACER ! 2110: void ! 2111: asydump(chan, tag) ! 2112: int chan; ! 2113: char *tag; ! 2114: { ! 2115: asy0_t *a0 = asy0 + chan; ! 2116: asy1_t *a1 = asy1 + chan; ! 2117: TTY *tp = &a1->a_tty; ! 2118: ! 2119: printf("ch=%d %s\n", chan, tag); ! 2120: printf("port=%x irqno=%x speed=%d ", ! 2121: a0->a_port, a0->a_irqno, a0->a_speed); ! 2122: printf("outs=%x gp=%d xcl=%d\n", ! 2123: a0->a_outs, a0->a_asy_gp, a0->a_ixc); ! 2124: printf("in_use=%d lcr=%x irq=%d has_irq=%d ", ! 2125: a1->a_in_use, a1->a_lcr, a1->a_irq, a1->a_has_irq); ! 2126: printf("hop=%d hcl=%d ", a1->a_hopn, a1->a_hcls); ! 2127: printf("opn=%d ier=%x\n", tp->t_open, inb(a0->a_port+IER)); ! 2128: } ! 2129: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.