Annotation of embedaddon/ntp/kernel/tty_clk.c, revision 1.1.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>