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