[comp.protocols.time.ntp] Latest version of SunOS STREAMS CHU module

mrapple@quack.sac.ca.us (Nick Sayer) (05/21/91)

This version has stayed stable for about a week now, so it's probably
not going be changing much more.

To install this module:

1. copy it to /sys/os/tty_chu.c.

2. Copy the chudefs.h file in the xntpd distribution to /sys/sys
and /usr/include/sys.

3. Append:

os/tty_chu.c	optional chu

to /sys/conf.common/files.cmn.

4. Edit /sys/sun/str_conf.c to include in appropriate places:

#include "chu.h"
.
.
.
#if NCHU > 0
extern struct streamtab chuinfo;
#endif
.
.
.
#if NCHU > 0
	{ "chu", &chuinfo },
#endif

5. Edit /sys/{arch}/conf/{k_name} to include:

pseudo-device	chu		; CHU clock support

6. config {k_name} ; cd ../{k_name} ; make ; cp vmunix / ; reboot. You
know the routine.

To use it, just open a device, set it up as you please, pop off
existing modules until there's nothing left if you like (you should
be removing ttcompat and ldterm), then ioctl(fd, I_PUSH, "chu");.
From then on, any reads on the device will return a struct
chucode. Depending on how you set PEDANTIC and ANAL_RETENTIVE
in the driver you may or may not need to do some additional
checking on the data. Writes and ioctls to the file should
take place just as before.

I have modified refclock_chu.c in xntp/xntpd, and chutest in
xntp/clockstuff to (optionally) use this driver. If anyone's
interested, I can pass them along too. I'd love it if this
stuff was included in the xntp distribution on louie, too.
Suns may have crappy clocks, but there are a lot of them out there.

The next step, by the way, would be to hack up the kernel's clock
stuff so that a sub-millisecond interrupt could increment the
clock, but then do nothing else. Every 2000th interrupt would
then jump on into the current clock interrupt code. I'd love
a Sun with all the SunOS bugs fixed, another 4 megs of RAM and
a 100 usec clock granularity. Le sigh.

----- cut here -----
/*
 * CHU STREAMS module for SunOS 4.1
 *
 * Copyright 1991, Nick Sayer
 *
 * Special thanks to Greg Onufer for his debug assists.
 *
 * Should be PUSHed directly on top of a serial I/O channel.
 * Provides complete chucode structures to user space.
 *
 */

#include "chu.h"

#if NCHU > 1
	MORE_THAN_ONE_CHU_MODULE_NOT_ALLOWED
#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	(50*1000)	/* 50 msec */

/*
 * The original line discipline only checked to make sure
 * the chars were BCDish and they weren't slow in getting there.
 * If PEDANTIC is defined, it will also make sure both 'halves'
 * of the code are the same, and that the first character has
 * '6' in the LSB. If it passes PEDANTIC, there's not much
 * chance of it being invalid.
 */
#define PEDANTIC /* Get serious about error checking */

/*
 * If you _REALLY_ want to make sure things are OK, you can
 * also make sure the time values make sense - day of year
 * 1-366, hour 0-23, minute 0-59, and second 31-39.
 * PEDANTIC is sufficient, but ANAL_RETENTIVE is as
 * good as you can get.
 */
/* #define ANAL_RETENTIVE /* Get rediculous about error checking */

#ifdef ANAL_RETENTIVE
#ifndef PEDANTIC
#define PEDANTIC /* ANAL_RETENTIVE requires PEDANTIC */
#endif
#endif

#include <sys/types.h>
#include <sys/stream.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/kernel.h>
#include <sys/errno.h>
#include <sys/user.h>
#include <syslog.h>

#include <sys/chudefs.h>

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 };

/*
 * Here's our single, global chu code structure
 */
struct chucode our_chu_struct;

char in_use=0;

/*ARGSUSED*/
static int chuopen(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag;
int sflag;
{
  if (in_use)
  {
    u.u_error = EBUSY;
    return (OPENFAIL);
  }

  in_use++;

  our_chu_struct.ncodechars = 0;
  our_chu_struct.chustatus = 0;

  return(0);
}

/*ARGSUSED*/
static int chuclose(q, flag)
queue_t *q;
int flag;
{
  in_use=0;

  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)
  {
    log(LOG_ERR,"chu: cannot allocate message");
    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=&our_chu_struct;
  register int i;
  long sec, usec;
  struct timeval tv;

  /*
   * Quick, Batman, get a timestamp! Fortunately, us kernel
   * folk need only snarf a kernel struct.
   */
  tv=time;

  /*
   * Do a check on the BCDishness of the character.
   */
  if (((c) & 0xf) > 9 || (((c)>>4) & 0xf) > 9)
  {
    chuc->ncodechars = 0;	/* blow all previous away */
    return;
  }

	/*
	 * 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;
    }
  }

#ifdef PEDANTIC
  if ( (i == 0) && (((c) & 0xf) != 6) )
  {
    chuc->ncodechars = 0;
    return;
  }
#endif

  /*
   * Store the character. Are we done now?
   */
  chuc->codechars[i] = (u_char)c;
  chuc->codetimes[i] = tv;

  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.
     * Someone may make clever use of chustatus some day.
     */
    chuc->ncodechars = NCHUCHARS;
    chuc->chustatus = 0;

#ifdef PEDANTIC
    /*
     * The front half and back half must match
     */
    for( i=0; i<(NCHUCHARS/2); i++)
      if (chuc->codechars[i] != chuc->codechars[i+(NCHUCHARS/2)])
      {
        chuc->ncodechars = 0;
        return;
      }
#endif

#ifdef ANAL_RETENTIVE
    /*
     * Make sure the values make sense. Day first: 1-366.
     */
    i =((chuc->codechars[0]&0xf0)>>4)*100;
    i+=(chuc->codechars[1]&0x0f)*10;
    i+=(chuc->codechars[1]&0xf0)>>4;
    if (i<1 || i>366)
    {
      chuc->ncodechars = 0;
      return;
    }
    /*
     * Hour now: 0-23.
     */
    i =(chuc->codechars[2]&0x0f)*10;
    i+=(chuc->codechars[2]&0xf0)>>4;
    if (i<0 || i>23)
    {
      chuc->ncodechars = 0;
      return;
    }
    /*
     * Minute now: 0-59.
     */
    i =(chuc->codechars[3]&0x0f)*10;
    i+=(chuc->codechars[3]&0xf0)>>4;
    if (i<0 || i>59)
    {
      chuc->ncodechars = 0;
      return;
    }
    /*
     * Second now: 31-39.
     */
    i =(chuc->codechars[4]&0x0f)*10;
    i+=(chuc->codechars[4]&0xf0)>>4;
    if (i<31 || i>39)
    {
      chuc->ncodechars = 0;
      return;
    }

#endif

    passback(chuc,q); /* We're done! */
    chuc->ncodechars = 0; /* Start all over again! */
  }
}

#endif
----- ereh tuc -----

-- 
Nick Sayer              | Think of me as a recombinant    | RIP: Mel Blanc
mrapple@quack.sac.ca.us | Simpson: Homer's looks, Lisa's  |   1908-1989
N6QQQ                   | brains, Bart's manners, and     |  May he never
209-952-5347 (Telebit)  | Maggie's appetite for TV.  --Me |  be silenced.