Expand PMF_FN_* macros.
[netbsd-mini2440.git] / dist / ntp / kernel / tty_clk.c
blob14e22533ffbe9fe19a7e65ef26a45f820bceedf5
1 /* $NetBSD$ */
3 /* tty_clk.c,v 3.1 1993/07/06 01:07:33 jbj Exp
4 * tty_clk.c - Generic line driver for receiving radio clock timecodes
5 */
7 #include "clk.h"
8 #if NCLK > 0
10 #include "../h/param.h"
11 #include "../h/types.h"
12 #include "../h/systm.h"
13 #include "../h/dir.h"
14 #include "../h/user.h"
15 #include "../h/ioctl.h"
16 #include "../h/tty.h"
17 #include "../h/proc.h"
18 #include "../h/file.h"
19 #include "../h/conf.h"
20 #include "../h/buf.h"
21 #include "../h/uio.h"
22 #include "../h/clist.h"
25 * This line discipline is intended to provide well performing
26 * generic support for the reception and time stamping of radio clock
27 * timecodes. Most radio clock devices return a string where a
28 * particular character in the code (usually a \r) is on-time
29 * synchronized with the clock. The idea here is to collect characters
30 * until (one of) the synchronization character(s) (we allow two) is seen.
31 * When the magic character arrives we take a timestamp by calling
32 * microtime() and insert the eight bytes of struct timeval into the
33 * buffer after the magic character. We then wake up anyone waiting
34 * for the buffer and return the whole mess on the next read.
36 * To use this the calling program is expected to first open the
37 * port, and then to set the port into raw mode with the speed
38 * set appropriately with a TIOCSETP ioctl(), with the erase and kill
39 * characters set to those to be considered magic (yes, I know this
40 * is gross, but they were so convenient). If only one character is
41 * magic you can set then both the same, or perhaps to the alternate
42 * parity versions of said character. After getting all this set,
43 * change the line discipline to CLKLDISC and you are on your way.
45 * The only other bit of magic we do in here is to flush the receive
46 * buffers on writes if the CRMOD flag is set (hack, hack).
50 * We run this very much like a raw mode terminal, with the exception
51 * that we store up characters locally until we hit one of the
52 * magic ones and then dump it into the rawq all at once. We keep
53 * the buffered data in clists since we can then often move it to
54 * the rawq without copying. For sanity we limit the number of
55 * characters between specials, and the total number of characters
56 * before we flush the rawq, as follows.
58 #define CLKLINESIZE (256)
59 #define NCLKCHARS (CLKLINESIZE*4)
61 struct clkdata {
62 int inuse;
63 struct clist clkbuf;
65 #define clk_cc clkbuf.c_cc
66 #define clk_cf clkbuf.c_cf
67 #define clk_cl clkbuf.c_cl
69 struct clkdata clk_data[NCLK];
72 * Routine for flushing the internal clist
74 #define clk_bflush(clk) (ndflush(&((clk)->clkbuf), (clk)->clk_cc))
76 int clk_debug = 0;
78 /*ARGSUSED*/
79 clkopen(dev, tp)
80 dev_t dev;
81 register struct tty *tp;
83 register struct clkdata *clk;
86 * Don't allow multiple opens. This will also protect us
87 * from someone opening /dev/tty
89 if (tp->t_line == CLKLDISC)
90 return (EBUSY);
91 ttywflush(tp);
92 for (clk = clk_data; clk < &clk_data[NCLK]; clk++)
93 if (!clk->inuse)
94 break;
95 if (clk >= &clk_data[NCLK])
96 return (EBUSY);
97 clk->inuse++;
98 clk->clk_cc = 0;
99 clk->clk_cf = clk->clk_cl = NULL;
100 tp->T_LINEP = (caddr_t) clk;
101 return (0);
106 * Break down... called when discipline changed or from device
107 * close routine.
109 clkclose(tp)
110 register struct tty *tp;
112 register struct clkdata *clk;
113 register int s = spltty();
115 clk = (struct clkdata *)tp->T_LINEP;
116 if (clk->clk_cc > 0)
117 clk_bflush(clk);
118 clk->inuse = 0;
119 tp->t_line = 0; /* paranoid: avoid races */
120 splx(s);
125 * Receive a write request. We pass these requests on to the terminal
126 * driver, except that if the CRMOD bit is set in the flags we
127 * first flush the input queues.
129 clkwrite(tp, uio)
130 register struct tty *tp;
131 struct uio *uio;
133 if (tp->t_flags & CRMOD) {
134 register struct clkdata *clk;
135 int s;
137 s = spltty();
138 if (tp->t_rawq.c_cc > 0)
139 ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
140 clk = (struct clkdata *) tp->T_LINEP;
141 if (clk->clk_cc > 0)
142 clk_bflush(clk);
143 (void)splx(s);
145 ttwrite(tp, uio);
150 * Low level character input routine.
151 * If the character looks okay, grab a time stamp. If the stuff in
152 * the buffer is too old, dump it and start fresh. If the character is
153 * non-BCDish, everything in the buffer too.
155 clkinput(c, tp)
156 register int c;
157 register struct tty *tp;
159 register struct clkdata *clk;
160 register int i;
161 register long s;
162 struct timeval tv;
165 * Check to see whether this isn't the magic character. If not,
166 * save the character and return.
168 #ifdef ultrix
169 if (c != tp->t_cc[VERASE] && c != tp->t_cc[VKILL]) {
170 #else
171 if (c != tp->t_erase && c != tp->t_kill) {
172 #endif
173 clk = (struct clkdata *) tp->T_LINEP;
174 if (clk->clk_cc >= CLKLINESIZE)
175 clk_bflush(clk);
176 if (putc(c, &clk->clkbuf) == -1) {
178 * Hopeless, no clists. Flush what we have
179 * and hope things improve.
181 clk_bflush(clk);
183 return;
187 * Here we have a magic character. Get a timestamp and store
188 * everything.
190 microtime(&tv);
191 clk = (struct clkdata *) tp->T_LINEP;
193 if (putc(c, &clk->clkbuf) == -1)
194 goto flushout;
196 #ifdef CLKLDISC
198 * STREAMS people started writing timestamps this way.
199 * It's not my fault, I am just going along with the flow...
201 for (i = 0; i < sizeof(struct timeval); i++)
202 if (putc(*( ((char*)&tv) + i ), &clk->clkbuf) == -1)
203 goto flushout;
204 #else
206 * This is a machine independant way of puting longs into
207 * the datastream. It has fallen into disuse...
209 s = tv.tv_sec;
210 for (i = 0; i < sizeof(long); i++) {
211 if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
212 goto flushout;
213 s <<= 8;
216 s = tv.tv_usec;
217 for (i = 0; i < sizeof(long); i++) {
218 if (putc((s >> 24) & 0xff, &clk->clkbuf) == -1)
219 goto flushout;
220 s <<= 8;
222 #endif
225 * If the length of the rawq exceeds our sanity limit, dump
226 * all the old crap in there before copying this in.
228 if (tp->t_rawq.c_cc > NCLKCHARS)
229 ndflush(&tp->t_rawq, tp->t_rawq.c_cc);
232 * Now copy the buffer in. There is a special case optimization
233 * here. If there is nothing on the rawq at present we can
234 * just copy the clists we own over. Otherwise we must concatenate
235 * the present data on the end.
237 s = (long)spltty();
238 if (tp->t_rawq.c_cc <= 0) {
239 tp->t_rawq = clk->clkbuf;
240 clk->clk_cc = 0;
241 clk->clk_cl = clk->clk_cf = NULL;
242 (void) splx((int)s);
243 } else {
244 (void) splx((int)s);
245 catq(&clk->clkbuf, &tp->t_rawq);
246 clk_bflush(clk);
250 * Tell the world
252 ttwakeup(tp);
253 return;
255 flushout:
257 * It would be nice if this never happened. Flush the
258 * internal clists and hope someone else frees some of them
260 clk_bflush(clk);
261 return;
266 * Handle ioctls. We reject most tty-style except those that
267 * change the line discipline and a couple of others..
269 clkioctl(tp, cmd, data, flag)
270 struct tty *tp;
271 int cmd;
272 caddr_t data;
273 int flag;
275 int flags;
276 struct sgttyb *sg;
278 if ((cmd>>8) != 't')
279 return (-1);
280 switch (cmd) {
281 case TIOCSETD:
282 case TIOCGETD:
283 case TIOCGETP:
284 case TIOCGETC:
285 case TIOCOUTQ:
286 return (-1);
288 case TIOCSETP:
290 * He likely wants to set new magic characters in.
291 * Do this part.
293 sg = (struct sgttyb *)data;
294 #ifdef ultrix
295 tp->t_cc[VERASE] = sg->sg_erase;
296 tp->t_cc[VKILL] = sg->sg_kill;
297 #else
298 tp->t_erase = sg->sg_erase;
299 tp->t_kill = sg->sg_kill;
300 #endif
301 return (0);
303 case TIOCFLUSH:
304 flags = *(int *)data;
305 if (flags == 0 || (flags & FREAD)) {
306 register struct clkdata *clk;
308 clk = (struct clkdata *) tp->T_LINEP;
309 if (clk->clk_cc > 0)
310 clk_bflush(clk);
312 return (-1);
314 default:
315 break;
317 return (ENOTTY); /* not quite appropriate */
319 #endif NCLK