📄 tty_clk.c
字号:
/* tty_clk.c,v 3.1 1993/07/06 01:07:33 jbj Exp * tty_clk.c - Generic line driver for receiving radio clock timecodes */#include "clk.h"#if NCLK > 0#include "../h/param.h"#include "../h/types.h"#include "../h/systm.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/ioctl.h"#include "../h/tty.h"#include "../h/proc.h"#include "../h/file.h"#include "../h/conf.h"#include "../h/buf.h"#include "../h/uio.h"#include "../h/clist.h"/* * This line discipline is intended to provide well performing * generic support for the reception and time stamping of radio clock * timecodes. Most radio clock devices return a string where a * particular character in the code (usually a \r) is on-time * synchronized with the clock. The idea here is to collect characters * until (one of) the synchronization character(s) (we allow two) is seen. * When the magic character arrives we take a timestamp by calling * microtime() and insert the eight bytes of struct timeval into the * buffer after the magic character. We then wake up anyone waiting * for the buffer and return the whole mess on the next read. * * To use this the calling program is expected to first open the * port, and then to set the port into raw mode with the speed * set appropriately with a TIOCSETP ioctl(), with the erase and kill * characters set to those to be considered magic (yes, I know this * is gross, but they were so convenient). If only one character is * magic you can set then both the same, or perhaps to the alternate * parity versions of said character. After getting all this set, * change the line discipline to CLKLDISC and you are on your way. * * The only other bit of magic we do in here is to flush the receive * buffers on writes if the CRMOD flag is set (hack, hack). *//* * We run this very much like a raw mode terminal, with the exception * that we store up characters locally until we hit one of the * magic ones and then dump it into the rawq all at once. We keep * the buffered data in clists since we can then often move it to * the rawq without copying. For sanity we limit the number of * characters between specials, and the total number of characters * before we flush the rawq, as follows. */#define CLKLINESIZE (256)#define NCLKCHARS (CLKLINESIZE*4)struct clkdata { int inuse; struct clist clkbuf;};#define clk_cc clkbuf.c_cc#define clk_cf clkbuf.c_cf#define clk_cl clkbuf.c_clstruct clkdata clk_data[NCLK];/* * Routine for flushing the internal clist */#define clk_bflush(clk) (ndflush(&((clk)->clkbuf), (clk)->clk_cc))int clk_debug = 0;/*ARGSUSED*/clkopen(dev, tp) dev_t dev; register struct tty *tp;{ register struct clkdata *clk; /* * Don't allow multiple opens. This will also protect us * from someone opening /dev/tty */ if (tp->t_line == CLKLDISC) return (EBUSY); ttywflush(tp); for (clk = clk_data; clk < &clk_data[NCLK]; clk++) if (!clk->inuse) break; if (clk >= &clk_data[NCLK]) return (EBUSY); clk->inuse++; clk->clk_cc = 0; clk->clk_cf = clk->clk_cl = NULL; tp->T_LINEP = (caddr_t) clk; return (0);}/* * Break down... called when discipline changed or from device * close routine. */clkclose(tp) register struct tty *tp;{ register struct clkdata *clk; register int s = spltty(); clk = (struct clkdata *)tp->T_LINEP; if (clk->clk_cc > 0) clk_bflush(clk); clk->inuse = 0; tp->t_line = 0; /* paranoid: avoid races */ splx(s);}/* * Receive a write request. We pass these requests on to the terminal * driver, except that if the CRMOD bit is set in the flags we * first flush the input queues. */clkwrite(tp, uio) register struct tty *tp; struct uio *uio;{ if (tp->t_flags & CRMOD) { register struct clkdata *clk; int s; s = spltty(); if (tp->t_rawq.c_cc > 0) ndflush(&tp->t_rawq, tp->t_rawq.c_cc); clk = (struct clkdata *) tp->T_LINEP; if (clk->clk_cc > 0) clk_bflush(clk); (void)splx(s); } ttwrite(tp, uio);}/* * Low level character input routine. * If the character looks okay, grab a time stamp. If the stuff in * the buffer is too old, dump it and start fresh. If the character is * non-BCDish, everything in the buffer too. */clkinput(c, tp) register int c; register struct tty *tp;{ register struct clkdata *clk; register int i; register long s; struct timeval tv; /* * Check to see whether this isn't the magic character. If not, * save the character and return. */#ifdef ultrix if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) {#else if (c != tp->t_erase && c != tp->t_kill) {#endif clk = (struct clkdata *) tp->T_LINEP; if (clk->clk_cc >= CLKLINESIZE) clk_bflush(clk); if (putc(c, &clk->clkbuf) == -1) { /* * Hopeless, no clists. Flush what we have * and hope things improve. */ clk_bflush(clk); } return; } /* * Here we have a magic character. Get a timestamp and store * everything. */ microtime(&tv); clk = (struct clkdata *) tp->T_LINEP; if (putc(c, &clk->clkbuf) == -1) goto flushout; #ifdef CLKLDISC /* * STREAMS people started writing timestamps this way. * It's not my fault, I am just going along with the flow... */ for (i = 0; i < sizeof(struct timeval); i++) if (putc(*( ((char*)&tv) + i ), &clk->clkbuf) == -1) goto flushout;#else /* * This is a machine independant way of puting longs into * the datastream. It has fallen into disuse... */ s = tv.tv_sec; for (i = 0; i < sizeof(long); i++) { if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) goto flushout; s <<= 8; } s = tv.tv_usec; for (i = 0; i < sizeof(long); i++) { if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1) goto flushout; s <<= 8; }#endif /* * If the length of the rawq exceeds our sanity limit, dump * all the old crap in there before copying this in. */ if (tp->t_rawq.c_cc > NCLKCHARS) ndflush(&tp->t_rawq, tp->t_rawq.c_cc); /* * Now copy the buffer in. There is a special case optimization * here. If there is nothing on the rawq at present we can * just copy the clists we own over. Otherwise we must concatenate * the present data on the end. */ s = (long)spltty(); if (tp->t_rawq.c_cc <= 0) { tp->t_rawq = clk->clkbuf; clk->clk_cc = 0; clk->clk_cl = clk->clk_cf = NULL; (void) splx((int)s); } else { (void) splx((int)s); catq(&clk->clkbuf, &tp->t_rawq); clk_bflush(clk); } /* * Tell the world */ ttwakeup(tp); return;flushout: /* * It would be nice if this never happened. Flush the * internal clists and hope someone else frees some of them */ clk_bflush(clk); return;}/* * Handle ioctls. We reject most tty-style except those that * change the line discipline and a couple of others.. */clkioctl(tp, cmd, data, flag) struct tty *tp; int cmd; caddr_t data; int flag;{ int flags; struct sgttyb *sg; if ((cmd>>8) != 't') return (-1); switch (cmd) { case TIOCSETD: case TIOCGETD: case TIOCGETP: case TIOCGETC: case TIOCOUTQ: return (-1); case TIOCSETP: /* * He likely wants to set new magic characters in. * Do this part. */ sg = (struct sgttyb *)data;#ifdef ultrix tp->t_cc[VERASE] = sg->sg_erase; tp->t_cc[VKILL] = sg->sg_kill;#else tp->t_erase = sg->sg_erase; tp->t_kill = sg->sg_kill;#endif return (0); case TIOCFLUSH: flags = *(int *)data; if (flags == 0 || (flags & FREAD)) { register struct clkdata *clk; clk = (struct clkdata *) tp->T_LINEP; if (clk->clk_cc > 0) clk_bflush(clk); } return (-1); default: break; } return (ENOTTY); /* not quite appropriate */}#endif NCLK
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -