Annotation of coherent/b/STREAMS/io.386/asy.c, revision 1.1.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.