Commit | Line | Data |
---|---|---|
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 | ||
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 |