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

unix.superglobalmegacorp.com

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