(Emacs: -*- indented-text -*-)


			  Implementation of
		    PPS Timekeeping Code in Linux

	     Copyright (c) 1996, 1997, 1998 Ulrich Windl
		 <Ulrich.Windl@rz.uni-regensburg.de>
			    7th June 1998

	     This file describes ``PPSkit 0.3'', a small
		  collection of files to support the
	      ``Kernel Model for Precision Timekeeping''
		 as described in RFC-1589 and in the
		 technical memorandum by Dave Mills.


Overview:
--------

This collection contains:

     1) Bug fixes for several time-related kernel functions, mostly
        for adjtimex(). [In standard kernel since 2.0.32]

     2) Extension for adjtimex() to adjust the value of
        `tickadj'. This can be useful when the adjtime() doesn't work
        at all or is too slow (0.5ms per second by default on i386).

     3) New code to support PPS clock synchronization in the kernel.

     4) Some utilities and documentation files (like this).


A short History of Changes and Plans:
------------------------------------

* In Linux 2.0.30 there was a module-hook for a function ``hardpps''
  to handle the timekeeping stuff.  As the code for timekeeping does
  not depend on the way the signal is fed into the hardware, but only
  on how the signal is detected, it was decided to add the PPS
  timekeeping code to kernel/time.c and to remove that hook.

* The new ``hardware_pps'' routine expects the current kernel time and
  the time elapsed since the last update of the kernel time variables
  be passed as parameters.  The offset is measured in microseconds and
  should measure the time when the pulse appeared (relative to the
  current tick).

* The interrupt routine of the serial driver that handles changes in
  CD (carrier detect) calls ``do_gettimeoffset()'' to get the offset
  to the current tick.  [[It seems it's OK to call it with interrupts
  disabled.  I also hope that it will return consistent and useful
  values for a good input signal.]]  ``do_gettimeoffset'' was made a
  public symbol and a declaration was added to time.h.

* The xntp package contains code to support a CIOGETEV ioctl that
  reads precision time-stamps of external events on the carrier detect
  line of a serial port.  CIOGETEV has been implemented as a new line
  discipline that fills the structure `ppsclockev'.  That structure
  contains an event count and a ``struct timeval'' of the last
  event.  The code has been adapted from a more complete solution made
  by Harald Koenig.

* A former implementation of the FreeBSD-like ``TIOCDCDTIMESTAMP'' has
  been removed again, because it required a change to the
  serial_struct, thus causing incompatibilities for existing binaries.
  Also, the CIOGETEV gets the same data.  H. Peter Anvin had
  implemented that function around Linux 2.1.40.

* The adjtimex() system call has been extended to allow reading and
  modifying of ``tickadj''.  This is not strictly required for
  accurate clock operation, but is rather helpful if the default slew
  rate of 0.5ms per second is too slow for a larger correction made by
  ``adjtime()''.

* I'm planning to get the new PPS API into kernel 2.1 to get good
  support for forthcoming NTPv4.  Unfortunately the API is still `work
  in progress' and should not be implemented.


Notes on Usage:
--------------

* For compatibility with existing software and to still retain a
  multi-purpose serial port driver, it is necessary to enable event
  processing for the desired port with code like the following:

	struct serial_struct ss;
	ioctl(fd, TIOCGSERIAL, &ss);	/* enable pulse detection on DCD */
	ss.flags |= ASYNC_PPS_CD_POS;	/* or ``ASYNC_PPS_CD_NEG'' */
	ioctl(fd, TIOCSSERIAL, &ss);

  Currently there is a patch supplied to enable PPS processing in
  xntpd3-5.91.

* The current implementation is still experimental, but it is working
  fine at several places.  As the additional code is usually inactive,
  only a few additional CPU cycles are needed.  Measurements on my Pentium
  100MHz have shown that the `hardware_pps' routine takes between 115
  and 3960 CPU cycles per call. The average was at 1600.

* I wrote the test program `gen_pps.c' that uses the RTC driver to
  create a PPS pulse on the UART's RTS pin (pin 4 on "COM2" (25
  pins)).  The program needs the device name for the port to use
  (e.g. /dev/cua0). I made a very simple cable between the BD9 and
  DB25 connector:

  (input)	(output)
  DB9:		DB25:
  ---		----
  1 -----------	4	(CD, RTS)
  5 -----------	7	(GND, GND)

* Yet another program (enable_pps.c) can be used to enable detection
  of the PPS signal on the CD pin and exercise the kernel clock
  machinery.  As that program expects standard input to be redirected
  to the desired port, detection will still be enabled after the
  program has terminated.  This is intended to be a feature, and not a
  bug.  Otherwise it's hard to get PPS support running in an
  unmodified xntpd.

* The programs are just my test programs to validate the code; don't
  expect them to synchronize your time!  Even worse, they may
  de-adjust your kernel clock badly.  Use xntp3-5.91 for nice NTP
  support.  I have a low-cost DCF77 receiver (77kHz long wave in
  Germany) for testing purposes, but it only gives a poor PPS signal.

* Usually you need some level converter to connect the TTL output of a
  clock to the CD input of the serial port.  There's also some
  information (`gadget box') on the NTP home page
  http://www.eecis.udel.edu/~ntp/.

* To get a quick start with xntp configuration and PPS read the
  documentation on ``enable pps'' and ``refclock ATOM''.  Also read
  the HTML files `prefer.html' and `debug.html' from the distribution.
  There's also a FAQ, but slighly old... (mostly composed from
  comp.protocols.time.ntp)


Credits:
-------

* Frank Kardel was the one to point my nose at NTP. He also wrote that
  fine DCF77 driver (among many others).

* Dave Mills had to read a lot of my stupid questions and bug reports
  about NTP and PPS support.

* Harlan Stenn volunteered to integrate my Linux patches in xntpd. He
  also made the package more widely accepted by converting the
  Makefile-mess to GNU autoconf.

* Theodore Y. Ts'o finally told me where to start adding PPS support
  to the driver.  His very first patch made me start the project.

* H. Peter Anvin ported my original patch forth to Linux 2.1, and
  he'll probably do it again...

* Harald König gave several useful hints and supplied his patches.

* Bill Broadley for trying out all the patches.

* Nigel Metheringham supplied an updated patch for sparc architecture
  and Linux-2.0.33.
