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
8 #include "../h/param.h"
9 #include "../h/types.h"
10 #include "../h/systm.h"
12 #include "../h/user.h"
13 #include "../h/ioctl.h"
15 #include "../h/proc.h"
16 #include "../h/file.h"
17 #include "../h/conf.h"
20 #include "../h/clist.h"
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.
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.
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).
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.
56 #define CLKLINESIZE (256)
57 #define NCLKCHARS (CLKLINESIZE*4)
63 #define clk_cc clkbuf.c_cc
64 #define clk_cf clkbuf.c_cf
65 #define clk_cl clkbuf.c_cl
67 struct clkdata clk_data[NCLK];
70 * Routine for flushing the internal clist
72 #define clk_bflush(clk) (ndflush(&((clk)->clkbuf), (clk)->clk_cc))
79 register struct tty *tp;
81 register struct clkdata *clk;
84 * Don't allow multiple opens. This will also protect us
85 * from someone opening /dev/tty
87 if (tp->t_line == CLKLDISC)
90 for (clk = clk_data; clk < &clk_data[NCLK]; clk++)
93 if (clk >= &clk_data[NCLK])
97 clk->clk_cf = clk->clk_cl = NULL;
98 tp->T_LINEP = (caddr_t) clk;
104 * Break down... called when discipline changed or from device
108 register struct tty *tp;
110 register struct clkdata *clk;
111 register int s = spltty();
113 clk = (struct clkdata *)tp->T_LINEP;
117 tp->t_line = 0; /* paranoid: avoid races */
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.
128 register struct tty *tp;
131 if (tp->t_flags & CRMOD) {
132 register struct clkdata *clk;
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;
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.
155 register struct tty *tp;
157 register struct clkdata *clk;
163 * Check to see whether this isn't the magic character. If not,
164 * save the character and return.
167 if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) {
169 if (c != tp->t_erase && c != tp->t_kill) {
171 clk = (struct clkdata *) tp->T_LINEP;
172 if (clk->clk_cc >= CLKLINESIZE)
174 if (putc(c, &clk->clkbuf) == -1) {
176 * Hopeless, no clists. Flush what we have
177 * and hope things improve.
185 * Here we have a magic character. Get a timestamp and store
189 clk = (struct clkdata *) tp->T_LINEP;
191 if (putc(c, &clk->clkbuf) == -1)
196 * STREAMS people started writing timestamps this way.
197 * It's not my fault, I am just going along with the flow...
199 for (i = 0; i < sizeof(struct timeval); i++)
200 if (putc(*( ((char*)&tv) + i ), &clk->clkbuf) == -1)
204 * This is a machine independant way of puting longs into
205 * the datastream. It has fallen into disuse...
208 for (i = 0; i < sizeof(long); i++) {
209 if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
215 for (i = 0; i < sizeof(long); i++) {
216 if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
223 * If the length of the rawq exceeds our sanity limit, dump
224 * all the old crap in there before copying this in.
226 if (tp->t_rawq.c_cc > NCLKCHARS)
227 ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
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.
236 if (tp->t_rawq.c_cc <= 0) {
237 tp->t_rawq = clk->clkbuf;
239 clk->clk_cl = clk->clk_cf = NULL;
243 catq(&clk->clkbuf, &tp->t_rawq);
255 * It would be nice if this never happened. Flush the
256 * internal clists and hope someone else frees some of them
264 * Handle ioctls. We reject most tty-style except those that
265 * change the line discipline and a couple of others..
267 clkioctl(tp, cmd, data, flag)
288 * He likely wants to set new magic characters in.
291 sg = (struct sgttyb *)data;
293 tp->t_cc[VERASE] = sg->sg_erase;
294 tp->t_cc[VKILL] = sg->sg_kill;
296 tp->t_erase = sg->sg_erase;
297 tp->t_kill = sg->sg_kill;
302 flags = *(int *)data;
303 if (flags == 0 || (flags & FREAD)) {
304 register struct clkdata *clk;
306 clk = (struct clkdata *) tp->T_LINEP;
315 return (ENOTTY); /* not quite appropriate */