Annotation of coherent/d/PS2_KERNEL/io.386/alx.c, revision 1.1

1.1     ! root        1: /* (-lgl
        !             2:  *     COHERENT Driver Kit Version x.x.x
        !             3:  *     Copyright (c) 1982, 1990 by Mark Williams Company.
        !             4:  *     All rights reserved. May not be copied without permission.
        !             5:  *
        !             6:  * $Log:       alx.c,v $
        !             7:  * Revision 1.2  92/08/04  12:51:47  bin
        !             8:  * update for ker59
        !             9:  * 
        !            10:  * Revision 1.11  92/04/30  08:59:18  hal
        !            11:  * Add asy.  Remove silos from tty struct.
        !            12:  * 
        !            13:  * Revision 1.10  92/04/13  14:53:15  hal
        !            14:  * Silos moved out of TTY struct.
        !            15:  * 
        !            16:  * Revision 1.9  92/04/13  10:12:27  hal
        !            17:  * Add NO_ISILO test code.
        !            18:  * 
        !            19:  * Revision 1.8  92/03/19  18:33:17  hal
        !            20:  * LSR_READ debug macro.
        !            21:  * 
        !            22:  * Revision 1.7  92/03/16  16:51:39  hal
        !            23:  * t_hal diagnostics.
        !            24:  * 
        !            25:  * Revision 1.6  92/02/20  19:43:13  piggy
        !            26:  * Add "mode" arg to ttsetgrp() for NOCTTY support.
        !            27:  * 
        !            28:  * Revision 1.5  92/02/16  18:27:47  hal
        !            29:  * Binary compatibility with Sys V sgtty
        !            30:  * 
        !            31:  * Revision 1.4  92/02/07  09:41:21  hal
        !            32:  * Fix Wallenberg bug.
        !            33:  * 
        !            34:  * Revision 2.10  92/02/04  18:50:00  hal
        !            35:  * Use EBUSY, not EDBUSY - merge for 386 code.
        !            36:  * 
        !            37:  * Revision 2.9  92/01/13  08:38:24  hal
        !            38:  * Rearrange alxopen() to deal with ill-behaved daemons.
        !            39:  * 
        !            40:  * Revision 2.8  92/01/12  19:23:50  hal
        !            41:  * Tracking nasty Kelly bug.
        !            42:  * 
        !            43:  * Revision 2.6  91/12/26  16:52:05  hal
        !            44:  * Flags left in bad state if open r-device got killed.
        !            45:  *
        !            46:  * Revision 2.5  91/12/20  14:08:27  hal
        !            47:  * Add static alx_send().
        !            48:  * From alxstart(), don't toggle Tx interrupts - call alx_send().
        !            49:  *
        !            50:  * Revision 2.4  91/12/10  08:04:13  hal
        !            51:  * Make interrupt routine clear all UART irq conditions if it gets an
        !            52:  * interrupt without an argument telling which port interrupted.
        !            53:  *
        !            54:  * Revision 2.3  91/12/05  09:35:06  hal
        !            55:  * Working 16550A code.  Nfg on GeeSee.
        !            56:  *
        !            57:  * Revision 2.2  91/12/02  19:21:45  hal
        !            58:  * Last version before FIFO testing.
        !            59:  *
        !            60:  * Revision 2.1  91/11/21  18:17:44  hal
        !            61:  * Same as V1.13 - used in 3.2.05k
        !            62:  *
        !            63:  -lgl) */
        !            64: /*
        !            65:  * Shared parts of IBM async port drivers.
        !            66:  */
        !            67: #include <sys/coherent.h>
        !            68: #ifndef _I386
        !            69: #include <sys/i8086.h>
        !            70: #endif
        !            71: #include <sys/al.h>
        !            72: #include <sys/con.h>
        !            73: #include <errno.h>
        !            74: #include <sys/stat.h>
        !            75: #include <sys/tty.h>
        !            76: #include <sys/timeout.h>
        !            77: #include <sys/clist.h>
        !            78: #include <sys/ins8250.h>
        !            79: #include <sys/sched.h>
        !            80: #include <sys/silo.h>
        !            81: 
        !            82: #ifdef _I386
        !            83: #define        EEBUSY  EBUSY
        !            84: #else
        !            85: #define        EEBUSY  EDBUSY
        !            86: #endif
        !            87: 
        !            88: #define ALPORT (((COM_DDP *)(tp->t_ddp))->port)
        !            89: #define AL_NUM (((COM_DDP *)(tp->t_ddp))->com_num)
        !            90: 
        !            91: #define DTRTMOUT  3    /* DTR timeout interval in seconds for close */
        !            92: 
        !            93: /*
        !            94:  * For rawin silo (see poll_clk.h), use last element of si_buf to count
        !            95:  * the number of characters in the silo.
        !            96:  */
        !            97: #define SILO_CHAR_COUNT        si_buf[SI_BUFSIZ-1]
        !            98: #define SILO_HIGH_MARK (SI_BUFSIZ-SI_BUFSIZ/4)
        !            99: #define SILO_LOW_MARK  (SI_BUFSIZ/4)
        !           100: #define MAX_SILO_INDEX (SI_BUFSIZ-2)
        !           101: #define MAX_SILO_CHARS (SI_BUFSIZ-1)
        !           102: 
        !           103: /*
        !           104:  * The following silo FLUSH macros are always called at high priority!
        !           105:  */
        !           106: #ifdef NO_ISILO
        !           107: #define RAWIN_FLUSH(in_silo)
        !           108: #else
        !           109: #define RAWIN_FLUSH(in_silo)   { in_silo->si_ox = in_silo->si_ix; \
        !           110:          in_silo->SILO_CHAR_COUNT = 0; }
        !           111: #endif
        !           112: #define RAWOUT_FLUSH(out_silo) { out_silo->si_ox = out_silo->si_ix; }
        !           113: 
        !           114: int    al_sg_set = 0;
        !           115: int    al_sg_clr = 0;
        !           116: static int poll_divisor;  /* set by set_poll_rate(), read by alxclk() */
        !           117: 
        !           118: /*
        !           119:  * functions herein
        !           120:  */
        !           121: int    alxopen();
        !           122: int    alxclose();
        !           123: int    alxtimer();
        !           124: int    alxioctl();
        !           125: int    alxparam();
        !           126: int    alxcycle();
        !           127: int    alxstart();
        !           128: int    alxbreak();
        !           129: int    alxintr();
        !           130: static int alxclk();
        !           131: static set_poll_rate();
        !           132: static void alxpoll();
        !           133: static void alx_send();
        !           134: static int iocbaud[4];
        !           135: static char ioclcr[4];
        !           136: 
        !           137: /*
        !           138:  * Port addresses are now patchable.
        !           139:  */
        !           140: int AL_ADDR[] = {
        !           141: #if BOB_H
        !           142:        0x280, 0x288, 0x290, 0x298
        !           143: #else
        !           144:        0x3F8, 0x2F8, 0x3E8, 0x2E8
        !           145: #endif
        !           146: };
        !           147: 
        !           148: /*
        !           149:  * Baud rate table and polling rate table.
        !           150:  * Indexed by ioctl bit rates.
        !           151:  */
        !           152: extern int albaud[], alp_rate[];
        !           153: 
        !           154: /*
        !           155:  *     the following is for debug only
        !           156:  */
        !           157: #if TRACER
        !           158: int ASY_OR = 0;
        !           159: #define LSR_READ(lval, port) \
        !           160:   { lval = inb((port)+LSR); if (lval & LS_OVER) ASY_OR++; }
        !           161: #define CDUMP(text, tp)        cdump(text, tp);
        !           162: #define tprintf(str)   { T_HAL(4, printf(str)); }
        !           163: #define REPORT_OE {if(ASY_OR&&(t_hal&0x20)){printf("oe=%d ",ASY_OR);ASY_OR=0;}}
        !           164: cdump(message, tp)
        !           165: char *message;
        !           166: TTY *tp;
        !           167: {
        !           168:        int i, b;
        !           169:        char cmd[11];
        !           170: 
        !           171:        if ((t_hal & 4) == 0)
        !           172:                return;
        !           173:        for (i = 0; i < NUM_AL_PORTS; i++) {
        !           174:                if (tp_table[i]) {
        !           175:                        b = ((COM_DDP *)(tp_table[i]->t_ddp))->port;
        !           176:                        printf("%x:%x:%x:%x ", i+1, b, inb(b+MCR), inb(b+IER));
        !           177:                }
        !           178:        }
        !           179:        for (i = 0; i < 10; i++) {
        !           180:                cmd[i] = u.u_comm[i];
        !           181:        }
        !           182:        cmd[10] = '\0';
        !           183:        printf("poll=%d cmd=%s pid=%d ", poll_rate, cmd, SELF->p_pid);
        !           184:        printf("%s\n", message);
        !           185:        if (tp) {
        !           186:                printf("#%d f=%x op=%d ", AL_NUM, tp->t_flags, tp->t_open);
        !           187:                printf("in_use=%d irq=%d has_irq=%d ",
        !           188:                  com_usage[AL_NUM].in_use,
        !           189:                  com_usage[AL_NUM].irq,
        !           190:                  com_usage[AL_NUM].has_irq);
        !           191:                printf("poll=%d hcls=%d ohlt=%d\n",
        !           192:                  com_usage[AL_NUM].poll,
        !           193:                  com_usage[AL_NUM].hcls,
        !           194:                  com_usage[AL_NUM].ohlt);
        !           195:        }
        !           196: }
        !           197: #else
        !           198: #define CDUMP(text, tp)
        !           199: #define REPORT_OE
        !           200: #define LSR_READ(lval, port)   { lval = inb((port)+LSR); }
        !           201: #endif
        !           202: 
        !           203: /*
        !           204:  * alxopen()
        !           205:  */
        !           206: alxopen(dev, mode, tp, irqtty)
        !           207: dev_t  dev;
        !           208: int    mode;
        !           209: register TTY   *tp, **irqtty;
        !           210: {
        !           211:        int     s;
        !           212:        int     b;
        !           213:        int     minor_h;  /* minor device number including high bit */
        !           214:        unsigned char   msr;
        !           215: 
        !           216:        minor_h = minor(dev);     /* complete minor number */
        !           217:        b = ALPORT;
        !           218: 
        !           219:        if (com_usage[AL_NUM].uart_type == US_NONE) { /* chip not found */
        !           220:                u.u_error = ENXIO;
        !           221:                goto bad_open;
        !           222:        }
        !           223: 
        !           224:        if ((tp->t_flags & T_EXCL) && !super()) {
        !           225:                u.u_error = ENODEV;
        !           226:                goto bad_open;
        !           227:        }
        !           228: 
        !           229:        if (drvl[major(dev)].d_time != 0) {     /* Modem settling */
        !           230:                u.u_error = EEBUSY;
        !           231:                goto bad_open;
        !           232:        }
        !           233: 
        !           234:        /*
        !           235:         * Can't open a polled port if another driver is using polling.
        !           236:         */
        !           237:        if (dev & CPOLL && poll_owner & ~ POLL_AL) {
        !           238:                u.u_error = EEBUSY;
        !           239:                goto bad_open;
        !           240:        }
        !           241: 
        !           242:        /*
        !           243:         * Can't have both com[13] or both com[24] IRQ at once.
        !           244:         */
        !           245:        if ( !(dev & CPOLL)
        !           246:        && com_usage[AL_NUM^2].irq
        !           247:        && com_usage[AL_NUM^2].in_use) {
        !           248:                u.u_error = EEBUSY;
        !           249:                goto bad_open;
        !           250:        }
        !           251: 
        !           252:        /*
        !           253:         * If port already in use, are new and old open modes compatible?
        !           254:         */
        !           255:        if (com_usage[AL_NUM].in_use) {
        !           256:                int oldmode = 0, newmode = 0; /* mctl:1 poll:2 flow:4 */
        !           257: 
        !           258:                if (tp->t_flags & T_MODC)
        !           259:                        oldmode += 1;
        !           260:                if (com_usage[AL_NUM].irq == 0)
        !           261:                        oldmode += 2;
        !           262:                if (tp->t_flags & T_CFLOW)
        !           263:                        oldmode += 4;
        !           264:                if ((minor_h & NMODC) == 0)
        !           265:                        newmode += 1;
        !           266:                if (dev & CPOLL)
        !           267:                        newmode += 2;
        !           268:                if (minor_h & CFLOW)
        !           269:                        newmode += 4;
        !           270:                if (oldmode != newmode) {
        !           271:                        u.u_error = EEBUSY;
        !           272:                        goto bad_open;
        !           273:                }
        !           274:        }
        !           275: 
        !           276:        /*
        !           277:         * Sleep here if another process is opening or closing the port.
        !           278:         * This can happen if:
        !           279:         *   another process is trying a first open and awaiting CD;
        !           280:         *   another process is closing the port after losing CD;
        !           281:         *   a remote process opened the port, spawned a daemon,
        !           282:         *     and disconnected, and the daemon ignored SIGHUP and is
        !           283:         *     improperly keeping the port open.
        !           284:         * Don't try to set tp->t_flags before this sleep!  During
        !           285:         *   the sleep, ttclose() may be called and clear the flags.
        !           286:         */
        !           287:        while (com_usage[AL_NUM].in_use &&
        !           288:          (com_usage[AL_NUM].hcls ||
        !           289:          ((minor_h & NMODC) == 0 && (inb(b+MSR) & MS_RLSD) == 0))) {
        !           290:                sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT, SVTTOUT);
        !           291:                if (SELF->p_ssig && nondsig()) {  /* signal? */
        !           292:                        u.u_error = EINTR;
        !           293:                        goto bad_open;
        !           294:                }
        !           295:        }
        !           296: 
        !           297:        /*
        !           298:         * If port already in use, are new and old open modes compatible?
        !           299:         * If not in use, mark it as such.
        !           300:         */
        !           301:        if (com_usage[AL_NUM].in_use) {
        !           302:                int oldmode = 0, newmode = 0; /* mctl:1 poll:2 flow:4 */
        !           303: 
        !           304:                if (tp->t_flags & T_MODC)
        !           305:                        oldmode += 1;
        !           306:                if (com_usage[AL_NUM].irq == 0)
        !           307:                        oldmode += 2;
        !           308:                if (tp->t_flags & T_CFLOW)
        !           309:                        oldmode += 4;
        !           310:                if ((minor_h & NMODC) == 0)
        !           311:                        newmode += 1;
        !           312:                if (dev & CPOLL)
        !           313:                        newmode += 2;
        !           314:                if (minor_h & CFLOW)
        !           315:                        newmode += 4;
        !           316:                if (oldmode != newmode) {
        !           317:                        u.u_error = EEBUSY;
        !           318:                        goto bad_open;
        !           319:                }
        !           320:        } else {
        !           321:                /*
        !           322:                 * Save modes for this open attempt to avoid future conflicts.
        !           323:                 * Then start alxcycle() for this port.
        !           324:                 */
        !           325:                if (dev & CPOLL)
        !           326:                        com_usage[AL_NUM].irq = 0;
        !           327:                else
        !           328:                        com_usage[AL_NUM].irq = 1;
        !           329:                if (minor_h & CFLOW)
        !           330:                        tp->t_flags |= T_CFLOW;
        !           331:                else
        !           332:                        tp->t_flags &= ~T_CFLOW;
        !           333:                if (minor_h & NMODC)
        !           334:                        tp->t_flags &= ~T_MODC;
        !           335:                else
        !           336:                        tp->t_flags |= T_MODC;
        !           337:        }
        !           338:        com_usage[AL_NUM].in_use++;
        !           339:        /*
        !           340:         * From here, error exit is bad_open_u.
        !           341:         */
        !           342: 
        !           343:        if (tp->t_open == 0) {        /* not already open */
        !           344:                if (!(dev & CPOLL)) {
        !           345:                        *irqtty = tp_table[AL_NUM];
        !           346:                        com_usage[AL_NUM].has_irq = 1;
        !           347:                }
        !           348: 
        !           349:                /*
        !           350:                 * Need to start cycling to scan for CD.
        !           351:                 */
        !           352:                alxcycle(tp);
        !           353: 
        !           354:                s = sphi();
        !           355:                /*
        !           356:                 * Raise basic modem control lines even if modem
        !           357:                 * control hasn't been specified.
        !           358:                 * MC_OUT2 turns on NON-open-collector IRQ line from the UART.
        !           359:                 * since we can't have two UART's on same IRQ with MC_OUT2 on
        !           360:                 */
        !           361:                if (dev & CPOLL) {
        !           362:                        outb(b+MCR, MC_RTS|MC_DTR);
        !           363:                } else {
        !           364:                        outb(b+MCR, MC_RTS|MC_DTR|MC_OUT2);
        !           365:                        outb(b+IER, IENABLE);
        !           366:                }
        !           367: 
        !           368:                if ((minor_h & NMODC) == 0) {   /* want modem control? */
        !           369:                        tp->t_flags |= T_HOPEN | T_STOP;
        !           370:                        for (;;) {      /* wait for carrier */
        !           371:                                msr = inb(b+MSR);
        !           372:                                /*
        !           373:                                 * If carrier detect present
        !           374:                                 *   if port not already open
        !           375:                                 *     break out of loop and finish first open
        !           376:                                 *   else
        !           377:                                 *     do second (or third, etc.) open
        !           378:                                 */
        !           379:                                if (msr & MS_RLSD)
        !           380:                                        break;
        !           381:                                sleep((char *)(&tp->t_open), CVTTOUT, IVTTOUT,
        !           382:                                        SVTTOUT);       /* wait for carrier */
        !           383:                                if (SELF->p_ssig && nondsig()) {  /* signal? */
        !           384:                                        outb(b+MCR, 0);
        !           385:                                        outb(b+IER, 0);
        !           386:                                        u.u_error = EINTR;
        !           387:                                        tp->t_flags &= ~(T_HOPEN | T_STOP);
        !           388:                                        spl(s);
        !           389:                                        goto bad_open_u;
        !           390:                                }
        !           391:                        }
        !           392: 
        !           393:                        /*
        !           394:                         * Mark that we are no longer hanging in open.
        !           395:                         * Allow output over the port unless hardware flow
        !           396:                         * control says not to.
        !           397:                         */
        !           398:                        tp->t_flags &= ~T_HOPEN;
        !           399:                        tp->t_flags &= ~T_STOP;
        !           400:                        if (!(tp->t_flags & T_CFLOW) || (msr & MS_CTS))
        !           401:                                com_usage[AL_NUM].ohlt = 0;
        !           402:                        else
        !           403:                                com_usage[AL_NUM].ohlt = 1;
        !           404: 
        !           405:                        /*
        !           406:                         * Awaken any other opens on same device.
        !           407:                         */
        !           408:                        wakeup((char *)(&tp->t_open));
        !           409:                }
        !           410:                tp->t_flags |= T_CARR;
        !           411:                ttopen(tp);                             /* stty inits */
        !           412: 
        !           413:                /*
        !           414:                 * Allow custom modification of defaults.
        !           415:                 */
        !           416:                tp->t_sgttyb.sg_flags |=  al_sg_set;
        !           417:                tp->t_sgttyb.sg_flags &= ~al_sg_clr;
        !           418: 
        !           419:                alxparam(tp);
        !           420:                spl(s);
        !           421:        } /* end of first-open case */
        !           422: 
        !           423:        tp->t_open++;
        !           424:        ttsetgrp(tp, dev, mode);
        !           425: 
        !           426:        /*
        !           427:         * Turn on polling for the port.
        !           428:         */
        !           429:        if (dev & CPOLL) {
        !           430:                com_usage[AL_NUM].poll = 1;
        !           431:                set_poll_rate();
        !           432:        }
        !           433: 
        !           434:        CDUMP((dev&CPOLL)?"open polled":"open irq", tp)
        !           435:        return;
        !           436: 
        !           437: bad_open_u:
        !           438:        --com_usage[AL_NUM].in_use;
        !           439:        wakeup((char *)(&tp->t_open));
        !           440: bad_open:
        !           441:        return;
        !           442: }
        !           443: 
        !           444: /*
        !           445:  * alxclose()
        !           446:  *
        !           447:  *     Called whenever kernel closes a com port.
        !           448:  */
        !           449: alxclose(dev, mode, tp)
        !           450: dev_t  dev;
        !           451: int    mode;
        !           452: TTY    *tp;
        !           453: {
        !           454:        register int b;
        !           455:        int maj;
        !           456:        int flags;
        !           457:        int s;
        !           458:        unsigned char lsr;
        !           459:        silo_t * out_silo = &com_usage[AL_NUM].raw_out;
        !           460:        silo_t * in_silo = &com_usage[AL_NUM].raw_in;
        !           461: 
        !           462:        if (--tp->t_open)
        !           463:                goto closed;
        !           464:        s = sphi();
        !           465: 
        !           466:        /*
        !           467:         * Called at high priority by alclose after al_buff is drained
        !           468:         */
        !           469:        com_usage[AL_NUM].hcls = 1;     /* disallow reopen til done closing */
        !           470:        flags = tp->t_flags;            /* save flags - ttclose zeroes them */
        !           471:        ttclose(tp);
        !           472:        b = ALPORT;
        !           473: 
        !           474:        /*
        !           475:         * Wait for output silo and uart xmit buffer to empty.
        !           476:         * Allow signal to break the sleep.
        !           477:         */
        !           478:        for (;;) {
        !           479:                LSR_READ(lsr, b);
        !           480:                if ((lsr & LS_TxIDLE)
        !           481:                  && (out_silo->si_ix == out_silo->si_ox))
        !           482:                        break;
        !           483: CDUMP("slp cls", tp)
        !           484:                sleep((char *)out_silo, CVTTOUT, IVTTOUT, SVTTOUT);
        !           485:                if (SELF->p_ssig && nondsig()) {  /* signal? */
        !           486:                        RAWOUT_FLUSH(out_silo);
        !           487:                        break;
        !           488:                }
        !           489:        }
        !           490: 
        !           491:        /*
        !           492:         * If not hanging in open
        !           493:         */
        !           494:        if ((flags & T_HOPEN) == 0) {
        !           495:                /*
        !           496:                 * Disable interrupts.
        !           497:                 */
        !           498:                outb(b+IER, 0);
        !           499:                outb(b+MCR, inb(b+MCR)&(~MC_OUT2));
        !           500:        }
        !           501: 
        !           502:        /*
        !           503:         * If hupcls
        !           504:         */
        !           505:        if (flags & T_HPCL) {
        !           506:                /*
        !           507:                 * Hangup port - drop DTR and RTS.
        !           508:                 */
        !           509:                outb(b+MCR, inb(b+MCR)&MC_OUT2);
        !           510: 
        !           511:                /*
        !           512:                 * Hold dtr low for timeout
        !           513:                 */
        !           514:                maj = major(dev);
        !           515:                drvl[maj].d_time = 1;
        !           516: CDUMP("slp DTR", tp)
        !           517:                sleep((char *)&drvl[maj].d_time, CVTTOUT, IVTTOUT, SVTTOUT);
        !           518:                drvl[maj].d_time = 0;
        !           519:        }
        !           520:        com_usage[AL_NUM].poll = 0;
        !           521:        set_poll_rate();
        !           522:        RAWIN_FLUSH(in_silo);
        !           523:        com_usage[AL_NUM].hcls = 0;     /* allow reopen - done closing */
        !           524:        wakeup((char *)(&tp->t_open));
        !           525:        spl(s);
        !           526: closed:;
        !           527:        --com_usage[AL_NUM].in_use;
        !           528:        wakeup((char *)(&tp->t_open));
        !           529:        CDUMP("closed", tp)
        !           530: }
        !           531: 
        !           532: /*
        !           533:  * Common c_timer routine for async ports.
        !           534:  */
        !           535: alxtimer(dev)
        !           536: dev_t dev;
        !           537: {
        !           538:        if (++drvl[major(dev)].d_time > DTRTMOUT)
        !           539:                wakeup((char *)&drvl[major(dev)].d_time);
        !           540: }
        !           541: 
        !           542: 
        !           543: /*
        !           544:  * Common c_ioctl routine for async ports.
        !           545:  */
        !           546: alxioctl(dev, com, vec, tp)
        !           547: dev_t  dev;
        !           548: struct sgttyb *vec;
        !           549: register TTY   *tp;
        !           550: {
        !           551:        register int    s, b;
        !           552:        int stat1, stat2;
        !           553:        unsigned char   msr;
        !           554:        unsigned char ier_save;
        !           555:        silo_t * out_silo = &com_usage[AL_NUM].raw_out;
        !           556:        silo_t * in_silo = &com_usage[AL_NUM].raw_in;
        !           557: 
        !           558:        s = sphi();
        !           559:        b = ALPORT;
        !           560:        ier_save=inb(b+IER);
        !           561:        stat1 = inb(b+MCR);             /* get current MCR register status */
        !           562:        stat2 = inb(b+LCR);             /* get current LCR register status */
        !           563: 
        !           564:        switch(com) {
        !           565:        case TIOCSBRK:                  /* set BREAK */
        !           566:                outb(b+LCR, stat2|LC_SBRK);
        !           567:                break;
        !           568:        case TIOCCBRK:                  /* clear BREAK */
        !           569:                outb(b+LCR, stat2 & ~LC_SBRK);
        !           570:                break;
        !           571:        case TIOCSDTR:                  /* set DTR */
        !           572:                outb(b+MCR, stat1|MC_DTR);
        !           573:                break;
        !           574:        case TIOCCDTR:                  /* clear DTR */
        !           575:                outb(b+MCR, stat1 & ~MC_DTR);
        !           576:                break;
        !           577:        case TIOCSRTS:                  /* set RTS */
        !           578:                outb(b+MCR, stat1|MC_RTS);
        !           579:                break;
        !           580:        case TIOCCRTS:                  /* clear RTS */
        !           581:                outb(b+MCR, stat1 & ~MC_RTS);
        !           582:                break;
        !           583:        case TIOCRSPEED:                /* set "raw" I/O speed divisor */
        !           584:                outb(b+LCR, stat2|LC_DLAB);  /* set speed latch bit */
        !           585:                outb(b+DLL, (unsigned) vec);
        !           586:                outb(b+DLH, (unsigned) vec >> 8);
        !           587:                outb(b+LCR, stat2);       /* reset latch bit */
        !           588:                break;
        !           589:        case TIOCWORDL:         /* set word length and stop bits */
        !           590:                outb(b+LCR, ((stat2&~0x7) | ((unsigned) vec & 0x7)));
        !           591:                break;
        !           592:        case TIOCRMSR:          /* get CTS/DSR/RI/RLSD (MSR) */
        !           593:                msr = inb(b+MSR);
        !           594:                stat1 = msr >> 4;
        !           595:                kucopy(&stat1, (unsigned *) vec, sizeof(unsigned));
        !           596:                break;
        !           597:        case TIOCFLUSH:         /* Flush silos here, queues in tty.c */
        !           598:                RAWIN_FLUSH(in_silo);
        !           599:                RAWOUT_FLUSH(out_silo);
        !           600:                /* fall through to default... */
        !           601:        default:
        !           602:                ttioctl(tp, com, vec);
        !           603:        }
        !           604:        outb(b+IER, ier_save);
        !           605:        spl(s);
        !           606: }
        !           607: 
        !           608: alxparam(tp)
        !           609: TTY    *tp;
        !           610: {
        !           611:        register int    b;
        !           612:        register int    baud;
        !           613:        int s;
        !           614:        char newlcr;
        !           615:        int write_baud=1, write_lcr=1;
        !           616:        int alnum;
        !           617: 
        !           618:        b = ALPORT;
        !           619: 
        !           620:        /*
        !           621:         * error if input speed not the same as output speed
        !           622:         */
        !           623:        if (tp->t_sgttyb.sg_ispeed!=tp->t_sgttyb.sg_ospeed) {
        !           624:                u.u_error = ENODEV;
        !           625:                return;
        !           626:        }
        !           627: 
        !           628:        if ((baud = albaud[tp->t_sgttyb.sg_ispeed]) == 0) {
        !           629:                if (tp->t_flags & T_MODC) {  /* modem control? */
        !           630:                        s = sphi();
        !           631:                        tp->t_flags &= ~T_CARR;  /* indicate no carrier */
        !           632:                        outb(b+MCR, inb(b+MCR) & MC_OUT2); /* hangup */
        !           633:                        spl(s);
        !           634:                }
        !           635:                write_baud = 0;
        !           636:        }
        !           637: 
        !           638:        switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) {
        !           639:        case ODDP:
        !           640:                newlcr = LC_CS7|LC_PARENB;
        !           641:                break;
        !           642:        case EVENP:
        !           643:                newlcr = LC_CS7|LC_PARENB|LC_PAREVEN;
        !           644:                break;
        !           645:        default:
        !           646:                newlcr = LC_CS8;
        !           647:                break;
        !           648:        }
        !           649: 
        !           650:        alnum = AL_NUM;
        !           651:        if (alnum >= 0 && alnum < 4) {
        !           652:                if (baud == iocbaud[alnum]) {
        !           653:                        write_baud = 0;
        !           654:                        if (newlcr == ioclcr[alnum]) {
        !           655:                                write_lcr = 0;
        !           656:                        }
        !           657:                }
        !           658:                iocbaud[alnum] = baud;
        !           659:                ioclcr[alnum] = newlcr;
        !           660:        }
        !           661: 
        !           662:        if (write_lcr) {
        !           663:                unsigned char ier_save;
        !           664:                s=sphi();
        !           665:                ier_save=inb(b+IER);
        !           666:                if (write_baud) {
        !           667:                        outb(b+LCR, LC_DLAB);
        !           668:                        outb(b+DLL, baud);
        !           669:                        outb(b+DLH, baud >> 8);
        !           670:                }
        !           671:                outb(b+LCR, newlcr);
        !           672:                if (com_usage[AL_NUM].uart_type == US_16550A)
        !           673:                        outb(b+FCR, FC_ENABLE | FC_Rx_RST | FC_Rx_08);
        !           674:                outb(b+IER, ier_save);
        !           675:                spl(s);
        !           676:        }
        !           677: 
        !           678:        set_poll_rate();
        !           679: }
        !           680: 
        !           681: /*
        !           682:  * Middle level processor.
        !           683:  *
        !           684:  *     Invoked 10 times per second.  (Once every ten clock ticks.)
        !           685:  *     Tranfers rawin buffer [from intr level] to canonical input queue.
        !           686:  *     Checks modem status for loss of carrier.
        !           687:  *     Transfers output queue to rawout buffer [for intr level].
        !           688:  */
        !           689: alxcycle(tp)
        !           690: register TTY * tp;
        !           691: {
        !           692:        register int b;
        !           693:        register int n;
        !           694:        unsigned char msr, mcr;
        !           695:        int s;
        !           696:        silo_t * out_silo = &com_usage[AL_NUM].raw_out;
        !           697:        silo_t * in_silo = &com_usage[AL_NUM].raw_in;
        !           698: 
        !           699:        REPORT_OE;
        !           700:        /*
        !           701:         * Check Carrier Detect (RLSD).
        !           702:         *
        !           703:         * Modem status interrupts were not enabled due to 8250 hardware bug.
        !           704:         * Enabling modem status and receive interrupts may cause lockup
        !           705:         * on older parts.
        !           706:         */
        !           707:        if (tp->t_flags & T_MODC) {
        !           708: 
        !           709:                /*
        !           710:                 * Get status
        !           711:                 */
        !           712:                msr = inb(ALPORT+MSR);
        !           713: 
        !           714:                /*
        !           715:                 * Carrier changed.
        !           716:                 */
        !           717:                if ((msr & MS_RLSD) && !(tp->t_flags & T_CARR)) {
        !           718:                        /*
        !           719:                         * Carrier is on - wakeup open.
        !           720:                         */
        !           721:                        s = sphi();
        !           722:                        tp->t_flags |= T_CARR;
        !           723:                        spl(s);
        !           724:                        wakeup((char *)(&tp->t_open));
        !           725:                }
        !           726: 
        !           727:                if (!(msr & MS_RLSD) && (tp->t_flags & T_CARR)) {
        !           728:                        s = sphi();
        !           729:                        RAWIN_FLUSH(in_silo);
        !           730:                        RAWOUT_FLUSH(out_silo);
        !           731:                        tp->t_flags &= ~T_CARR;
        !           732:                        spl(s);
        !           733:                        tthup(tp);
        !           734:                }
        !           735:        }
        !           736: 
        !           737:        /*
        !           738:         * Empty raw input buffer.
        !           739:         *
        !           740:         * The line discipline module (tty.c) will set T_ISTOP true when the
        !           741:         * tt input queue is nearly full (tp->t_iq.cq_cc >= IHILIM), and make
        !           742:         * T_ISTOP false when it's ready for more input.
        !           743:         *
        !           744:         * When T_ISTOP is true, ttin() simply discards the character passed.
        !           745:         */
        !           746: #ifndef NOISILO
        !           747:        if (!(tp->t_flags & T_ISTOP)) {
        !           748:                while (in_silo->SILO_CHAR_COUNT > 0) {
        !           749:                        s = sphi();
        !           750:                        ttin(tp, in_silo->si_buf[in_silo->si_ox]);
        !           751:                        if (in_silo->si_ox < MAX_SILO_INDEX)
        !           752:                                in_silo->si_ox++;
        !           753:                        else
        !           754:                                in_silo->si_ox = 0;
        !           755:                        in_silo->SILO_CHAR_COUNT--;
        !           756:                        spl(s);
        !           757:                }
        !           758:        }
        !           759: #endif
        !           760: 
        !           761:        /*
        !           762:         * Hardware flow control.
        !           763:         *      Check CTS to see if we need to halt output.
        !           764:         *      (MS_INTR should have done this - repeat code here to be sure)
        !           765:         *      Check input silo to see if we need to raise RTS.
        !           766:         */
        !           767:        if (tp->t_flags & T_CFLOW) {
        !           768: 
        !           769:                /*
        !           770:                 * Get status
        !           771:                 */
        !           772:                msr = inb(ALPORT+MSR);
        !           773: 
        !           774:                s = sphi();
        !           775:                if (msr & MS_CTS)
        !           776:                        com_usage[AL_NUM].ohlt = 0;
        !           777:                else
        !           778:                        com_usage[AL_NUM].ohlt = 1;
        !           779:                spl(s);
        !           780: #if TRACER
        !           781: if(t_hal & 4) {static cts = 0;
        !           782: if (!cts && (msr & MS_CTS)) {
        !           783:        cts = 1;
        !           784:        printf("[");
        !           785: } else if (cts && !(msr & MS_CTS)) {
        !           786:        cts = 0;
        !           787:        printf("]");
        !           788: }}
        !           789: #endif
        !           790: 
        !           791:                /*
        !           792:                 * If using hardware flow control, see if we need to drop RTS.
        !           793:                 */
        !           794:                if ( (tp->t_flags & T_CFLOW)
        !           795: #ifdef NO_ISILO
        !           796:                && (tp->t_flags & T_ISTOP)) {
        !           797: #else
        !           798:                && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
        !           799: #endif
        !           800:                        s = sphi();
        !           801:                        mcr = inb(ALPORT+MCR);
        !           802:                        if (mcr & MC_RTS) {
        !           803:                                outb(ALPORT+MCR, mcr & ~MC_RTS);
        !           804: #if TRACER
        !           805: tprintf("-");
        !           806: #endif
        !           807:                        }
        !           808:                        spl(s);
        !           809:                }
        !           810: 
        !           811:                /*
        !           812:                 * If input silo below low mark, assert RTS.
        !           813:                 */
        !           814: #ifdef NO_ISILO
        !           815:                if ((tp->t_flags & T_ISTOP) == 0) {
        !           816: #else
        !           817:                if (in_silo->SILO_CHAR_COUNT <= SILO_LOW_MARK) {
        !           818: #endif
        !           819:                        s = sphi();
        !           820:                        mcr = inb(ALPORT+MCR);
        !           821:                        if ((mcr & MC_RTS) == 0) {
        !           822:                                outb(ALPORT+MCR, mcr | MC_RTS);
        !           823: #if TRACER
        !           824: tprintf("+");
        !           825: #endif
        !           826:                        }
        !           827:                        spl(s);
        !           828:                }
        !           829:        }
        !           830: 
        !           831:        /*
        !           832:         * Calculate free output slot count.
        !           833:         */
        !           834:        n  = sizeof(out_silo->si_buf) - 1;
        !           835:        n += out_silo->si_ox - out_silo->si_ix;
        !           836:        n %= sizeof(out_silo->si_buf);
        !           837: 
        !           838:        /*
        !           839:         * Fill raw output buffer.
        !           840:         */
        !           841:        for (;;) {
        !           842:                if (--n < 0)
        !           843:                        break;
        !           844:                s = sphi();
        !           845:                b = ttout(tp);
        !           846:                spl(s);
        !           847:                if (b < 0)
        !           848:                        break;
        !           849: 
        !           850:                s = sphi();
        !           851:                out_silo->si_buf[out_silo->si_ix] = b;
        !           852:                if (out_silo->si_ix >= sizeof(out_silo->si_buf) - 1)
        !           853:                        out_silo->si_ix = 0;
        !           854:                else
        !           855:                        out_silo->si_ix++;
        !           856:                spl(s);
        !           857:        }
        !           858: 
        !           859:        /*
        !           860:         * (Re)start output, wake sleeping processes, etc.
        !           861:         */
        !           862:        ttstart(tp);
        !           863: 
        !           864:        /*
        !           865:         * Schedule next cycle.
        !           866:         */
        !           867:        if (com_usage[AL_NUM].in_use)
        !           868:                timeout(&tp->t_rawtim, HZ/10, alxcycle, tp);
        !           869: }
        !           870: 
        !           871: /*
        !           872:  * Serial Transmit Start Routine.
        !           873:  */
        !           874: alxstart(tp)
        !           875: register TTY * tp;
        !           876: {
        !           877:        int b;
        !           878:        int s;
        !           879:        extern alxbreak();
        !           880:        int need_xmit = 1;      /* True if should start sending data now. */
        !           881:        silo_t * out_silo = &com_usage[AL_NUM].raw_out;
        !           882: 
        !           883:        /*
        !           884:         * Read line status register AFTER disabling interrupts.
        !           885:         */
        !           886:        s = sphi();
        !           887:        LSR_READ(b, ALPORT);
        !           888: 
        !           889:        /*
        !           890:         * Process break indication.
        !           891:         * NOTE: Break indication cleared when line status register was read.
        !           892:         */
        !           893:        if (b & LS_BREAK)
        !           894:                defer(alxbreak, tp);
        !           895: 
        !           896:        /*
        !           897:         * If no output data, it may be time to finish closing the port;
        !           898:         * but won't need another xmit interrupt.
        !           899:         */
        !           900:        if (out_silo->si_ix == out_silo->si_ox) {
        !           901:                wakeup((char *)out_silo);
        !           902:                need_xmit = 0;
        !           903:        }
        !           904: 
        !           905:        /*
        !           906:         * Do nothing if output is stopped.
        !           907:         */
        !           908:        if (tp->t_flags & T_STOP)
        !           909:                need_xmit = 0;
        !           910:        if (com_usage[AL_NUM].ohlt)
        !           911:                need_xmit = 0;
        !           912: 
        !           913:        /*
        !           914:         * Start data transmission by writing to UART xmit reg.
        !           915:         */
        !           916:        if ((b & LS_TxRDY) && need_xmit) {
        !           917:                int xmit_count;
        !           918: 
        !           919:                xmit_count = (com_usage[AL_NUM].uart_type == US_16550A)?16:1;
        !           920:                alx_send(out_silo, ALPORT+DREG, xmit_count);
        !           921:        }
        !           922: 
        !           923:        spl(s);
        !           924: }
        !           925: 
        !           926: /*
        !           927:  * Serial Received Break Handler.
        !           928:  */
        !           929: alxbreak(tp)
        !           930: TTY * tp;
        !           931: {
        !           932:        int s;
        !           933:        silo_t * out_silo = &com_usage[AL_NUM].raw_out;
        !           934:        silo_t * in_silo = &com_usage[AL_NUM].raw_in;
        !           935: 
        !           936:        s = sphi();
        !           937:        RAWIN_FLUSH(in_silo);
        !           938:        RAWOUT_FLUSH(out_silo);
        !           939:        spl(s);
        !           940:        ttsignal(tp, SIGINT);
        !           941: }
        !           942: 
        !           943: /*
        !           944:  * Serial Interrupt Handler.
        !           945:  */
        !           946: alxintr(tp)
        !           947: register TTY * tp;
        !           948: {
        !           949:        int c;
        !           950:        register int port = ALPORT;
        !           951:        unsigned char msr, lsr;
        !           952:        int xmit_count;
        !           953:        silo_t * in_silo = &com_usage[AL_NUM].raw_in;
        !           954:        silo_t * out_silo = &com_usage[AL_NUM].raw_out;
        !           955: 
        !           956:        if (tp) {
        !           957: rescan:
        !           958:                switch (inb(port+IIR) & 0x07) {
        !           959: 
        !           960:                case LS_INTR:
        !           961:                        LSR_READ(lsr, port);
        !           962:                        if (lsr & LS_BREAK)
        !           963:                                defer(alxbreak, tp);
        !           964:                        goto rescan;
        !           965: 
        !           966:                case Rx_INTR:
        !           967:                        c = inb(port+DREG);
        !           968:                        if (tp->t_open == 0)
        !           969:                                goto rescan;
        !           970:                        /*
        !           971:                         * Must recognize XOFF quickly to avoid transmit overrun.
        !           972:                         * Recognize XON here as well to avoid race conditions.
        !           973:                         */
        !           974:                        if (!ISRIN) {
        !           975:                                /*
        !           976:                                 * XOFF.
        !           977:                                 */
        !           978:                                if (ISSTOP) {
        !           979:                                        tp->t_flags |= T_STOP;
        !           980:                                        goto rescan;
        !           981:                                }
        !           982: 
        !           983:                                /*
        !           984:                                 * XON.
        !           985:                                 */
        !           986:                                if (ISSTART) {
        !           987:                                        tp->t_flags &= ~T_STOP;
        !           988:                                        goto rescan;
        !           989:                                }
        !           990:                        }
        !           991: 
        !           992:                        /*
        !           993:                         * Save char in raw input buffer.
        !           994:                         */
        !           995: #ifdef NO_ISILO
        !           996:                        if (tp->t_flags & T_ISTOP) {
        !           997:                                /*
        !           998:                                 * If using hardware flow control, we need to drop RTS.
        !           999:                                 */
        !          1000:                                if (tp->t_flags & T_CFLOW) {
        !          1001:                                        unsigned char mcr = inb(port+MCR);
        !          1002:                                        if (mcr & MC_RTS)
        !          1003:                                                outb(port+MCR, mcr & ~MC_RTS);
        !          1004:                                }
        !          1005:                        } else {
        !          1006:                                ttin(tp, c);
        !          1007:                        }
        !          1008: #else
        !          1009:                        if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) {
        !          1010:                                in_silo->si_buf[in_silo->si_ix] = c;
        !          1011:                                if (in_silo->si_ix < MAX_SILO_INDEX)
        !          1012:                                        in_silo->si_ix++;
        !          1013:                                else
        !          1014:                                        in_silo->si_ix = 0;
        !          1015:                                in_silo->SILO_CHAR_COUNT++;
        !          1016:                        }
        !          1017: 
        !          1018:                        /*
        !          1019:                         * If using hardware flow control, see if we need to drop RTS.
        !          1020:                         */
        !          1021:                        if ( (tp->t_flags & T_CFLOW)
        !          1022:                        && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
        !          1023:                                unsigned char mcr = inb(port+MCR);
        !          1024:                                if (mcr & MC_RTS) {
        !          1025:                                        outb(port+MCR, mcr & ~MC_RTS);
        !          1026:                                }
        !          1027:                        }
        !          1028: #endif
        !          1029:                        goto rescan;
        !          1030: 
        !          1031:                case Tx_INTR:
        !          1032:                        /*
        !          1033:                         * Do nothing if output is stopped.
        !          1034:                         */
        !          1035:                        if (tp->t_flags & T_STOP)
        !          1036:                                goto rescan;
        !          1037:                        if (com_usage[AL_NUM].ohlt)
        !          1038:                                goto rescan;
        !          1039: 
        !          1040:                        /*
        !          1041:                         * Transmit next char in raw output buffer.
        !          1042:                         */
        !          1043:                        xmit_count =
        !          1044:                          (com_usage[AL_NUM].uart_type == US_16550A)?16:1;
        !          1045:                        alx_send(out_silo, port+DREG, xmit_count);
        !          1046:                        goto rescan;
        !          1047: 
        !          1048:                case MS_INTR:
        !          1049:                        /*
        !          1050:                         * Get status (and clear interrupt).
        !          1051:                         */
        !          1052:                        msr = inb(port+MSR);
        !          1053: 
        !          1054:                        /*
        !          1055:                         * Hardware flow control.
        !          1056:                         *      Check CTS to see if we need to halt output.
        !          1057:                         */
        !          1058:                        if (tp->t_flags & T_CFLOW) {
        !          1059:                                if (msr & MS_CTS)
        !          1060:                                        com_usage[AL_NUM].ohlt = 0;
        !          1061:                                else
        !          1062:                                        com_usage[AL_NUM].ohlt = 1;
        !          1063:                        }
        !          1064: 
        !          1065:                        goto rescan;
        !          1066:                } /* endswitch */
        !          1067:        } else {
        !          1068:                /*
        !          1069:                 * If tp is zero, an interrupt occurred before things
        !          1070:                 * are fully set up.  Just try to clear all pending
        !          1071:                 * interrupts from ANY serial ports.
        !          1072:                 */
        !          1073:                int com_num;
        !          1074:                for (com_num = 0; com_num < 4; com_num++) {
        !          1075:                        port = AL_ADDR[com_num];
        !          1076:                        inb(port+IIR);
        !          1077:                        inb(port+LSR);
        !          1078:                        inb(port+MSR);
        !          1079:                        inb(port+DREG);
        !          1080:                }
        !          1081:        }
        !          1082: }
        !          1083: 
        !          1084: /*
        !          1085:  * alxclk will be called every time T0 interrupts - if it returns 0,
        !          1086:  * the usual system timer interrupt stuff is done
        !          1087:  */
        !          1088: static int alxclk()
        !          1089: {
        !          1090:        static int count;
        !          1091:        int i;
        !          1092: 
        !          1093:        for (i = 0; i < NUM_AL_PORTS;  i++)
        !          1094:                if (com_usage[i].poll)
        !          1095:                        alxpoll(tp_table[i]);
        !          1096:        count++;
        !          1097:        if (count >= poll_divisor)
        !          1098:                count = 0;
        !          1099:        return count;
        !          1100: }
        !          1101: 
        !          1102: /*
        !          1103:  * set_poll_rate is called when a port is opened or closed or changes speed
        !          1104:  * it sets the polling rate only as fast as needed, and shuts off polling
        !          1105:  * whenever possible
        !          1106:  */
        !          1107: static set_poll_rate()
        !          1108: {
        !          1109:        int port_num, max_rate, port_rate;
        !          1110: 
        !          1111:        /*
        !          1112:         * If another driver has the polling clock, do nothing.
        !          1113:         */
        !          1114:        if (poll_owner & ~ POLL_AL)
        !          1115:                return;
        !          1116: 
        !          1117:        /*
        !          1118:         * Find highest valid polling rate in units of HZ/10.
        !          1119:         * If using FIFO chip, can poll at 1/16 the usual rate.
        !          1120:         */
        !          1121:        max_rate = 0;
        !          1122:        for (port_num = 0; port_num < NUM_AL_PORTS; port_num++) {
        !          1123:                if (com_usage[port_num].poll) {
        !          1124:                        port_rate = alp_rate[(tp_table[port_num])->t_sgttyb.sg_ispeed];
        !          1125:                        if (com_usage[port_num].uart_type == US_16550A) {
        !          1126:                                port_rate /= 16;
        !          1127:                                if (port_rate % HZ)
        !          1128:                                        port_rate += HZ - (port_rate % HZ);
        !          1129:                        }
        !          1130:                        if (max_rate < port_rate)
        !          1131:                                max_rate = port_rate;
        !          1132:                }
        !          1133:        }
        !          1134:        /*
        !          1135:         * if max_rate is not current rate, adjust the system clock
        !          1136:         */
        !          1137:        if (max_rate != poll_rate) {
        !          1138:                poll_rate = max_rate;
        !          1139:                poll_divisor = poll_rate/HZ;  /* used in alxclk() */
        !          1140:                altclk_out();           /* stop previous polling */
        !          1141:                poll_owner &= ~ POLL_AL;
        !          1142:                if (max_rate) { /* resume polling at new rate if needed */
        !          1143:                        poll_owner |= POLL_AL;
        !          1144:                        altclk_in(poll_rate, alxclk);
        !          1145:                }
        !          1146:                CDUMP("new rate", 0)
        !          1147:        }
        !          1148: }
        !          1149: 
        !          1150: /*
        !          1151:  * alxpoll()
        !          1152:  *
        !          1153:  * Serial polling handler.  Compare to alxintr().
        !          1154:  */
        !          1155: static void alxpoll(tp)
        !          1156: register TTY * tp;
        !          1157: {
        !          1158:        int c;
        !          1159:        int port = ALPORT;
        !          1160:        int xmit_count;
        !          1161:        unsigned char lsr;
        !          1162:        silo_t * in_silo = &com_usage[AL_NUM].raw_in;
        !          1163:        silo_t * out_silo = &com_usage[AL_NUM].raw_out;
        !          1164: 
        !          1165:        /*
        !          1166:         * Check for received break first.
        !          1167:         * This status is wiped out on reading the LSR.
        !          1168:         */
        !          1169:        LSR_READ(lsr, port);
        !          1170:        if (lsr & LS_BREAK)
        !          1171:                defer(alxbreak, tp);
        !          1172: 
        !          1173:        /*
        !          1174:         * Handle all incoming characters.
        !          1175:         */
        !          1176:        for (;;) {
        !          1177:                LSR_READ(lsr, port);
        !          1178:                if ((lsr & LS_RxRDY) == 0)
        !          1179:                        break;
        !          1180:                c = inb(port+DREG);
        !          1181:                if (tp->t_open == 0)
        !          1182:                        continue;
        !          1183:                /*
        !          1184:                 * Must recognize XOFF quickly to avoid transmit overrun.
        !          1185:                 * Recognize XON here as well to avoid race conditions.
        !          1186:                 */
        !          1187:                if (!ISRIN) {
        !          1188:                        /*
        !          1189:                         * XOFF.
        !          1190:                         */
        !          1191:                        if (ISSTOP) {
        !          1192:                                tp->t_flags |= T_STOP;
        !          1193:                                continue;
        !          1194:                        }
        !          1195: 
        !          1196:                        /*
        !          1197:                         * XON.
        !          1198:                         */
        !          1199:                        if (ISSTART) {
        !          1200:                                tp->t_flags &= ~T_STOP;
        !          1201:                                continue;
        !          1202:                        }
        !          1203:                }
        !          1204: 
        !          1205:                /*
        !          1206:                 * Save char in raw input buffer.
        !          1207:                 */
        !          1208: #ifdef NO_ISILO
        !          1209:                if (tp->t_flags & T_ISTOP) {
        !          1210:                        /*
        !          1211:                         * If using hardware flow control, we need to drop RTS.
        !          1212:                         */
        !          1213:                        if (tp->t_flags & T_CFLOW) {
        !          1214:                                unsigned char mcr = inb(port+MCR);
        !          1215:                                if (mcr & MC_RTS)
        !          1216:                                        outb(port+MCR, mcr & ~MC_RTS);
        !          1217:                        }
        !          1218:                } else {
        !          1219:                        ttin(tp, c);
        !          1220:                }
        !          1221: #else
        !          1222:                if (in_silo->SILO_CHAR_COUNT < MAX_SILO_CHARS) {
        !          1223:                        in_silo->si_buf[in_silo->si_ix] = c;
        !          1224:                        if (in_silo->si_ix < MAX_SILO_INDEX)
        !          1225:                                in_silo->si_ix++;
        !          1226:                        else
        !          1227:                                in_silo->si_ix = 0;
        !          1228:                        in_silo->SILO_CHAR_COUNT++;
        !          1229:                }
        !          1230: 
        !          1231:                /*
        !          1232:                 * If using hardware flow control, see if we need to drop RTS.
        !          1233:                 */
        !          1234:                if ( (tp->t_flags & T_CFLOW)
        !          1235:                  && (in_silo->SILO_CHAR_COUNT > SILO_HIGH_MARK)) {
        !          1236:                        unsigned char mcr = inb(port+MCR);
        !          1237:                        if (mcr & MC_RTS) {
        !          1238:                                outb(port+MCR, mcr & ~MC_RTS);
        !          1239:                        }
        !          1240:                }
        !          1241: #endif
        !          1242:        }
        !          1243: 
        !          1244:        /*
        !          1245:         * Handle outgoing characters.
        !          1246:         * Do nothing if output is stopped.
        !          1247:         */
        !          1248:        LSR_READ(lsr, port);
        !          1249:        if ((lsr & LS_TxRDY)
        !          1250:          && !(tp->t_flags & T_STOP)
        !          1251:          && !(com_usage[AL_NUM].ohlt)) {
        !          1252:                /*
        !          1253:                 * Transmit next char in raw output buffer.
        !          1254:                 */
        !          1255:                xmit_count = (com_usage[AL_NUM].uart_type == US_16550A)?16:1;
        !          1256:                alx_send(out_silo, port+DREG, xmit_count);
        !          1257:        }
        !          1258: 
        !          1259:        /*
        !          1260:         * Hardware flow control.
        !          1261:         *      Check CTS to see if we need to halt output.
        !          1262:         */
        !          1263:        if (tp->t_flags & T_CFLOW) {
        !          1264:                if (inb(port+MSR) & MS_CTS)
        !          1265:                        com_usage[AL_NUM].ohlt = 0;
        !          1266:                else
        !          1267:                        com_usage[AL_NUM].ohlt = 1;
        !          1268:        }
        !          1269: }
        !          1270: 
        !          1271: /*
        !          1272:  * alx_send()
        !          1273:  *
        !          1274:  * Write to xmit data register of the UART.
        !          1275:  * Assume all checking about whether it's time to send has been done already.
        !          1276:  * Called by time-critical IRQ and polling routines!
        !          1277:  *
        !          1278:  * "rawout" is the output silo for the TTY struct supplying data to the port.
        !          1279:  * "dreg" is the i/o address of the UART xmit data register.
        !          1280:  * "xmit_count" is the max number of chars we can write (16 for FIFO parts).
        !          1281:  */
        !          1282: static void alx_send(rawout, dreg, xmit_count)
        !          1283: register silo_t * rawout;
        !          1284: int dreg, xmit_count;
        !          1285: {
        !          1286:        /*
        !          1287:         * Transmit next chars in raw output buffer.
        !          1288:         */
        !          1289:        for (;(rawout->si_ix != rawout->si_ox) && xmit_count; xmit_count--) {
        !          1290:                outb(dreg, rawout->si_buf[rawout->si_ox]);
        !          1291:                /*
        !          1292:                 * Adjust raw output buffer output index.
        !          1293:                 */
        !          1294:                if (++rawout->si_ox >= sizeof(rawout->si_buf))
        !          1295:                        rawout->si_ox = 0;
        !          1296:        }
        !          1297: }

unix.superglobalmegacorp.com

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