Subject: PPS diffs, round #3
To: None <tech-kern@NetBSD.ORG>
From: Jonathan Stone <jonathan@DSG.Stanford.EDU>
List: tech-kern
Date: 04/21/1998 20:51:02
OK, I think this patch addresses Chris Torek's point. It could in
principle be extended from just PPS phase-error sampling to other
kinds of ``timestamping'', though that'd still require an extended
ioctl interface to fetch those other timestamps.

For now, I'm punting on POSIX timespecs, since xntpd doesn't use them.
Obviously the API should include nanosecond resolution (or even
CPU-tick, for CPUs faster than 1Gz) when the kernel supports
nanotime() or better.  Right now it'd be syntactic sugar,. and since
ntp expects timevals anyway, that's all I did.

I confess I cant rememebr the POSIX namespace rules: do just the DCD_*
`edge' values need to be protected, or the TIOC* namespace, too?


Index: sys/dev/ic/com.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/com.c,v
retrieving revision 1.143
diff -c -r1.143 com.c
*** com.c	1998/03/22 00:55:37	1.143
--- com.c	1998/04/22 03:44:48
***************
*** 595,600 ****
--- 595,605 ----
  	/* Clear any break condition set with TIOCSBRK. */
  	com_break(sc, 0);
  
+ 	/* Turn off PPS on last close. */
+ 	sc->sc_timestamp_state = DCD_NONE;
+ 	sc->sc_dopps = 0;
+ 
+ 
  	/*
  	 * Hang up if necessary.  Wait a bit, so the other side has time to
  	 * notice even if we immediately open the port again.
***************
*** 689,694 ****
--- 694,704 ----
  		/* Fetch the current modem control status, needed later. */
  		sc->sc_msr = bus_space_read_1(sc->sc_iot, sc->sc_ioh, com_msr);
  
+ 		/* Clear PPS state on open. */
+ 		sc->sc_dopps = 0;
+ 		sc->sc_timestamp_state = 0;
+ 		bzero(&sc->sc_dcd_timestamp, sizeof(sc->sc_dcd_timestamp));
+ 
  		splx(s2);
  
  		/*
***************
*** 933,938 ****
--- 943,995 ----
  		*(int *)data = bits;
  		break;
  	}
+ 
+ 	case TIOCGTSTAMP:
+ 		*(int*) data = sc->sc_timestamp_state;
+ 		break;
+ 
+ 	case TIOCSTSTAMP:
+ 		sc->sc_timestamp_state = *(int*) data;
+ 		switch (sc->sc_timestamp_state) {
+ 		case DCD_NONE:
+ 			sc->sc_dopps = 0;
+ 			sc->sc_dcd_edgemask = 0;
+ 			break;
+ 	
+ 		case DCD_LEADING_EDGE:
+ 			sc->sc_dopps = 1;
+ 			sc->sc_dcd_edgemask = MSR_DCD;
+ 			break;
+ 	
+ 		case DCD_TRAILING_EDGE:
+ 			sc->sc_dopps = 1;
+ 			sc->sc_dcd_edgemask = 0;
+ 			break;
+ 	
+ 		default:
+ 			error = EINVAL;
+ 			break;
+ 		}
+ 		break;
+ 
+ 	case TIOCDCDTIMESTAMP:	/* XXX old, overloaded API */
+ 		sc->sc_dopps = 1;
+ 		/*
+ 		 * Some GPS clocks models use the falling rather than
+ 		 * rising edge as the on-the-second signal. 
+ 		 * The old API has no way to specify PPS polarity.
+ 		 */
+ #ifndef PPS_TRAILING_EDGE
+ 	         sc->sc_dcd_edgemask = MSR_DCD;
+ #else
+ 	         sc->sc_dcd_edgemask = 0;
+ #endif
+ 		/*FALLTHROUGH*/
+ 
+ 	case TIOCFETCHLASTTSTAMP:
+ 		*(struct timeval *)data = sc->sc_dcd_timestamp;
+ 		break;
+ 
  	default:
  		error = ENOTTY;
  		break;
***************
*** 1749,1754 ****
--- 1806,1825 ----
  		sc->sc_msr = msr;
  		if (ISSET(delta, sc->sc_msr_mask)) {
  			SET(sc->sc_msr_delta, delta);
+ 
+ 			/*
+ 			 * Pulse-per-second clock  signal on edge of DCD?
+ 			 */
+ 			if (sc->sc_dopps && ISSET(delta, MSR_DCD) &&
+ 			    (delta & MSR_DCD) == sc->sc_dcd_edgemask) {
+ 				struct timeval tv;
+ 
+ 				microtime(&tv);
+ 				sc->sc_dcd_timestamp = tv;
+ #ifdef PPS_SYNC
+ 				hardpps(&tv, tv.usec);
+ #endif
+ 			}
  
  			/*
  			 * Stop output immediately if we lose the output
Index: sys/dev/ic/comvar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/comvar.h,v
retrieving revision 1.22
diff -c -r1.22 comvar.h
*** comvar.h	1998/02/02 23:01:05	1.22
--- comvar.h	1998/04/22 03:44:48
***************
*** 109,114 ****
--- 109,120 ----
  	void (*disable) __P((struct com_softc *));
  	int enabled;
  
+ 	/* Discipline system clock to pulse-per-second signal wire to DCD? */
+ 	int	sc_timestamp_state;		/* userlevel ioctl state */
+ 	int	sc_dopps;			/* boolean flag */
+ 	int	sc_dcd_edgemask;		/* edge mask */
+ 	struct timeval	sc_dcd_timestamp;;	/* XXX nanotime()? */
+ 
  #if NRND > 0 && defined(RND_COM)
  	rndsource_element_t  rnd_source;
  #endif
Index: sys/sys/ttycom.h
===================================================================
RCS file: /cvsroot/src/sys/sys/ttycom.h,v
retrieving revision 1.8
diff -c -r1.8 ttycom.h
*** ttycom.h	1998/03/26 02:45:01	1.8
--- ttycom.h	1998/04/22 03:44:48
***************
*** 129,136 ****
--- 129,146 ----
  #define		TIOCFLAG_CRTSCTS	0x04	/* set crtscts on open */
  #define		TIOCFLAG_MDMBUF		0x08	/* set mdmbuf on open */
  #define		TIOCFLAG_CDTRCTS	0x10	/* set cdtrcts on open */
+ 
  #define	TIOCDCDTIMESTAMP _IOR('t', 88, struct timeval) /* get timestamp of last
  						 * Cd rise, stamp next rise */
+ #define	TIOCGTSTAMP _IOR('t', 82, int)	/* get DCD-PPS timestamp state */
+ #define	TIOCSTSTAMP _IOW('t', 83, int)	/* set DCD-timestamp state */
+ #if !defined(_POSIX_SOURCE) && !defined(_XOPEN_SOURCE)
+ #define DCD_NONE		0
+ #define DCD_LEADING_EDGE	1
+ #define DCD_TRAILING_EDGE	2
+ #endif
+ #define	TIOCFETCHLASTTSTAMP _IOR('t', 84, struct timeval) 
+ 					/* fetch most recent timestamp */
  
  #define	TTYDISC		0		/* termios tty line discipline */
  #define	TABLDISC	3		/* tablet discipline */