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>