#ifdef SOLARIS2
# ifndef NCHU
# define NCHU 1
# endif
# define _KERNEL
#elif defined(LOADABLE)
# ifndef NCHU
# define NCHU 3
# define KERNEL
# endif
#else
# include "chu.h"
#endif
#if NCHU > 0
#define CHUMAXUSEC (60*1000)
#include <sys/types.h>
#include <sys/stream.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/errno.h>
#include <sys/user.h>
#include <syslog.h>
#include <sys/tty.h>
#include <sys/chudefs.h>
#ifdef SOLARIS2
#include <sys/ksynch.h>
#include <sys/kmem.h>
#include <sys/cmn_err.h>
#include <sys/conf.h>
#include <sys/strtty.h>
#include <sys/modctl.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#endif
#ifdef LOADABLE
#include <sys/kernel.h>
#include <sys/conf.h>
#include <sys/buf.h>
#include <sundev/mbvar.h>
#include <sun/autoconf.h>
#include <sun/vddrv.h>
#endif
static struct module_info rminfo = { 0, "chu", 0, INFPSZ, 0, 0 };
static struct module_info wminfo = { 0, "chu", 0, INFPSZ, 0, 0 };
static int chuopen(), churput(), chuwput(), chuclose();
static struct qinit rinit = { churput, NULL, chuopen, chuclose, NULL,
&rminfo, NULL };
static struct qinit winit = { chuwput, NULL, NULL, NULL, NULL,
&wminfo, NULL };
struct streamtab chuinfo = { &rinit, &winit, NULL, NULL };
struct priv_data
{
#ifdef SOLARIS2
kmutex_t chucode_mutex;
#else
char in_use;
#endif
struct chucode chu_struct;
};
#ifndef SOLARIS2
struct priv_data our_priv_data[NCHU];
#endif
#ifdef SOLARIS2
static struct fmodsw fsw =
{
"chu",
&chuinfo,
D_NEW | D_MP
};
extern struct mod_ops mod_strmodops;
static struct modlstrmod modlstrmod =
{
&mod_strmodops,
"CHU timecode decoder v2.6",
&fsw
};
static struct modlinkage modlinkage =
{
MODREV_1,
(void*) &modlstrmod,
NULL
};
int _init()
{
return mod_install(&modlinkage);
}
int _info(foo)
struct modinfo *foo;
{
return mod_info(&modlinkage,foo);
}
int _fini()
{
return mod_remove(&modlinkage);
}
#endif
#ifdef LOADABLE
# ifdef sun
static struct vdldrv vd =
{
VDMAGIC_PSEUDO,
"chu",
NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0,
};
static struct fmodsw *chu_fmod;
chuinit (fc, vdp, vdi, vds)
unsigned int fc;
struct vddrv *vdp;
addr_t vdi;
struct vdstat *vds;
{
switch (fc) {
case VDLOAD:
{
int dev, i;
for (dev = 0; dev < fmodcnt; dev++) {
if (fmodsw[dev].f_str == NULL)
break;
}
if (dev == fmodcnt)
return (ENODEV);
chu_fmod = &fmodsw[dev];
for (i = 0; i <= FMNAMESZ; i++)
chu_fmod->f_name[i] = wminfo.mi_idname[i];
chu_fmod->f_str = &chuinfo;
}
vdp->vdd_vdtab = (struct vdlinkage *) & vd;
{
int i;
for (i=0; i<NCHU; i++)
our_priv_data[i].in_use=0;
}
return 0;
case VDUNLOAD:
{
int dev;
for (dev = 0; dev < NCHU; dev++)
if (our_priv_data[dev].in_use) {
return (EBUSY);
}
}
chu_fmod->f_name[0] = '\0';
chu_fmod->f_str = NULL;
return 0;
case VDSTAT:
return 0;
default:
return EIO;
}
}
# endif
#endif
#if !defined(LOADABLE) && !defined(SOLARIS2)
char chu_first_open=1;
#endif
static int chuopen(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag;
int sflag;
{
int i;
#if !defined(LOADABLE) && !defined(SOLARIS2)
if (chu_first_open)
{
chu_first_open=0;
for(i=0;i<NCHU;i++)
our_priv_data[i].in_use=0;
}
#endif
#ifdef SOLARIS2
q->q_ptr = kmem_alloc( sizeof(struct priv_data), KM_SLEEP );
((struct priv_data *) q->q_ptr)->chu_struct.ncodechars = 0;
mutex_init(&((struct priv_data *) q->q_ptr)->chucode_mutex,"Chucode Mutex",MUTEX_DRIVER,NULL);
qprocson(q);
if (!putnextctl1(WR(q), M_CTL, MC_SERVICEIMM))
{
qprocsoff(q);
mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex);
kmem_free(q->q_ptr, sizeof(struct chucode) );
return (EFAULT);
}
return 0;
#else
for(i=0;i<NCHU;i++)
if (!our_priv_data[i].in_use)
{
((struct priv_data *) (q->q_ptr))=&(our_priv_data[i]);
our_priv_data[i].in_use++;
our_priv_data[i].chu_struct.ncodechars = 0;
if (!putctl1(WR(q)->q_next, M_CTL, MC_SERVICEIMM))
{
our_priv_data[i].in_use=0;
u.u_error = EFAULT;
return (OPENFAIL);
}
return 0;
}
u.u_error = EBUSY;
return (OPENFAIL);
#endif
}
static int chuclose(q, flag)
queue_t *q;
int flag;
{
#ifdef SOLARIS2
qprocsoff(q);
mutex_destroy(&((struct priv_data *)q->q_ptr)->chucode_mutex);
kmem_free(q->q_ptr, sizeof(struct chucode) );
#else
((struct priv_data *) (q->q_ptr))->in_use=0;
#endif
return (0);
}
void chuinput();
void passback();
static int churput(q, mp)
queue_t *q;
mblk_t *mp;
{
mblk_t *bp;
switch(mp->b_datap->db_type)
{
case M_DATA:
for(bp=mp; bp!=NULL; bp=bp->b_cont)
{
while(bp->b_rptr < bp->b_wptr)
chuinput( ((u_char)*(bp->b_rptr++)) , q );
}
freemsg(mp);
break;
default:
putnext(q,mp);
break;
}
}
static int chuwput(q, mp)
queue_t *q;
mblk_t *mp;
{
putnext(q,mp);
}
void passback(outdata,q)
struct chucode *outdata;
queue_t *q;
{
mblk_t *mp;
int j;
mp=(mblk_t*) allocb(sizeof(struct chucode),BPRI_LO);
if (mp==NULL)
{
#ifdef SOLARIS2
cmn_err(CE_WARN,"chu module couldn't allocate message block");
#else
log(LOG_ERR,"chu: cannot allocate message");
#endif
return;
}
for(j=0;j<sizeof(struct chucode); j++)
*mp->b_wptr++ = *( ((char*)outdata) + j );
putnext(q,mp);
}
void chuinput(c,q)
register u_char c;
queue_t *q;
{
register struct chucode *chuc;
register int i;
long sec, usec;
struct timeval tv;
uniqtime(&tv);
#ifdef SOLARIS2
mutex_enter(&((struct priv_data *)q->q_ptr)->chucode_mutex);
#endif
chuc=&(((struct priv_data *) (q->q_ptr))->chu_struct);
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;
}
}
chuc->codechars[i] = (u_char)c;
chuc->codetimes[i] = tv;
if (i == NCHUCHARS/2)
{
register u_char temp_byte;
temp_byte=chuc->codechars[i] ^ chuc->codechars[0];
if ( (temp_byte) && (temp_byte!=0xff) )
{
register int t;
for(t=0;t<=NCHUCHARS/2;t++)
{
chuc->codechars[t]=chuc->codechars[t+1];
chuc->codetimes[t]=chuc->codetimes[t+1];
}
i--;
}
}
if (++i < NCHUCHARS)
{
chuc->ncodechars = (u_char)i;
}
else
{
chuc->ncodechars = NCHUCHARS;
if(chuc->codechars[0] == chuc->codechars[NCHUCHARS/2])
{
chuc->chutype = CHU_TIME;
for( i=0; i<(NCHUCHARS/2); i++)
if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)])
{
chuc->ncodechars = 0;
#ifdef SOLARIS2
mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
#endif
return;
}
}
else
{
chuc->chutype = CHU_YEAR;
for( i=0; i<(NCHUCHARS/2); i++)
if (((chuc->codechars[i] ^ chuc->codechars[i+(NCHUCHARS/2)]) & 0xff)
!= 0xff )
{
chuc->ncodechars = 0;
#ifdef SOLARIS2
mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
#endif
return;
}
}
passback(chuc,q);
chuc->ncodechars = 0;
}
#ifdef SOLARIS2
mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);
#endif
}
#endif