]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/ntp/kernel/tty_chu.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / ntp / kernel / tty_chu.c
1 /* tty_chu.c,v 3.1 1993/07/06 01:07:30 jbj Exp
2  * tty_chu.c - CHU line driver
3  */
4
5 #include "chu.h"
6 #if NCHU > 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
21 #include "../h/chudefs.h"
22
23 /*
24  * Line discipline for receiving CHU time codes.
25  * Does elementary noise elimination, takes time stamps after
26  * the arrival of each character, returns a buffer full of the
27  * received 10 character code and the associated time stamps.
28  */
29 #define NUMCHUBUFS      3
30
31 struct chudata {
32         u_char used;            /* Set to 1 when structure in use */
33         u_char lastindex;       /* least recently used buffer */
34         u_char curindex;        /* buffer to use */
35         u_char sleeping;        /* set to 1 when we're sleeping on a buffer */
36         struct chucode chubuf[NUMCHUBUFS];
37 } chu_data[NCHU];
38
39 /*
40  * Number of microseconds we allow between
41  * character arrivals.  The speed is 300 baud
42  * so this should be somewhat more than 30 msec
43  */
44 #define CHUMAXUSEC      (50*1000)       /* 50 msec */
45
46 int chu_debug = 0;
47
48 /*
49  * Open as CHU time discipline.  Called when discipline changed
50  * with ioctl, and changes the interpretation of the information
51  * in the tty structure.
52  */
53 /*ARGSUSED*/
54 chuopen(dev, tp)
55         dev_t dev;
56         register struct tty *tp;
57 {
58         register struct chudata *chu;
59
60         /*
61          * Don't allow multiple opens.  This will also protect us
62          * from someone opening /dev/tty
63          */
64         if (tp->t_line == CHULDISC)
65                 return (EBUSY);
66         ttywflush(tp);
67         for (chu = chu_data; chu < &chu_data[NCHU]; chu++)
68                 if (!chu->used)
69                         break;
70         if (chu >= &chu[NCHU])
71                 return (EBUSY);
72         chu->used++;
73         chu->lastindex = chu->curindex = 0;
74         chu->sleeping = 0;
75         chu->chubuf[0].ncodechars = 0;
76         tp->T_LINEP = (caddr_t) chu;
77         return (0);
78 }
79
80 /*
81  * Break down... called when discipline changed or from device
82  * close routine.
83  */
84 chuclose(tp)
85         register struct tty *tp;
86 {
87         register int s = spl5();
88
89         ((struct chudata *) tp->T_LINEP)->used = 0;
90         tp->t_cp = 0;
91         tp->t_inbuf = 0;
92         tp->t_rawq.c_cc = 0;            /* clear queues -- paranoid */
93         tp->t_canq.c_cc = 0;
94         tp->t_line = 0;                 /* paranoid: avoid races */
95         splx(s);
96 }
97
98 /*
99  * Read a CHU buffer.  Sleep on the current buffer
100  */
101 churead(tp, uio)
102         register struct tty *tp;
103         struct uio *uio;
104 {
105         register struct chudata *chu;
106         register struct chucode *chucode;
107         register int s;
108
109         if ((tp->t_state&TS_CARR_ON)==0)
110                 return (EIO);
111
112         chu = (struct chudata *) (tp->T_LINEP);
113
114         s = spl5();
115         chucode = &(chu->chubuf[chu->lastindex]);
116         while (chu->curindex == chu->lastindex) {
117                 chu->sleeping = 1;
118                 sleep((caddr_t)chucode, TTIPRI);
119         }
120         chu->sleeping = 0;
121         if (++(chu->lastindex) >= NUMCHUBUFS)
122                 chu->lastindex = 0;
123         splx(s);
124
125         return (uiomove((caddr_t)chucode, sizeof(*chucode), UIO_READ, uio));
126 }
127
128 /*
129  * Low level character input routine.
130  * If the character looks okay, grab a time stamp.  If the stuff in
131  * the buffer is too old, dump it and start fresh.  If the character is
132  * non-BCDish, everything in the buffer too.
133  */
134 chuinput(c, tp)
135         register int c;
136         register struct tty *tp;
137 {
138         register struct chudata *chu = (struct chudata *) tp->T_LINEP;
139         register struct chucode *chuc;
140         register int i;
141         long sec, usec;
142         struct timeval tv;
143
144         /*
145          * Do a check on the BSDness of the character.  This delays
146          * the time stamp a bit but saves a fair amount of overhead
147          * when the static is bad.
148          */
149         if (((c) & 0xf) > 9 || (((c)>>4) & 0xf) > 9) {
150                 chuc = &(chu->chubuf[chu->curindex]);
151                 chuc->ncodechars = 0;   /* blow all previous away */
152                 return;
153         }
154
155         /*
156          * Call microtime() to get the current time of day
157          */
158         microtime(&tv);
159
160         /*
161          * Compute the difference in this character's time stamp
162          * and the last.  If it exceeds the margin, blow away all
163          * the characters currently in the buffer.
164          */
165         chuc = &(chu->chubuf[chu->curindex]);
166         i = (int)chuc->ncodechars;
167         if (i > 0) {
168                 sec = tv.tv_sec - chuc->codetimes[i-1].tv_sec;
169                 usec = tv.tv_usec - chuc->codetimes[i-1].tv_usec;
170                 if (usec < 0) {
171                         sec -= 1;
172                         usec += 1000000;
173                 }
174                 if (sec != 0 || usec > CHUMAXUSEC) {
175                         i = 0;
176                         chuc->ncodechars = 0;
177                 }
178         }
179
180         /*
181          * Store the character.  If we're done, have to tell someone
182          */
183         chuc->codechars[i] = (u_char)c;
184         chuc->codetimes[i] = tv;
185
186         if (++i < NCHUCHARS) {
187                 /*
188                  * Not much to do here.  Save the count and wait
189                  * for another character.
190                  */
191                 chuc->ncodechars = (u_char)i;
192         } else {
193                 /*
194                  * Mark this buffer full and point at next.  If the
195                  * next buffer is full we overwrite it by bumping the
196                  * next pointer.
197                  */
198                 chuc->ncodechars = NCHUCHARS;
199                 if (++(chu->curindex) >= NUMCHUBUFS)
200                         chu->curindex = 0;
201                 if (chu->curindex == chu->lastindex)
202                         if (++(chu->lastindex) >= NUMCHUBUFS)
203                                 chu->lastindex = 0;
204                 chu->chubuf[chu->curindex].ncodechars = 0;
205
206                 /*
207                  * Wake up anyone sleeping on this.  Also wake up
208                  * selectors and/or deliver a SIGIO as required.
209                  */
210                 if (tp->t_rsel) {
211                         selwakeup(tp->t_rsel, tp->t_state&TS_RCOLL);
212                         tp->t_state &= ~TS_RCOLL;
213                         tp->t_rsel = 0;
214                 }
215                 if (tp->t_state & TS_ASYNC)
216                         gsignal(tp->t_pgrp, SIGIO);
217                 if (chu->sleeping)
218                         (void) wakeup((caddr_t)chuc);
219         }
220 }
221
222 /*
223  * Handle ioctls.  We reject all tty-style except those that
224  * change the line discipline.
225  */
226 chuioctl(tp, cmd, data, flag)
227         struct tty *tp;
228         int cmd;
229         caddr_t data;
230         int flag;
231 {
232
233         if ((cmd>>8) != 't')
234                 return (-1);
235         switch (cmd) {
236         case TIOCSETD:
237         case TIOCGETD:
238         case TIOCGETP:
239         case TIOCGETC:
240                 return (-1);
241         }
242         return (ENOTTY);        /* not quite appropriate */
243 }
244
245
246 chuselect(dev, rw)
247         dev_t dev;
248         int rw;
249 {
250         register struct tty *tp = &cdevsw[major(dev)].d_ttys[minor(dev)];
251         struct chudata *chu;
252         int s = spl5();
253
254         chu = (struct chudata *) (tp->T_LINEP);
255
256         switch (rw) {
257
258         case FREAD:
259                 if (chu->curindex != chu->lastindex)
260                         goto win;
261                 if (tp->t_rsel && tp->t_rsel->p_wchan == (caddr_t)&selwait)
262                         tp->t_state |= TS_RCOLL;
263                 else
264                         tp->t_rsel = u.u_procp;
265                 break;
266
267         case FWRITE:
268                 goto win;
269         }
270         splx(s);
271         return (0);
272 win:
273         splx(s);
274         return (1);
275 }
276 #endif NCHU