[comp.protocols.time.ntp] tty_chu_STREAMS.c finished!

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

Since no one else stepped forward to say they had done so, I went ahead
and wrote it. If you have a Sun, you can now use the CHU driver in
xntpd. You need to make a small patch in refclock_chu.c to make this
work, then add this module to your kernel.

1. Fix refclock_chu.c: I didn't save the original, so I don't have
a patch, I'm afraid, but here's the relevant parts.

After the include of sgtty.h:

#ifdef STREAM
#include <stropts.h>
#endif

Later on, where the CHULDISC is set:

#ifdef STREAM
	/*
	 * Okay. Push the CHU stream on top of the tty.
	 */
	if (ioctl(fd, I_PUSH, "chu" ) < 0) {
		syslog(LOG_ERR, "chu clock: ioctl(%s, I_PUSH): %m", chudev);
		(void) close(fd);
		return 0;
	}
#else
	/*
	 * Okay.  Set the line discipline to the CHU line discipline, then
	 * give it to the I/O code to start receiving stuff.  Not the
	 * change of line discipline will clear the read buffers, which
	 * makes the change clean if done quickly.
	 */
	ldisc = CHULDISC;
	if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
		syslog(LOG_ERR, "chu clock: ioctl(%s, TIOCSETD): %m", chudev);
		(void) close(fd);
		return 0;
	}
#endif
	if (!io_addclock(&chu->chuio)) {

2. Edit Config. Add -DSTREAM and otherwise make ready for a CHU driver.
While you're at it, a local-clock-sync driver is a nice idea too.

3. Now make the kernel ready. Copy tty_chu_STREAMS.c to /sys/os/tty_chu.c.

4. Copy chudefs.h to /usr/include/sys and /sys/sys.

5. Add to /sys/conf.common/files.cmn:

os/tty_chu.c	optional chu

6. Add to /sys/sun/str_conf.c:

#include "chu.h"

and

#if NCHU>0
extern struct streaminfo chuinfo;
#endif

and right below the similar stuff for "ttcompat":

#if NCHU>0
	{ "chu", &chuinfo },
#endif

7. cd /sys/{ARCH}/conf directory and edit whatever conf file you
make your kernel from. You need to add:

pseudo-device	chu3	# CHU clock discipline

The '3' isn't cast in stone. I suppose '1' is more sensible.

8. config (whatever)

9. cd ../(whatever) ; make

10. (OPTIONAL) adb -w vmunix and take care of dosynctodr, noprintf and tickadj

11. Reboot with the new kernel. You should now be able to start xntpd,
add an appropriate peer (127.127.7.x) and try it out.

Note that in step 1 purists may wish to preceed the I_PUSH with a
series of I_POPs to get rid of ldterm and ttcompat. Sun clocks are
so crappy, however, that it's probably not worth the trouble.

tty_chu.c is copyrighted. You can distribute it only if you give
me credit and you don't charge for it. There's no warranty. If
you get kernel panics that keep you up nights, it's your own
damn fault for following my advice. :-)

Now then: Here's tty_chu_STREAMS.c:

----- 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.
 *
 */

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

#include <sys/types.h>
#include <sys/stream.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/kernel.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
 */
static struct chucode our_chu_struct;

static int chuopen(q, dev, flag, sflag)
queue_t *q;
dev_t dev;
int flag;
int sflag;
{
  our_chu_struct.ncodechars = 0;
  our_chu_struct.chustatus = 0;

  return(0);
}

static int chuclose(q, flag)
queue_t *q;
int flag;
{
  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;
	struct timezone tzp;

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

	/*
	 * Do a check on the BCDness 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;
		}
	}

	/*
	 * 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 pass it back!
		 */
		chuc->ncodechars = NCHUCHARS;
		chuc->chustatus = 0;

		passback(chuc,q); /* We're done! */
		chuc->ncodechars = 0; /* Start all over again! */
	}
}
----- 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  [44.2.1.17]      | brains, Bart's manners, and     |  May he never
209-952-5347 (Telebit)  | Maggie's appetite for TV.  --Me |  be silenced.