Annotation of coherent/d/PS2_KERNEL/io.386/hs.c, revision 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.