Annotation of coherent/b/STREAMS/io.386/asy.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.