279 lines
6.0 KiB
C
279 lines
6.0 KiB
C
|
/* $NetBSD: tty_chu.c,v 1.1.1.1 2000/03/29 12:38:49 simonb Exp $ */
|
||
|
|
||
|
/* 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
|