This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / kern / tty_chu.c
CommitLineData
c4794f91
GW
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
31struct 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
46int 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*/
54chuopen(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 */
84chuclose(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 */
101churead(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 */
134chuinput(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 */
226chuioctl(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
246chuselect(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);
272win:
273 splx(s);
274 return (1);
275}
276#endif NCHU