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

unix.superglobalmegacorp.com

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