diff options
Diffstat (limited to 'usr.sbin/xntpd/kernel/tty_chu.c')
-rw-r--r-- | usr.sbin/xntpd/kernel/tty_chu.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/usr.sbin/xntpd/kernel/tty_chu.c b/usr.sbin/xntpd/kernel/tty_chu.c new file mode 100644 index 0000000..4615875 --- /dev/null +++ b/usr.sbin/xntpd/kernel/tty_chu.c @@ -0,0 +1,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 |