Annotation of embedaddon/ntp/kernel/tty_clk.c, revision 1.1

1.1     ! misho       1: /* tty_clk.c,v 3.1 1993/07/06 01:07:33 jbj Exp
        !             2:  * tty_clk.c - Generic line driver for receiving radio clock timecodes
        !             3:  */
        !             4: 
        !             5: #include "clk.h"
        !             6: #if NCLK > 0
        !             7: 
        !             8: #include "../h/param.h"
        !             9: #include "../h/types.h"
        !            10: #include "../h/systm.h"
        !            11: #include "../h/dir.h"
        !            12: #include "../h/user.h"
        !            13: #include "../h/ioctl.h"
        !            14: #include "../h/tty.h"
        !            15: #include "../h/proc.h"
        !            16: #include "../h/file.h"
        !            17: #include "../h/conf.h"
        !            18: #include "../h/buf.h"
        !            19: #include "../h/uio.h"
        !            20: #include "../h/clist.h"
        !            21: 
        !            22: /*
        !            23:  * This line discipline is intended to provide well performing
        !            24:  * generic support for the reception and time stamping of radio clock
        !            25:  * timecodes.  Most radio clock devices return a string where a
        !            26:  * particular character in the code (usually a \r) is on-time
        !            27:  * synchronized with the clock.  The idea here is to collect characters
        !            28:  * until (one of) the synchronization character(s) (we allow two) is seen.
        !            29:  * When the magic character arrives we take a timestamp by calling
        !            30:  * microtime() and insert the eight bytes of struct timeval into the
        !            31:  * buffer after the magic character.  We then wake up anyone waiting
        !            32:  * for the buffer and return the whole mess on the next read.
        !            33:  *
        !            34:  * To use this the calling program is expected to first open the
        !            35:  * port, and then to set the port into raw mode with the speed
        !            36:  * set appropriately with a TIOCSETP ioctl(), with the erase and kill
        !            37:  * characters set to those to be considered magic (yes, I know this
        !            38:  * is gross, but they were so convenient).  If only one character is
        !            39:  * magic you can set then both the same, or perhaps to the alternate
        !            40:  * parity versions of said character.  After getting all this set,
        !            41:  * change the line discipline to CLKLDISC and you are on your way.
        !            42:  *
        !            43:  * The only other bit of magic we do in here is to flush the receive
        !            44:  * buffers on writes if the CRMOD flag is set (hack, hack).
        !            45:  */
        !            46: 
        !            47: /*
        !            48:  * We run this very much like a raw mode terminal, with the exception
        !            49:  * that we store up characters locally until we hit one of the
        !            50:  * magic ones and then dump it into the rawq all at once.  We keep
        !            51:  * the buffered data in clists since we can then often move it to
        !            52:  * the rawq without copying.  For sanity we limit the number of
        !            53:  * characters between specials, and the total number of characters
        !            54:  * before we flush the rawq, as follows.
        !            55:  */
        !            56: #define        CLKLINESIZE     (256)
        !            57: #define        NCLKCHARS       (CLKLINESIZE*4)
        !            58: 
        !            59: struct clkdata {
        !            60:        int inuse;
        !            61:        struct clist clkbuf;
        !            62: };
        !            63: #define        clk_cc  clkbuf.c_cc
        !            64: #define        clk_cf  clkbuf.c_cf
        !            65: #define        clk_cl  clkbuf.c_cl
        !            66: 
        !            67: struct clkdata clk_data[NCLK];
        !            68: 
        !            69: /*
        !            70:  * Routine for flushing the internal clist
        !            71:  */
        !            72: #define        clk_bflush(clk)         (ndflush(&((clk)->clkbuf), (clk)->clk_cc))
        !            73: 
        !            74: int clk_debug = 0;
        !            75: 
        !            76: /*ARGSUSED*/
        !            77: clkopen(dev, tp)
        !            78:        dev_t dev;
        !            79:        register struct tty *tp;
        !            80: {
        !            81:        register struct clkdata *clk;
        !            82: 
        !            83:        /*
        !            84:         * Don't allow multiple opens.  This will also protect us
        !            85:         * from someone opening /dev/tty
        !            86:         */
        !            87:        if (tp->t_line == CLKLDISC)
        !            88:                return (EBUSY);
        !            89:        ttywflush(tp);
        !            90:        for (clk = clk_data; clk < &clk_data[NCLK]; clk++)
        !            91:                if (!clk->inuse)
        !            92:                        break;
        !            93:        if (clk >= &clk_data[NCLK])
        !            94:                return (EBUSY);
        !            95:        clk->inuse++;
        !            96:        clk->clk_cc = 0;
        !            97:        clk->clk_cf = clk->clk_cl = NULL;
        !            98:        tp->T_LINEP = (caddr_t) clk;
        !            99:        return (0);
        !           100: }
        !           101: 
        !           102: 
        !           103: /*
        !           104:  * Break down... called when discipline changed or from device
        !           105:  * close routine.
        !           106:  */
        !           107: clkclose(tp)
        !           108:        register struct tty *tp;
        !           109: {
        !           110:        register struct clkdata *clk;
        !           111:        register int s = spltty();
        !           112: 
        !           113:        clk = (struct clkdata *)tp->T_LINEP;
        !           114:        if (clk->clk_cc > 0)
        !           115:                clk_bflush(clk);
        !           116:        clk->inuse = 0;
        !           117:        tp->t_line = 0;                 /* paranoid: avoid races */
        !           118:        splx(s);
        !           119: }
        !           120: 
        !           121: 
        !           122: /*
        !           123:  * Receive a write request.  We pass these requests on to the terminal
        !           124:  * driver, except that if the CRMOD bit is set in the flags we
        !           125:  * first flush the input queues.
        !           126:  */
        !           127: clkwrite(tp, uio)
        !           128:        register struct tty *tp;
        !           129:        struct uio *uio;
        !           130: {
        !           131:        if (tp->t_flags & CRMOD) {
        !           132:                register struct clkdata *clk;
        !           133:                int s;
        !           134: 
        !           135:                s = spltty();
        !           136:                if (tp->t_rawq.c_cc > 0)
        !           137:                        ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
        !           138:                clk = (struct clkdata *) tp->T_LINEP;
        !           139:                if (clk->clk_cc > 0)
        !           140:                        clk_bflush(clk);
        !           141:                (void)splx(s);
        !           142:        }
        !           143:        ttwrite(tp, uio);
        !           144: }
        !           145: 
        !           146: 
        !           147: /*
        !           148:  * Low level character input routine.
        !           149:  * If the character looks okay, grab a time stamp.  If the stuff in
        !           150:  * the buffer is too old, dump it and start fresh.  If the character is
        !           151:  * non-BCDish, everything in the buffer too.
        !           152:  */
        !           153: clkinput(c, tp)
        !           154:        register int c;
        !           155:        register struct tty *tp;
        !           156: {
        !           157:        register struct clkdata *clk;
        !           158:        register int i;
        !           159:        register long s;
        !           160:        struct timeval tv;
        !           161: 
        !           162:        /*
        !           163:         * Check to see whether this isn't the magic character.  If not,
        !           164:         * save the character and return.
        !           165:         */
        !           166: #ifdef ultrix
        !           167:        if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) {
        !           168: #else
        !           169:        if (c != tp->t_erase && c != tp->t_kill) {
        !           170: #endif
        !           171:                clk = (struct clkdata *) tp->T_LINEP;
        !           172:                if (clk->clk_cc >= CLKLINESIZE)
        !           173:                        clk_bflush(clk);
        !           174:                if (putc(c, &clk->clkbuf) == -1) {
        !           175:                        /*
        !           176:                         * Hopeless, no clists.  Flush what we have
        !           177:                         * and hope things improve.
        !           178:                         */
        !           179:                        clk_bflush(clk);
        !           180:                }
        !           181:                return;
        !           182:        }
        !           183: 
        !           184:        /*
        !           185:         * Here we have a magic character.  Get a timestamp and store
        !           186:         * everything.
        !           187:         */
        !           188:        microtime(&tv);
        !           189:        clk = (struct clkdata *) tp->T_LINEP;
        !           190: 
        !           191:        if (putc(c, &clk->clkbuf) == -1)
        !           192:                goto flushout;
        !           193:        
        !           194: #ifdef CLKLDISC
        !           195:        /*
        !           196:         * STREAMS people started writing timestamps this way.
        !           197:         * It's not my fault, I am just going along with the flow...
        !           198:         */
        !           199:        for (i = 0; i < sizeof(struct timeval); i++)
        !           200:                if (putc(*( ((char*)&tv) + i ), &clk->clkbuf) == -1)
        !           201:                        goto flushout;
        !           202: #else
        !           203:        /*
        !           204:         * This is a machine independant way of puting longs into
        !           205:         * the datastream.  It has fallen into disuse...
        !           206:         */
        !           207:        s = tv.tv_sec;
        !           208:        for (i = 0; i < sizeof(long); i++) {
        !           209:                if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
        !           210:                        goto flushout;
        !           211:                s <<= 8;
        !           212:        }
        !           213: 
        !           214:        s = tv.tv_usec;
        !           215:        for (i = 0; i < sizeof(long); i++) {
        !           216:                if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
        !           217:                        goto flushout;
        !           218:                s <<= 8;
        !           219:        }
        !           220: #endif
        !           221: 
        !           222:        /*
        !           223:         * If the length of the rawq exceeds our sanity limit, dump
        !           224:         * all the old crap in there before copying this in.
        !           225:         */
        !           226:        if (tp->t_rawq.c_cc > NCLKCHARS)
        !           227:                ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
        !           228:        
        !           229:        /*
        !           230:         * Now copy the buffer in.  There is a special case optimization
        !           231:         * here.  If there is nothing on the rawq at present we can
        !           232:         * just copy the clists we own over.  Otherwise we must concatenate
        !           233:         * the present data on the end.
        !           234:         */
        !           235:        s = (long)spltty();
        !           236:        if (tp->t_rawq.c_cc <= 0) {
        !           237:                tp->t_rawq = clk->clkbuf;
        !           238:                clk->clk_cc = 0;
        !           239:                clk->clk_cl = clk->clk_cf = NULL;
        !           240:                (void) splx((int)s);
        !           241:        } else {
        !           242:                (void) splx((int)s);
        !           243:                catq(&clk->clkbuf, &tp->t_rawq);
        !           244:                clk_bflush(clk);
        !           245:        }
        !           246: 
        !           247:        /*
        !           248:         * Tell the world
        !           249:         */
        !           250:        ttwakeup(tp);
        !           251:        return;
        !           252: 
        !           253: flushout:
        !           254:        /*
        !           255:         * It would be nice if this never happened.  Flush the
        !           256:         * internal clists and hope someone else frees some of them
        !           257:         */
        !           258:        clk_bflush(clk);
        !           259:        return;
        !           260: }
        !           261: 
        !           262: 
        !           263: /*
        !           264:  * Handle ioctls.  We reject most tty-style except those that
        !           265:  * change the line discipline and a couple of others..
        !           266:  */
        !           267: clkioctl(tp, cmd, data, flag)
        !           268:        struct tty *tp;
        !           269:        int cmd;
        !           270:        caddr_t data;
        !           271:        int flag;
        !           272: {
        !           273:        int flags;
        !           274:        struct sgttyb *sg;
        !           275: 
        !           276:        if ((cmd>>8) != 't')
        !           277:                return (-1);
        !           278:        switch (cmd) {
        !           279:        case TIOCSETD:
        !           280:        case TIOCGETD:
        !           281:        case TIOCGETP:
        !           282:        case TIOCGETC:
        !           283:        case TIOCOUTQ:
        !           284:                return (-1);
        !           285: 
        !           286:        case TIOCSETP:
        !           287:                /*
        !           288:                 * He likely wants to set new magic characters in.
        !           289:                 * Do this part.
        !           290:                 */
        !           291:                sg = (struct sgttyb *)data;
        !           292: #ifdef ultrix
        !           293:                tp->t_cc[VERASE] = sg->sg_erase;
        !           294:                tp->t_cc[VKILL] = sg->sg_kill;
        !           295: #else
        !           296:                tp->t_erase = sg->sg_erase;
        !           297:                tp->t_kill = sg->sg_kill;
        !           298: #endif
        !           299:                return (0);
        !           300: 
        !           301:        case TIOCFLUSH:
        !           302:                flags = *(int *)data;
        !           303:                if (flags == 0 || (flags & FREAD)) {
        !           304:                        register struct clkdata *clk;
        !           305: 
        !           306:                        clk = (struct clkdata *) tp->T_LINEP;
        !           307:                        if (clk->clk_cc > 0)
        !           308:                                clk_bflush(clk);
        !           309:                }
        !           310:                return (-1);
        !           311:        
        !           312:        default:
        !           313:                break;
        !           314:        }
        !           315:        return (ENOTTY);        /* not quite appropriate */
        !           316: }
        !           317: #endif NCLK

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>