File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / kernel / tty_clk.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 3 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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>