⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tty_chu_streams.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
字号:
/* * CHU STREAMS module for SunOS * * Version 2.6 * * Copyright 1991-1994, Nick Sayer * * Special thanks to Greg Onufer for his debug assists. * Special thanks to Matthias Urlichs for the 4.1.x loadable driver support *   code. * Special wet-noodle whippings to Sun for not properly documenting *   ANYTHING that makes this stuff at all possible. * * Should be PUSHed directly on top of a serial I/O channel. * Provides complete chucode structures to user space. * * COMPILATION: * * * To make a SunOS 4.1.x compatable loadable module (from the ntp kernel * directory): * * % cc -c -I../include -DLOADABLE tty_chu_STREAMS.c * * The resulting .o file is the loadable module. Modload it * thusly: * * % modload tty_chu_STREAMS.o -entry _chuinit * * When none of the instances are pushed in a STREAM, you can * modunload the driver in the usual manner if you wish. * * As an alternative to loading it dynamically you can compile it * directly into the kernel by hacking str_conf.c. See the README * file for more details on doing it the old fashioned way. * * * To make a Solaris 2.x compatable module (from the ntp kernel * directory): * * % {gcc,cc} -c -I../include -DSOLARIS2 tty_chu_STREAMS.c * % ld -r -o /usr/kernel/strmod/chu tty_chu_STREAMS.o * % chmod 755 /usr/kernel/strmod/chu * * The OS will load it for you automagically when it is first pushed. * * If you get syntax errors from <sys/timer.h> (really references * to types that weren't typedef'd in gcc's version of types.h), * add -D_SYS_TIMER_H to blot out the miscreants. * * Under Solaris 2.2 and previous, do not attempt to modunload the * module unless you're SURE it's not in use. I haven't tried it, but * I've been told it won't do the right thing. Under Solaris 2.3 (and * presumably future revs) an attempt to unload the module when it's in * use will properly refuse with a "busy" message. * * * HISTORY: * * v2.6 - Mutexed the per-instance chucode just to be safe. * v2.5 - Fixed show-stopper bug in Solaris 2.x - qprocson(). * v2.4 - Added dynamic allocation support for Solaris 2.x. * v2.3 - Added support for Solaris 2.x. * v2.2 - Added SERVICE IMMEDIATE hack. * v2.1 - Added 'sixth byte' heuristics. * v2.0 - first version with an actual version number. *        Added support for new CHU 'second 31' data format. *        Deleted PEDANTIC and ANAL_RETENTIVE. * */#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/* * Number of microseconds we allow between * character arrivals.  The speed is 300 baud * so this should be somewhat more than 30 msec */#define	CHUMAXUSEC	(60*1000)	/* 60 msec */#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>#endifstatic 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 };/* * Here's our private data type and structs */struct priv_data {#ifdef SOLARIS2  kmutex_t chucode_mutex;#else  char in_use;#endif  struct chucode chu_struct;};#ifndef SOLARIS2struct priv_data our_priv_data[NCHU];#endif#ifdef SOLARIS2static 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 /* SOLARIS2 */#ifdef LOADABLE# ifdef sunstatic struct vdldrv vd ={    VDMAGIC_PSEUDO,    "chu",    NULL, NULL, NULL, 0, 0, NULL, NULL, 0, 0,};static struct fmodsw *chu_fmod;/*ARGSUSED*/chuinit (fc, vdp, vdi, vds)    unsigned int fc;    struct vddrv *vdp;    addr_t vdi;    struct vdstat *vds;{    switch (fc) {    case VDLOAD:        {            int dev, i;            /* Find free entry in fmodsw */            for (dev = 0; dev < fmodcnt; dev++) {                if (fmodsw[dev].f_str == NULL)                    break;            }            if (dev == fmodcnt)                return (ENODEV);            chu_fmod = &fmodsw[dev];	    /* If you think a kernel would have strcpy() you're mistaken. */            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) {                    /* One of the modules is still open */                    return (EBUSY);                }        }        chu_fmod->f_name[0] = '\0';        chu_fmod->f_str = NULL;        return 0;    case VDSTAT:        return 0;    default:        return EIO;    }}# endif /* sun */#endif /* LOADABLE */#if !defined(LOADABLE) && !defined(SOLARIS2)char chu_first_open=1;#endif/*ARGSUSED*/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  /* According to the docs, calling with KM_SLEEP can never     fail */  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}/*ARGSUSED*/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);}/* * Now the crux of the biscuit. * * We will be passed data from the man downstairs. If it's not a data * packet, it must be important, so pass it along unmunged. If, however, * it is a data packet, we're gonna do special stuff to it. We're going * to pass each character we get to the old line discipline code we * include below for just such an occasion. When the old ldisc code * gets a full chucode struct, we'll hand it back upstairs. * * chuinput takes a single character and q (as quickly as possible). * passback takes a pointer to a chucode struct and q and sends it upstream. */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;  }}/* * Writing to a chu device doesn't make sense, but we'll pass them * through in case they're important. */static int chuwput(q, mp)queue_t *q;mblk_t *mp;{  putnext(q,mp);}/* * Take a pointer to a filled chucode struct and a queue and * send the chucode stuff upstream */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);}/* * This routine was copied nearly verbatim from the old line discipline. */void chuinput(c,q)register u_char c;queue_t *q;{  register struct chucode *chuc;  register int i;  long sec, usec;  struct timeval tv;  /*   * Quick, Batman, get a timestamp! We need to do this   * right away. The time between the end of the stop bit   * and this point is critical, and should be as nearly   * constant and as short as possible. (Un)fortunately,   * the Sun's clock granularity is so big this isn't a   * major problem.   *   * uniqtime() is totally undocumented, but there you are.   */  uniqtime(&tv);#ifdef SOLARIS2  mutex_enter(&((struct priv_data *)q->q_ptr)->chucode_mutex);#endif  /*   * Now, locate the chu struct once so we don't have to do it   * over and over.   */  chuc=&(((struct priv_data *) (q->q_ptr))->chu_struct);	/*	 * 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.	 */  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.   */  chuc->codechars[i] = (u_char)c;  chuc->codetimes[i] = tv;  /*   * Now we perform the 'sixth byte' heuristics.   *   * This is a long story.   *   * We used to be able to count on the first byte of the code   * having a '6' in the LSD. This prevented most code framing   * errors (garbage before the first byte wouldn't typically   * have a 6 in the LSD). That's no longer the case.   *   * We can get around this, however, by noting that the 6th byte   * must be either equal to or one's complement of the first.   * If we get a sixth byte that ISN'T like that, then it may   * well be that the first byte is garbage. The right thing   * to do is to left-shift the whole buffer one count and   * continue to wait for the sixth byte.   */  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;      /*       * No match. Left-shift the buffer and try again       */      for(t=0;t<=NCHUCHARS/2;t++)      {	chuc->codechars[t]=chuc->codechars[t+1];	chuc->codetimes[t]=chuc->codetimes[t+1];      }      i--; /* This is because of the ++i immediately following */    }  }  /*   * We done yet?   */  if (++i < NCHUCHARS)  {    /*     * We're not done. Not much to do here. Save the count and wait     * for another character.     */    chuc->ncodechars = (u_char)i;  }  else  {    /*     * We are done. Mark this buffer full and pass it along.     */    chuc->ncodechars = NCHUCHARS;    /*     * Now we have a choice. Either the front half and back half     * have to match, or be one's complement of each other.     *     * So let's try the first byte and see     */    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); /* We're done! */    chuc->ncodechars = 0; /* Start all over again! */  }#ifdef SOLARIS2  mutex_exit(&((struct priv_data *)q->q_ptr)->chucode_mutex);#endif}#endif /* NCHU > 0 */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -