Annotation of coherent/b/kernel/io.386/hs.c, revision 1.1.1.1

1.1       root        1: /* (-lgl
                      2:  *     COHERENT Driver Kit Version 1.1.0
                      3:  *     Copyright (c) 1982, 1990 by Mark Williams Company.
                      4:  *     All rights reserved. May not be copied without permission.
                      5:  -lgl) */
                      6: /*
                      7:  * Polled Serial Port Device Driver.
                      8:  * - supports version 7 compatible ioctl
                      9:  */
                     10: 
                     11: #include <sys/coherent.h>
                     12: #include <sys/ins8250.h>
                     13: #include <sys/stat.h>
                     14: #include <sys/proc.h>
                     15: #include <sys/tty.h>           /* indirectly includes sgtty.h */
                     16: #include <sys/con.h>
                     17: #include <sys/devices.h>
                     18: #include <errno.h>
                     19: #include <sys/sched.h>         /* CVTTOUT, IVTTOUT, SVTTOUT */
                     20: #include <sys/poll_clk.h>
                     21: 
                     22: #ifdef _I386
                     23: #define        EEBUSY  EBUSY
                     24: #else
                     25: #define        EEBUSY  EDBUSY
                     26: #endif
                     27: 
                     28: /*
                     29:  * Definitions.
                     30:  *
                     31:  * HSBAUD is the highest baud rate supported by this driver
                     32:  * HS_HZ is the polling rate, i.e. the number of times per second
                     33:  *   at which all open ports are checked for input, output, and
                     34:  *   line status changes
                     35:  * MAX_HSNUM is the maximum number of devices that can be polled
                     36:  *   using this driver and can be revised up or down
                     37:  * PORT is a convenience macro for the base address of a port
                     38:  * port_config is the structure of the initial configuration for each
                     39:  *   polled port;  note that "speed" is NOT the actual baud rate, but
                     40:  *   the value of the symbol for that baud rate as defined in
                     41:  *   /usr/include/sgtty.h
                     42:  */
                     43: #define        HSBAUD  9600
                     44: #define        HS_HZ   (HSBAUD/6)
                     45: #define MAX_HSNUM      8
                     46: #define        PORT    ((int)(tp->t_ddp))
                     47: struct port_config {
                     48:        int     addr;   /* base address of the 8250-family UART */
                     49:        int     speed;  /* B0..B19200 */
                     50: };
                     51: 
                     52: /*
                     53:  * Export Variables - these can be patched without recompiling and linking
                     54:  *
                     55:  * HSNUM is the actual number of polled serial ports, and should be
                     56:  *   less than or equal to MAX_HSNUM
                     57:  * HS_PORTS is an array of address/speed pairs, one for each port
                     58:  */
                     59: int    HSNUM = 4;
                     60: struct port_config HS_PORTS[MAX_HSNUM] = {
                     61:        { 0x3F8, B9600 },
                     62:        { 0x2F8, B9600 },
                     63:        { 0x3E8, B9600 },
                     64:        { 0x2E8, B9600 }
                     65: };
                     66: 
                     67: /*
                     68:  * Export Functions.
                     69:  */
                     70: int    hsload();
                     71: int    hsopen();
                     72: int    hsclose();
                     73: int    hsread();
                     74: int    hswrite();
                     75: int    hsunload();
                     76: int    hspoll();
                     77: 
                     78: static void hsioctl();
                     79: 
                     80: int    hscycle();
                     81: int    hsintr();
                     82: int    hsparam();
                     83: int    hsstart();
                     84: int    hsclk();
                     85: int    set_poll_rate();
                     86: 
                     87: /*
                     88:  * Import Functions
                     89:  */
                     90: int    nulldev();
                     91: int    nonedev();
                     92: 
                     93: /*
                     94:  * Configuration table.
                     95:  */
                     96: CON hscon ={
                     97:        DFCHR|DFPOL,                    /* Flags */
                     98:        HS_MAJOR,                       /* Major index */
                     99:        hsopen,                         /* Open */
                    100:        hsclose,                        /* Close */
                    101:        nulldev,                        /* Block */
                    102:        hsread,                         /* Read */
                    103:        hswrite,                        /* Write */
                    104:        hsioctl,                        /* Ioctl */
                    105:        nulldev,                        /* Powerfail */
                    106:        nulldev,                        /* Timeout */
                    107:        hsload,                         /* Load */
                    108:        hsunload,                       /* Unload */
                    109:        hspoll                          /* Poll */
                    110: };
                    111: 
                    112: /*
                    113:  * Local variables.
                    114:  */
                    115: static TTY *hstty;
                    116: static silo_t *out_silos, *in_silos;
                    117: static TTY *hslimtty;
                    118: static TIM hstim;
                    119: static int poll_divisor;       /* used in hsclk() and set_poll_rate() */
                    120: static int iocbaud[MAX_HSNUM];
                    121: static char ioclcr[MAX_HSNUM];
                    122: 
                    123: /*
                    124:  * Time constant table.
                    125:  * Indexed by ioctl baud rate.
                    126:  */
                    127: extern int albaud[], alp_rate[];
                    128: 
                    129: /*
                    130:  * Load Routine.
                    131:  */
                    132: static hsload()
                    133: {
                    134:        register TTY * tp;
                    135:        register int port;
                    136:        int i, b;
                    137: 
                    138:        if ((in_silos = (silo_t *)kalloc(HSNUM*sizeof(silo_t))) == 0) {
                    139:                printf("hsload: can't allocate in_silos\n");
                    140:                return;
                    141:        }
                    142:        kclear(in_silos, HSNUM*sizeof(silo_t));
                    143: 
                    144:        if ((out_silos = (silo_t *)kalloc(HSNUM*sizeof(silo_t))) == 0) {
                    145:                printf("hsload: can't allocate out_silos\n");
                    146:                return;
                    147:        }
                    148:        kclear(out_silos, HSNUM*sizeof(silo_t));
                    149: 
                    150:        if ((hstty = (TTY *)kalloc(HSNUM*sizeof(TTY))) == 0) {
                    151:                printf("hsload: can't allocate tty's\n");
                    152:                return;
                    153:        }
                    154:        kclear(hstty, HSNUM*sizeof(TTY));
                    155: 
                    156:        for (i = 0; i < HSNUM; i++) {
                    157:                port = HS_PORTS[i].addr;
                    158:                tp = hstty + i;
                    159: 
                    160:                outb(port+MCR, 0);
                    161:                outb(port+IER, 0);
                    162: 
                    163:                tp->t_cs_sel  = cs_sel();
                    164:                tp->t_start   = hsstart;
                    165:                tp->t_param   = hsparam;
                    166:                tp->t_sgttyb.sg_ospeed = tp->t_sgttyb.sg_ispeed = 
                    167:                tp->t_dispeed = tp->t_dospeed = HS_PORTS[i].speed;
                    168:                tp->t_ddp     = port;
                    169: 
                    170:                b = albaud[ tp->t_sgttyb.sg_ospeed ];
                    171:                outb(port+LCR, LC_DLAB);
                    172:                outb(port+DLL, b);
                    173:                outb(port+DLH, b >> 8);
                    174:                outb(port+LCR, LC_CS8);
                    175: 
                    176:        }
                    177:        hslimtty = hstty + HSNUM;
                    178: }
                    179: 
                    180: static hsunload()
                    181: {
                    182:        if (hstty != (TTY *)0)
                    183:                kfree(hstty);
                    184: }
                    185: 
                    186: /*
                    187:  * Open Routine.
                    188:  */
                    189: hsopen(dev, mode)
                    190: dev_t dev;
                    191: {
                    192:        register TTY * tp = &hstty[ dev & 15 ];
                    193:        register int b;
                    194:        int s;
                    195: 
                    196:        /*
                    197:         * Verify hardware exists.
                    198:         */
                    199:        if ((PORT == 0) || (inb(PORT+IER) & ~IE_TxI)) {
                    200:                u.u_error = ENXIO;
                    201:                return;
                    202:        }
                    203: 
                    204:        /*
                    205:         * Can't open if another driver is using polling
                    206:         */
                    207:        if (poll_owner & ~ POLL_HS) {
                    208:                u.u_error = EEBUSY;
                    209:                return;
                    210:        }
                    211: 
                    212:        /*
                    213:         * Initialize if not already open.
                    214:         */
                    215:        if (++tp->t_open == 1) {
                    216:                ttopen(tp);
                    217: 
                    218:                if (dev & 0x80) {
                    219:                        s = sphi();
                    220:                        b = inb(PORT+MSR);
                    221:                        tp->t_flags |= T_MODC + T_STOP;
                    222:                        if (b & MS_CTS)
                    223:                                tp->t_flags &= ~T_STOP;
                    224:                        if (b & MS_DSR)
                    225:                                tp->t_flags |=  T_CARR;
                    226:                        spl(s);
                    227:                } else  {
                    228:                        tp->t_flags &= ~T_MODC;
                    229:                        tp->t_flags |=  T_CARR;
                    230:                }
                    231:                hscycle(tp);
                    232:        }
                    233:        ttsetgrp(tp, dev, mode);
                    234:        set_poll_rate();
                    235: }
                    236: 
                    237: /*
                    238:  * Close Routine.
                    239:  */
                    240: hsclose(dev)
                    241: dev_t dev;
                    242: {
                    243:        short chan = dev & 15;
                    244:        register TTY * tp = hstty + chan;
                    245:        silo_t * out_silo = out_silos + chan;
                    246: 
                    247:        /*
                    248:         * Reset if last close.
                    249:         */
                    250:        if (tp->t_open == 1) {
                    251:                int state;
                    252: 
                    253:                ttclose(tp);
                    254:                /*
                    255:                 * ttclose() only emptied the output queue tp->t_oq;
                    256:                 * now wait 0.1 sec for the silo to empty
                    257:                 * and allow a delay for the UART on-chip xmit buffer to empty
                    258:                 *
                    259:                 * state 2: waiting for silo to empty
                    260:                 * state 1: stalling so UART can empty xmit buffer
                    261:                 * state 0: done!
                    262:                 */
                    263:                state = 2;
                    264:                while (state) {
                    265:                        timeout(&hstim, 10, wakeup, (int)&hstim);
                    266: #ifdef _I386
                    267:                        x_sleep((char *)&hstim,
                    268:                          pritty, slpriNoSig, "hsopen");
                    269: #else
                    270:                        v_sleep((char *)&hstim,
                    271:                          CVTTOUT, IVTTOUT, SVTTOUT, "hsopen");
                    272: #endif
                    273:                        if (out_silo->si_ix == out_silo->si_ox  && state)
                    274:                                state--;
                    275:                }
                    276:        }
                    277: 
                    278:        --tp->t_open;
                    279:        set_poll_rate();
                    280: }
                    281: 
                    282: /*
                    283:  * Read Routine.
                    284:  */
                    285: hsread(dev, iop)
                    286: dev_t dev;
                    287: register IO * iop;
                    288: {
                    289:        ttread(&hstty[ dev & 15 ], iop);
                    290: }
                    291: 
                    292: /*
                    293:  * Write Routine.
                    294:  */
                    295: hswrite(dev, iop)
                    296: dev_t dev;
                    297: register IO * iop;
                    298: {
                    299:        ttwrite(&hstty[ dev & 15 ], iop);
                    300: }
                    301: 
                    302: /*
                    303:  * Ioctl Routine.
                    304:  */
                    305: static void
                    306: hsioctl(dev, com, vec)
                    307: dev_t  dev;
                    308: int    com;
                    309: struct sgttyb *vec;
                    310: {
                    311:        ttioctl(&hstty[ dev & 15 ], com, vec);
                    312: }
                    313: 
                    314: /*
                    315:  * Polling Routine.
                    316:  */
                    317: hspoll(dev, ev, msec)
                    318: dev_t dev;
                    319: int ev;
                    320: int msec;
                    321: {
                    322:        return ttpoll(&hstty[ dev & 15 ], ev, msec);
                    323: }
                    324: 
                    325: /*
                    326:  * Cyclic routine - invoked every clock tick to perform raw input/output.
                    327:  *
                    328:  *     Notes:  Invoked 10 times per second.
                    329:  */
                    330: hscycle(tp)
                    331: register TTY * tp;
                    332: {
                    333:        register int resid;
                    334:        register int c;
                    335:        int chan = tp - hstty;
                    336:        silo_t * out_silo = out_silos + chan;
                    337:        silo_t * in_silo = in_silos + chan;
                    338: 
                    339:        /*
                    340:         * Process rawin buf.
                    341:         */
                    342:        while (in_silo->si_ix != in_silo->si_ox) {
                    343: 
                    344:                ttin(tp, in_silo->si_buf[ in_silo->si_ox ]);
                    345: 
                    346:                if (in_silo->si_ox >= sizeof(in_silo->si_buf) - 1)
                    347:                        in_silo->si_ox = 0;
                    348:                else
                    349:                        in_silo->si_ox++;
                    350:        }
                    351: 
                    352:        /*
                    353:         * Calculate free output slot count.
                    354:         */
                    355:        resid  = sizeof(out_silo->si_buf) - 1;
                    356:        resid += out_silo->si_ox - out_silo->si_ix;
                    357:        resid %= sizeof(out_silo->si_buf);
                    358: 
                    359:        /*
                    360:         * Fill raw output buffer.
                    361:         */
                    362:        while ((--resid >= 0) && ((c = ttout(tp)) >= 0)) {
                    363: 
                    364:                out_silo->si_buf[ out_silo->si_ix ] = c;
                    365: 
                    366:                if (out_silo->si_ix >= sizeof(out_silo->si_buf) - 1)
                    367:                        out_silo->si_ix = 0;
                    368:                else
                    369:                        out_silo->si_ix++;
                    370:        }
                    371: 
                    372:        /*
                    373:         * (Re)start output, waking processes waiting to output, etc.
                    374:         */
                    375:        ttstart(tp);
                    376: 
                    377:        /*
                    378:         * Schedule next cycle.
                    379:         */
                    380:        if (tp->t_open != 0)
                    381:                timeout(&tp->t_rawtim, HZ/10, hscycle, tp);
                    382: }
                    383: 
                    384: /*
                    385:  * Clock Interrupt driven Polling routine.
                    386:  */
                    387: hsintr()
                    388: {
                    389:        register TTY * tp = hstty;
                    390:        register int b;
                    391:        silo_t * out_silo = out_silos;
                    392:        silo_t * in_silo = in_silos;
                    393: 
                    394:        for (tp = hstty, in_silo = in_silos, out_silo = out_silos;
                    395:          tp < hslimtty; tp++, in_silo++, out_silo++) {
                    396:                if (tp->t_open == 0)
                    397:                        continue;
                    398: 
                    399:                /*
                    400:                 * Check modem status if modem control is enabled.
                    401:                 */
                    402:                if (tp->t_flags & T_MODC) {
                    403: 
                    404:                        b = inb(PORT+MSR);
                    405: 
                    406:                        if (b & (MS_DCTS|MS_DDSR)) {
                    407: 
                    408:                                if (b & MS_DCTS) {
                    409:                                        if (b & MS_CTS)
                    410:                                                tp->t_flags &= ~T_STOP;
                    411:                                        else
                    412:                                                tp->t_flags |=  T_STOP;
                    413:                                }
                    414:                                if (b & MS_DDSR) {
                    415:                                        if (b & MS_DSR)
                    416:                                                tp->t_flags |=  T_CARR;
                    417:                                        else {
                    418:                                                tp->t_flags &= ~T_CARR;
                    419:                                                tthup(tp);
                    420:                                        }
                    421:                                }
                    422:                        }
                    423:                }
                    424: 
                    425:                b = inb(PORT+LSR);
                    426: 
                    427:                if ((b & LS_BREAK) && (tp->t_flags & T_CARR))
                    428:                        ttsignal(tp, SIGINT);
                    429: 
                    430:                /*
                    431:                 * Receive ready.
                    432:                 */
                    433:                if (b & LS_RxRDY) {
                    434: 
                    435:                        in_silo->si_buf[in_silo->si_ix] = inb(PORT+DREG);
                    436: 
                    437:                        if (tp->t_flags & T_CARR) {
                    438: 
                    439:                                if (++(in_silo->si_ix) >=
                    440:                                                sizeof(in_silo->si_buf))
                    441:                                        in_silo->si_ix = 0;
                    442:                        }
                    443:                }
                    444: 
                    445:                /*
                    446:                 * Transmit ready and raw output data exists.
                    447:                 */
                    448:                if ((b & LS_TxRDY) && ((tp->t_flags & T_STOP) == 0)
                    449:                  && (out_silo->si_ix != out_silo->si_ox)) {
                    450: 
                    451:                        outb(   PORT+DREG,
                    452:                                out_silo->si_buf[ out_silo->si_ox ]);
                    453: 
                    454:                        if (++(out_silo->si_ox) >=
                    455:                                        sizeof(out_silo->si_buf))
                    456:                                out_silo->si_ox = 0;
                    457:                }
                    458: 
                    459:        }
                    460: }
                    461: 
                    462: /*
                    463:  * Set hardware parameters.
                    464:  */
                    465: hsparam(tp)
                    466: register TTY * tp;
                    467: {
                    468:        int s;
                    469:        int hnum;
                    470:        int newbaud;
                    471:        char newlcr;
                    472:        int write_baud = 1, write_lcr = 1;
                    473: 
                    474:        newbaud = albaud[tp->t_sgttyb.sg_ospeed];
                    475: 
                    476:        switch (tp->t_sgttyb.sg_flags & (EVENP|ODDP|RAW)) {
                    477:        case ODDP:
                    478:                newlcr = LC_CS7|LC_PARENB;
                    479:                break;
                    480:        case EVENP:
                    481:                newlcr = LC_CS7|LC_PARENB|LC_PAREVEN;
                    482:                break;
                    483:        default:
                    484:                newlcr = LC_CS8;
                    485:                break;
                    486:        }
                    487:        
                    488:        hnum = tp - hstty;
                    489:        if (hnum >= 0 && hnum < HSNUM) {
                    490:                if (newbaud == iocbaud[hnum]) {
                    491:                        write_baud = 0;
                    492:                        if (newlcr == ioclcr[hnum]) {
                    493:                                write_lcr = 0;
                    494:                        }
                    495:                }
                    496:                iocbaud[hnum] = newbaud;
                    497:                ioclcr[hnum] = newlcr;
                    498:        }
                    499: 
                    500:        s = sphi();
                    501:        /*
                    502:         * Assert required modem control lines (DTR, RTS).
                    503:         */
                    504:        if (tp->t_sgttyb.sg_ospeed == B0) {
                    505:                outb(PORT+MCR, 0);
                    506:        } else {
                    507:                outb(PORT+MCR, MC_DTR | MC_RTS);
                    508:        }
                    509: 
                    510:        /*
                    511:         * Program baud rate.
                    512:         */
                    513:        if (write_baud) {
                    514:                outb(PORT+LCR, LC_DLAB);
                    515:                outb(PORT+DLL, newbaud);
                    516:                outb(PORT+DLH, newbaud >> 8);
                    517:        }
                    518: 
                    519:        /*
                    520:         * Program character size, parity.
                    521:         */
                    522:        if (write_lcr)
                    523:                outb(PORT+LCR, newlcr);
                    524: 
                    525:        /*
                    526:         * Enable Transmit Buffer Empty Interrupts.
                    527:         */
                    528:        outb(PORT+IER, IE_TxI);
                    529: 
                    530:        spl(s);
                    531:        set_poll_rate();
                    532: }
                    533: 
                    534: /*
                    535:  * Start Routine.
                    536:  */
                    537: hsstart(tp)
                    538: register TTY * tp;
                    539: {
                    540:        register int s;
                    541:        int chan = tp - hstty;
                    542:        silo_t * out_silo = out_silos + chan;
                    543: 
                    544:        /*
                    545:         * Transmit buffer is empty, and raw output buffer is not.
                    546:         */
                    547:        s = sphi();
                    548:        if ((inb(PORT+LSR) & LS_TxRDY)
                    549:          && (out_silo->si_ix != out_silo->si_ox)) {
                    550: 
                    551:                /*
                    552:                 * Send next char from raw output buffer.
                    553:                 */
                    554:                outb(PORT+DREG, out_silo->si_buf[ out_silo->si_ox ]);
                    555: 
                    556:                if (++out_silo->si_ox >= sizeof(out_silo->si_buf))
                    557:                        out_silo->si_ox = 0;
                    558:        }
                    559:        spl(s);
                    560: }
                    561: 
                    562: /*
                    563:  * hsclk will be called every time T0 interrupts - if it returns 0,
                    564:  * the usual system timer interrupt stuff is done
                    565:  */
                    566: static int hsclk()
                    567: {
                    568:        static int count;
                    569: 
                    570:        hsintr();
                    571:        count++;
                    572:        if (count >= poll_divisor)
                    573:                count = 0;
                    574:        return count;
                    575: }
                    576: 
                    577: /*
                    578:  * set_poll_rate is called when a port is opened or closed or changes speed
                    579:  * it sets the polling rate only as fast as needed, and shuts off polling
                    580:  * whenever possible
                    581:  */
                    582: static set_poll_rate()
                    583: {
                    584:        int port_num, max_rate, port_rate;
                    585: 
                    586:        /*
                    587:         * If another driver has the polling clock, do nothing.
                    588:         */
                    589:        if (poll_owner & ~ POLL_HS)
                    590:                return;
                    591: 
                    592:        /*
                    593:         * find highest valid polling rate in units of HZ/10
                    594:         */
                    595:        max_rate = 0;
                    596:        for (port_num = 0; port_num < HSNUM; port_num++) {
                    597:                if (hstty[port_num].t_open) {
                    598:                  port_rate = alp_rate[hstty[port_num].t_sgttyb.sg_ispeed];
                    599:                  if (max_rate < port_rate)
                    600:                        max_rate = port_rate;
                    601:                }
                    602:        }
                    603:        /*
                    604:         * if max_rate is not current rate, adjust the system clock
                    605:         */
                    606:        if (max_rate != poll_rate) {
                    607:                poll_rate = max_rate;
                    608:                poll_divisor = poll_rate/HZ;  /* used in hsclk() */
                    609:                altclk_out();           /* stop previous polling */
                    610:                poll_owner &= ~POLL_HS;
                    611:                if (max_rate) { /* resume polling at new rate if needed */
                    612:                        altclk_in(poll_rate, hsclk);
                    613:                        poll_owner |= POLL_HS;
                    614:                }
                    615:        }
                    616: }

unix.superglobalmegacorp.com

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