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


			  Implementation of
		  PPS Timekeeping Code for Linux 2.2

	      Copyright (c) 1996 - 1999 by Ulrich Windl
		 <Ulrich.Windl@rz.uni-regensburg.de>
			    7th March 1999

      This file describes ``PPSkit 0.6'', a small collection of
   files to support the ``Kernel Model for Precision Timekeeping''
	 as described in RFC-1589, the technical memorandum,
	       and the kernel simulator by Dave Mills.
	  Mainly this algorithms are used by NTPv3 and NTPv4
		  (Network Time Protocol, RFC1305).
      Support is added for adjusting the offset and frequency of
    the kernel clock towards an external pulse-per-second signal.


Overview:
--------

This collection contains:

     0) A new kernel that keeps time in nanoseconds (instead of
        microseconds).  These changes come along with several other
        improvements and cleanups.

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

     2) New code to support PPS (pulse-per-second) clock
        synchronization in the kernel.

     3) Example implementation for the serial driver (implements
        detection of pulse on DCD pin).

     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 ``hardpps'' routine expects the time of the pulse to be
  passed as parameters.

* The interrupt routine of the serial driver that handles changes in
  CD (carrier detect) calls ``do_gettimeofday()'' to get the current
  time.  [[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.]]

* 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()''.

* The PPSkit (0.4) has been merged into Linux-2.2 shortly before it
  came out.  Thus 2.2.0 has some essential time fixes that older
  versions did not have (these fixes entered 2.0 when 2.1 already
  existed).

* In preparation for exchanging the major part of the NTP code, the
  code has been restructured for PPSkit-0.5.  The next generation will
  have 64bit quantities measuring nanoseconds.  Currently noone in the
  kernel provides nanoseconds, but we'll be prepared.

* In PPSkit-0.6 the kernel was converted to nanoseconds by brute
  force.  Along with the new 64bit time variables came the new kernel
  clock model known as the ``nanokernel'' (because it features
  nanoseconds and ``STA_NANO'').  It is planned to bring some of the
  related fixes back to the stable standard kernel.

* I'm planning to get the new PPS API into kernel 2.2 to get good
  support for evolving 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.93.  For ntpd-4.0.91f there are patches by Frank Kardel to
  use PPSkit with the PARSE drivers.  Possibly these changes are
  already in ntp4.0.92c.

* 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 128
  and 7000 CPU cycles per call (with debugging enabled, of course).

* I wrote the test program `gen_pps.c' that uses the RTC driver (see
  /proc/rtc) 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)

  Unfortunately the RTC driver seems to have some problems (last seen
  in 2.0.36): From time to time the kernel says: ``rtc: lost some
  interrupts at 2Hz.'' (This is because updating the RTC will reset
  the divider for the periodic interrupt)

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

  NOTE: Probably this is no longer true due to some changes made in
  the serial code.

* 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.93 for nice NTP
  support.  Meinberg in Germany lent me a GPS 167 receiver that I use
  for measurements.  The accuracy is claimed to be 250ns for the PPS
  pulse.

* Usually you need some level converter to connect the TTL level
  output of a clock to the CD input of the serial port.  A friend of
  mine and I have developed a simple converter that is powered from
  the serial port's status lines.  There's also some information about
  a sample device (`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 (that comes with xntp) on ``PPS'' (pps.html) and
  ``enable pps'' (prefer.html) and ``refclock ATOM'' (driver22.html).
  You are kindly advised to read ``debug.html'' before reporting
  problems to the xntp developers or to the newsgroup
  comp.protocols.time.ntp.  There's also a FAQ, but slighly
  old... (mostly composed from comp.protocols.time.ntp)
