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.