diff -Pur ntp-4.1.1.orig/acconfig.h ntp-4.1.1/acconfig.h
--- ntp-4.1.1.orig/acconfig.h	Mon Oct  8 22:58:36 2001
+++ ntp-4.1.1/acconfig.h	Mon May 13 22:07:58 2002
@@ -61,6 +61,9 @@
 /* Forum Graphic GPS datating station driver */
 #undef CLOCK_FG
 
+/* Garmin GPS Handheld Receivers */
+#undef CLOCK_GARMIN
+
 /* TrueTime GPS receiver/VME interface */
 #undef CLOCK_GPSVME
 
diff -Pur ntp-4.1.1.orig/config.h.in ntp-4.1.1/config.h.in
--- ntp-4.1.1.orig/config.h.in	Sun Dec  2 00:24:53 2001
+++ ntp-4.1.1/config.h.in	Mon May 13 22:07:58 2002
@@ -62,6 +62,9 @@
 /* Forum Graphic GPS datating station driver */
 #undef CLOCK_FG
 
+/* Garmin GPS Handheld Receivers */
+#undef CLOCK_GARMIN
+
 /* TrueTime GPS receiver/VME interface */
 #undef CLOCK_GPSVME
 
diff -Pur ntp-4.1.1.orig/configure ntp-4.1.1/configure
--- ntp-4.1.1.orig/configure	Tue Feb 26 18:13:58 2002
+++ ntp-4.1.1/configure	Mon May 13 22:07:58 2002
@@ -692,6 +692,7 @@
   --enable-AUDIO-CHU      s CHU audio/decoder
   --enable-DATUM          s Datum Programmable Time System
   --enable-FG             + Forum Graphic GPS
+  --enable-GARMIN         + Garmin GPS Handheld Receivers
   --enable-HEATH          s Heath GC-1000 WWV/WWVH receiver
   --enable-HPGPS          + HP 58503A GPS receiver
   --enable-IRIG           s Sun IRIG audio decoder
@@ -12541,6 +12542,25 @@
 EOF
 
 fi
+echo "$as_me:12357: result: $ntp_ok" >&5
+echo "${ECHO_T}$ntp_ok" >&6
+
+echo "$as_me:12341: checking Garmin GPS Handheld Receivers" >&5
+echo $ECHO_N "checking Garmin GPS Handheld Receivers... $ECHO_C" >&6
+# Check whether --enable-GARMIN or --disable-GARMIN was given.
+if test "${enable_GARMIN+set}" = set; then
+  enableval="$enable_GARMIN"
+  ntp_ok=$enableval
+else
+  ntp_ok=$ntp_eac
+fi;
+if test "$ntp_ok" = "yes"; then
+    ntp_refclock=yes
+    cat >>confdefs.h <<\EOF
+#define CLOCK_GARMIN 1
+EOF
+
+fi
 echo "$as_me:12544: result: $ntp_ok" >&5
 echo "${ECHO_T}$ntp_ok" >&6
 
diff -Pur ntp-4.1.1.orig/html/driver41.htm ntp-4.1.1/html/driver41.htm
--- ntp-4.1.1.orig/html/driver41.htm	Wed Dec 31 16:00:00 1969
+++ ntp-4.1.1/html/driver41.htm	Mon May 13 22:07:58 2002
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso8859-1">
+<title>Garmin GPS Handheld Receivers</title>
+</head>
+
+<body>
+<h3>Garmin GPS Handheld Receivers</h3>
+
+<hr>
+<h4>Synopsis</h4>
+Address: 127.127.41.<i>u</i><br>
+Reference ID: <TT>GPS</TT><br>
+Driver ID: <tt>GARMIN</tt><br>
+Serial Port: <tt>/dev/gps<i>u</i></tt>; 9600 bps, 8-bits, no parity<br>
+<br>Features: <tt>(none)</tt>
+<h4>Description</h4>
+
+<p>NTP clock driver for Garmin GPS handheld receivers using the Garmin
+proprietary protocol.  It is based on both documented and undocumented
+aspects of the Garmin proprietary protocol.
+
+<p>To use this driver, your Garmin GPS handheld receiver must be
+configured to use Garmin protocol interface mode, not NMEA.
+
+<p>This driver has been written and tested using a Linux based system.
+To achieve the best quality results, turn off serial port FIFOs and enable
+low latency tty driver processing.  In Linux, this is accomplished using
+the setserial application (e.g. setserial /dev/gps<i>u</i> uart 16550
+low_latency).  Even better results are obtained with kernel timestamps on
+received characters.  This is what I have been using for most of my tests.
+
+<p>This is a "sloppy" clock but I believe it is possible to recover
+sub-millisecond results with a good clock filter.  Without an accurate
+reference clock, I am unable to provide more quantitative performance
+results at this time.
+
+<p>I suspect that earlier versions of firmware may not return the
+undisciplined oscillator count as part of a date/time response.
+This information is needed to recover the higher accuracy results.
+Without this undocumented field, the driver will only achieve sub-second
+accuracy. I welcome technical support from the manufacturer to achieve
+universal support for the entire range of models and firmware versions.
+
+<p>This driver has been testing with the following units.
+I need feedback from users to populate this list!  Check for
+updates to this list, driver, and other related software at at <a
+href="http://www.isi.edu/~lindell/garmin.html"> NTP Drivers for Garmin
+GPS Handheld Receivers</a>
+
+<ul>
+<li> Garmin GPS 12 firmware version 4.54
+</ul>
+
+<h4>Fudge Factors</h4>
+
+<dl>
+<dt><tt>time1 <i>time</i></tt></dt>
+<dd>Specifies the time offset calibration factor, in seconds and fraction,
+with default 0.0.</dd>
+
+<dt><tt>time2 <i>time</i></tt></dt>
+<dd>Not used by this driver.</dd>
+
+<dt><tt>stratum <i>number</i></tt></dt>
+<dd>Specifies the driver stratum, in decimal from 0 to 15, with default 0.
+</dd>
+
+<dt><tt>refid <i>string</i></tt></dt>
+<dd>Specifies the driver reference identifier, an ASCII string from one to
+four characters, with default <tt>GPS</tt>.</dd>
+
+<dt><tt>flag1 0 | 1</tt></dt>
+<dd>Not used by this driver.</dd>
+
+<dt><tt>flag2 0 | 1</tt></dt>
+<dd>Not used by this driver.</dd>
+
+<dt><tt>flag3 0 | 1</tt></dt>
+<dd>Not used by this driver.</dd>
+
+<dt><tt>flag4 0 | 1</tt></dt>
+<dd>Not used by this driver.</dd>
+</dl>
+
+<hr>
+<address>
+Bob Lindell (lindell@isi.edu)
+</address>
+</body>
+</html>
diff -Pur ntp-4.1.1.orig/html/refclock.htm ntp-4.1.1/html/refclock.htm
--- ntp-4.1.1.orig/html/refclock.htm	Mon Oct  8 22:58:38 2001
+++ ntp-4.1.1/html/refclock.htm	Mon May 13 22:13:24 2002
@@ -224,6 +224,10 @@
 <a href="driver39.htm">Type 39</a> hopf GPS/DCF77 6039 for PCI-Bus
 (<tt>HOPF_P</tt>)<br>
 <a href="driver40.htm">Type 40</a> JJY Receivers (<tt>JJY</tt>)<br>
+(<tt>HOPF_P</tt>)<br>
+<a href="driver41.htm">Type 41</a> Garmin GPS Handheld Receivers (<tt>GARMIN
+</tt>)<br>
+
 </p>
  
 
diff -Pur ntp-4.1.1.orig/include/ntp.h ntp-4.1.1/include/ntp.h
--- ntp-4.1.1.orig/include/ntp.h	Mon Oct  8 22:58:39 2001
+++ ntp-4.1.1/include/ntp.h	Mon May 13 22:11:12 2002
@@ -458,7 +458,8 @@
 #define REFCLK_HOPF_SERIAL	38	/* hopf DCF77/GPS serial line receiver  */
 #define REFCLK_HOPF_PCI		39	/* hopf DCF77/GPS PCI receiver  */
 #define REFCLK_JJY		40	/* JJY receiver  */
-#define REFCLK_MAX		40	/* Grow as needed... */
+#define REFCLK_GARMIN		41	/* Garmin GPS Handheld Receivers */
+#define REFCLK_MAX		41	/* Grow as needed... */
 
 /*
  * We tell reference clocks from real peers by giving the reference
diff -Pur ntp-4.1.1.orig/libntp/clocktypes.c ntp-4.1.1/libntp/clocktypes.c
--- ntp-4.1.1.orig/libntp/clocktypes.c	Mon Oct  8 22:58:40 2001
+++ ntp-4.1.1/libntp/clocktypes.c	Mon May 13 22:14:36 2002
@@ -92,6 +92,8 @@
 	  "HOPF_P"},
 	{ REFCLK_JJY,	"JJY receiver (40)",
 	  "JJY" },
+	{ REFCLK_GARMIN,	"Garmin GPS Handheld Receivers (41)",
+	  "GPS_GARMIN"},
 	{ -1,			"", "" }
 };
 
diff -Pur ntp-4.1.1.orig/ntpd/Makefile.am ntp-4.1.1/ntpd/Makefile.am
--- ntp-4.1.1.orig/ntpd/Makefile.am	Mon Nov 12 22:42:36 2001
+++ ntp-4.1.1/ntpd/Makefile.am	Mon May 13 22:07:58 2002
@@ -29,7 +29,8 @@
 	ntp_util.c ntpd.c refclock_acts.c refclock_arbiter.c refclock_arc.c \
 	refclock_as2201.c refclock_atom.c refclock_bancomm.c \
 	refclock_chronolog.c refclock_chu.c refclock_conf.c refclock_datum.c \
-	refclock_dumbclock.c refclock_fg.c refclock_gpsvme.c refclock_heath.c \
+	refclock_dumbclock.c refclock_fg.c refclock_garmin.c \
+	refclock_gpsvme.c refclock_heath.c \
 	refclock_hopfser.c refclock_hopfpci.c \
 	refclock_hpgps.c refclock_irig.c refclock_jjy.c refclock_jupiter.c refclock_leitch.c \
 	refclock_local.c refclock_msfees.c refclock_mx4200.c refclock_nmea.c \
diff -Pur ntp-4.1.1.orig/ntpd/Makefile.in ntp-4.1.1/ntpd/Makefile.in
--- ntp-4.1.1.orig/ntpd/Makefile.in	Tue Feb 26 18:15:45 2002
+++ ntp-4.1.1/ntpd/Makefile.in	Mon May 13 22:16:21 2002
@@ -138,7 +138,8 @@
 	ntp_util.c ntpd.c refclock_acts.c refclock_arbiter.c refclock_arc.c \
 	refclock_as2201.c refclock_atom.c refclock_bancomm.c \
 	refclock_chronolog.c refclock_chu.c refclock_conf.c refclock_datum.c \
-	refclock_dumbclock.c refclock_fg.c refclock_gpsvme.c refclock_heath.c \
+	refclock_dumbclock.c refclock_fg.c refclock_garmin.c \
+	refclock_gpsvme.c refclock_heath.c \
 	refclock_hopfser.c refclock_hopfpci.c \
 	refclock_hpgps.c refclock_irig.c refclock_jjy.c refclock_jupiter.c refclock_leitch.c \
 	refclock_local.c refclock_msfees.c refclock_mx4200.c refclock_nmea.c \
@@ -175,7 +176,7 @@
 	refclock_bancomm$U.$(OBJEXT) refclock_chronolog$U.$(OBJEXT) \
 	refclock_chu$U.$(OBJEXT) refclock_conf$U.$(OBJEXT) \
 	refclock_datum$U.$(OBJEXT) refclock_dumbclock$U.$(OBJEXT) \
-	refclock_fg$U.$(OBJEXT) refclock_gpsvme$U.$(OBJEXT) \
+	refclock_fg$U.$(OBJEXT) refclock_garmin$U.o refclock_gpsvme$U.$(OBJEXT) \
 	refclock_heath$U.$(OBJEXT) refclock_hopfser$U.$(OBJEXT) \
 	refclock_hopfpci$U.$(OBJEXT) refclock_hpgps$U.$(OBJEXT) \
 	refclock_irig$U.$(OBJEXT) refclock_jjy$U.$(OBJEXT) \
diff -Pur ntp-4.1.1.orig/ntpd/ntp_control.c ntp-4.1.1/ntpd/ntp_control.c
--- ntp-4.1.1.orig/ntpd/ntp_control.c	Mon Oct  8 22:58:40 2001
+++ ntp-4.1.1/ntpd/ntp_control.c	Mon May 13 22:17:34 2002
@@ -396,6 +396,7 @@
 	CTL_SST_TS_UHF, 	/* REFCLK_HOPF_SERIAL (38) */
 	CTL_SST_TS_UHF,		/* REFCLK_HOPF_PCI (39) */
 	CTL_SST_TS_LF,		/* REFCLK_JJY (40) */
+	CTL_SST_TS_UHF,		/* REFCLK_GPS_GARMIN (41) */
 };
 
 
diff -Pur ntp-4.1.1.orig/ntpd/refclock_conf.c ntp-4.1.1/ntpd/refclock_conf.c
--- ntp-4.1.1.orig/ntpd/refclock_conf.c	Mon Oct  8 22:58:41 2001
+++ ntp-4.1.1/ntpd/refclock_conf.c	Mon May 13 22:18:28 2002
@@ -228,6 +228,12 @@
 #define	refclock_fg	refclock_none
 #endif
 
+#ifdef CLOCK_GARMIN
+extern	struct refclock	refclock_garmin;
+#else
+#define	refclock_garmin	refclock_none
+#endif
+
 #ifdef CLOCK_HOPF_SERIAL
 extern	struct refclock	refclock_hopfser;
 #else
@@ -293,7 +299,8 @@
 	&refclock_fg,		/* 37 REFCLOCK_FG */
 	&refclock_hopfser,	/* 38 REFCLK_HOPF_SERIAL */
 	&refclock_hopfpci,	/* 39 REFCLK_HOPF_PCI */
-	&refclock_jjy		/* 40 REFCLK_JJY */
+	&refclock_jjy,		/* 40 REFCLK_JJY */
+	&refclock_garmin	/* 41 REFCLK_GARMIN */
 };
 
 u_char num_refclock_conf = sizeof(refclock_conf)/sizeof(struct refclock *);
diff -Pur ntp-4.1.1.orig/ntpd/refclock_garmin.c ntp-4.1.1/ntpd/refclock_garmin.c
--- ntp-4.1.1.orig/ntpd/refclock_garmin.c	Wed Dec 31 16:00:00 1969
+++ ntp-4.1.1/ntpd/refclock_garmin.c	Mon May 13 22:07:58 2002
@@ -0,0 +1,642 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#if defined(REFCLOCK) && defined(CLOCK_GARMIN)
+
+/*
+ *	NTP clock driver for Garmin GPS handheld receivers (1.2)
+ *	Copyright (C) 2000 Bob Lindell (lindell@isi.edu)
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License as
+ *	published by the Free Software Foundation; either version 2 of
+ *	the License, or (at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public
+ *	License along with this program; if not, write to the Free
+ *	Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ *	MA  02111-1307, USA.
+ */
+
+/*
+ *	NTP clock driver for Garmin GPS handheld receivers using the
+ *	Garmin proprietary protocol.  It is based on both documented
+ *	and undocumented aspects of the Garmin proprietary protocol.
+ *
+ *	To use this driver, your Garmin GPS handheld receiver must be
+ *	configured to use Garmin protocol interface mode, not NMEA.
+ *
+ *	This driver has been written and tested using a Linux based
+ *	system.  To achieve the best quality results, turn off serial
+ *	port FIFOs and enable low latency tty driver processing.
+ *	In Linux, this is accomplished using the setserial application
+ *	(e.g. setserial /dev/gps0 uart 16550 low_latency).  Even better
+ *	results are obtained with kernel timestamps on received
+ *	characters.  This is what I have been using for most of my tests.
+ *
+ *	This is a "sloppy" clock but I believe it is possible to recover
+ *	sub-millisecond results with a good clock filter.  Without an
+ *	accurate reference clock, I am unable to provide more quantitative
+ *	performance results at this time.
+ *
+ *	I suspect that earlier versions of firmware may not return the
+ *	undisciplined oscillator count as part of a date/time response.
+ *	This information is needed to recover the higher accuracy results.
+ *	Without this undocumented field, the driver will only achieve
+ *	sub-second accuracy. I welcome technical support from the
+ *	manufacturer to achieve universal support for the entire range
+ *	of models and firmware versions.
+ *
+ *	This driver has been testing with the following units.
+ *	I need feedback from users to populate this list!  Check for
+ *	updates to this list, driver, and other related software
+ *	at http://www.isi.edu/~lindell/garmin.html.
+ *
+ *		* Garmin GPS 12 firmware version 4.54
+ *		* ??
+ */
+
+/* #define	TIMESTAMPS */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <sys/time.h>
+
+#include "ntpd.h"
+#include "ntp_io.h"
+#include "ntp_refclock.h"
+#include "ntp_stdlib.h"
+#ifdef	TIMESTAMPS
+#include "ntp_unixtime.h"
+#endif	/* TIMESTAMPS */
+
+/*
+ *	One day, POSIX types will be a given.
+ */
+
+typedef unsigned char uint8_x;
+typedef short int16_x;
+typedef unsigned short uint16_x;
+typedef u_int32 uint32_x;
+
+/*
+ *	Generic functions
+ */
+
+#define	SIZEOF(x)		(sizeof(x) / sizeof((x)[0]))
+
+/*
+ *	Time constants
+ */
+
+#define	USEC_PER_SEC		1000000
+#define	SEC_PER_MIN		60
+#define	MIN_PER_HOUR		60
+#define	HOUR_PER_DAY		24
+#define	SEC_PER_DAY		(SEC_PER_MIN * MIN_PER_HOUR * HOUR_PER_DAY)
+
+/*
+ *	The Garmin proprietary protocol is partially documented
+ *	by the manufacturer.  The document, "Garmin GPS Interface
+ *	Specification", dated December, 1999, is available at
+ *	http://www.garmin.com/support/pdf/iop_spec.pdf.  A good reference
+ *	for some of the undocumented packet formats can be found at
+ *	http://artico.lma.fi.upm.es/numerico/miembros/antonio/async/.
+ */
+
+/*
+ *	Packet IDs at the Garmin protocol link layer.
+ */
+
+#define	PID_ACK_BYTE		6
+#define	PID_COMMAND_DATA	10
+#define	PID_DATE_TIME_DATA	14
+#define	PID_UNDOC_PVT		20
+#define	PID_NAK_BYTE		21
+#define	PID_UNDOC_ASYNC		28
+#define	PID_PVT_DATA		51
+
+/*
+ *	Packet commands at the Garmin protocol application layer.
+ */
+
+#define	CMND_TRANSFER_TIME	5
+
+/*
+ *	Garmin data structure constants
+ */
+
+#define	FIX_2D			2		/* At least a 2D fix */
+#define	CLK_SHIFT		9		/* LSB of oscillator */
+#define	CLK_MASK		((1 << CLK_SHIFT) - 1)
+
+/*
+ *	Garmin packet functions
+ */
+
+#define	PKT_MAX			(2 + 2 * 257 + 2)
+#define	PKT_PID(x)		((x)[0])
+#define	PKT_SIZE(x)		((x)[1])
+
+#ifdef	XNTP_BIG_ENDIAN
+#define	GTOH16(buf,i)		(((buf)[(i) + 1] << 8) | (buf)[i])
+#define	GTOH32(buf,i)		((GTOH16(buf,(i) + 2) << 16) | GTOH16(buf,i))
+#define	GTOHD(buf,i)		gtohd(buf,i)
+static
+double
+gtohd(uint8_x *buf,int i) {
+	union {
+		unsigned long l[2];
+		double d;
+	} x;
+
+	x.l[1] = GTOH32(buf,i);
+	x.l[0] = GTOH32(buf,i + 4);
+	return(x.d);
+}
+#else	/* XNTP_BIG_ENDIAN */
+#define	GTOH16(buf,i)		(*((uint16_x *) &(buf)[i]))
+#define	GTOH32(buf,i)		(*((uint32_x *) &(buf)[i]))
+#define	GTOHD(buf,i)		(*((double *) &(buf)[i]))
+#endif	/* XNTP_BIG_ENDIAN */
+
+/*
+ *	NTP daemon definitions
+ */
+
+#ifdef SYS_WINNT
+#define	DEVICE		"COM%d:"		/* COM 1 - 3 supported */
+#else
+#define	DEVICE		"/dev/gps%d"		/* name of radio device */
+#endif
+#define	SPEED232	B9600			/* UART speed (9600 bps) */
+#define	PRECISION	(-10)			/* precision (about 1 ms) */
+#define	REFID		"GPS\0"			/* reference id */
+#define	DESCRIPTION	"Garmin GPS Clock"	/* who we are */
+
+#define	BUF_SIZE		1024	/* ring buffer size */
+#define	MIN_SAMPLES		10	/* min samples per poll period */
+
+/*
+ *	NTP daemon unit control structure
+ */
+
+struct unit {
+	uint8_x buffer[BUF_SIZE];	/* received data */
+	l_fp ts[BUF_SIZE];		/* time of byte arrival */
+	uint16_x rp;			/* read pointer */
+	uint16_x wp;			/* write pointer */
+	double period;			/* period of counter (usecs) */
+	double tow0;			/* previous value of GPS tow */
+	uint32_x counter0;		/* previous value of counter */
+	int16_x leap;			/* GPS leap second offset to UTC */
+	int high;			/* High accuracy mode enabled */
+#ifdef	TIMESTAMPS
+	uint8_x tcnt;			/* byte count for timeval data */
+	struct timeval tv;		/* time of byte arrival */
+#endif	/* TIMESTAMPS */
+};
+
+/*
+ *	Function prototypes
+ */
+
+typedef void (*callback)(struct recvbuf *,uint8_x *,l_fp *);
+
+static	int	gstart		P((int,struct peer *));
+static	void	gshutdown	P((int,struct peer *));
+static	void	greceive	P((struct recvbuf *));
+static	void	gpoll		P((int,struct peer *));
+static	int	gwrite		P((int,uint8_x *));
+static	void	gread		P((struct recvbuf *,callback));
+static	void	process		P((struct recvbuf *,uint8_x *,l_fp *));
+
+/*
+ *	NTP daemon transfer vector
+ */
+
+struct	refclock refclock_garmin = {
+	gstart,			/* start up driver */
+	gshutdown,		/* shut down driver */
+	gpoll,			/* transmit poll message */
+	noentry,		/* handle control */
+	noentry,		/* initialize driver */
+	noentry,		/* buginfo */
+	NOFLAGS			/* not used */
+};
+
+/* Start async message generation of PID_PVT_DATA and PID_UNDOC_PVT */
+static uint8_x async[] = { PID_UNDOC_ASYNC, 2, 4, 3 };
+
+/*
+ *	start - open the devices and initialize data for
+ *	processing.
+ */
+
+static
+int
+gstart(int unit,struct peer *peer)
+{
+	struct unit *up;
+	struct refclockproc *pp;
+	char device[sizeof(DEVICE) + 1];
+
+	/*
+	 * Allocate and initialize structures
+	 */
+	up = (struct unit *) emalloc(sizeof(*up));
+	if (up == NULL)
+		return (FALSE);
+	memset((char *)up,0,sizeof(*up));
+	pp = peer->procptr;
+	pp->unitptr = (caddr_t)up;
+	pp->io.srcclock = (caddr_t)peer;
+	pp->io.clock_recv = greceive;
+	pp->io.datalen = 0;
+	peer->precision = PRECISION;
+	pp->clockdesc = DESCRIPTION;
+	memcpy((char *)&pp->refid,REFID,4);
+	(void)sprintf(device,DEVICE,unit);
+	pp->io.fd = refclock_open(device,SPEED232,LDISC_RAW);
+	if (pp->io.fd < 0) {
+		free(up);
+		return (FALSE);
+	}
+	if (!io_addclock(&pp->io)) {
+		(void) close(pp->io.fd);
+		free(up);
+		return (FALSE);
+	}
+	gwrite(pp->io.fd,async);
+	return (TRUE);
+}
+
+/*
+ *	shutdown - shut down the clock.
+ */
+
+static
+void
+gshutdown(int unit,struct peer *peer)
+{
+	struct unit *up;
+	struct refclockproc *pp;
+	/* Stop async message generation */
+	static uint8_x stop[] = { PID_UNDOC_ASYNC, 2, 0, 0 };
+
+	pp = peer->procptr;
+	up = (struct unit *)pp->unitptr;
+	gwrite(pp->io.fd,stop);
+	io_closeclock(&pp->io);
+	free(up);
+}
+
+/*
+ *	receive - receive data from the clock.
+ */
+
+static
+void
+greceive(struct recvbuf *rbufp)
+{
+	gread(rbufp,process);
+}
+
+/*
+ *	poll - called by the transmit procedure.
+ */
+
+static
+void
+gpoll(int unit,struct peer *peer)
+{
+	struct refclockproc *pp;
+	struct unit *up;
+
+	pp = peer->procptr;
+	up = (struct unit *)pp->unitptr;
+	pp->polls++;
+	/*
+	 *	Reexamine the GPS leap offset every poll period.
+	 *	Also support hot disconnects and reconnects of the GPS
+	 *	clock.  We don't want to deprive the user from going on
+	 *	an enjoyable hike with their receiver.
+	 */
+	gwrite(pp->io.fd,async);
+	if (pp->coderecv < (pp->codeproc + MIN_SAMPLES)) {
+		refclock_report(peer,CEVNT_TIMEOUT);
+		up->rp = up->wp;
+#ifdef	TIMESTAMPS
+		up->tcnt = 0;
+#endif	/* TIMESTAMPS */
+		return;
+	}
+	record_clock_stats(&peer->srcadr,pp->a_lastcode);
+	refclock_receive(peer);
+}
+
+
+/*
+ *	Process packets of the Garmin protocol.  The Garmin specification
+ *	refers to this as the application layer processing.
+ */
+
+static
+void
+process(struct recvbuf *rbufp,uint8_x *buf,l_fp *t)
+{
+	uint32_x counter;
+	struct unit *up;
+	struct refclockproc *pp;
+	struct peer *peer;
+	double tow;
+	/* Poll for date and time */
+	static uint8_x date[] = { PID_COMMAND_DATA, 2, CMND_TRANSFER_TIME, 0 };
+	/* Start async message generation of PID_UNDOC_PVT only */
+	static uint8_x simplepvt[] = { PID_UNDOC_ASYNC, 2, 4, 0 };
+
+	peer = (struct peer *)rbufp->recv_srcclock;
+	pp = peer->procptr;
+	up = (struct unit *)pp->unitptr;
+	if (PKT_PID(buf) == PID_UNDOC_PVT) {
+		/*
+		 *	Every second we get the current count of the
+		 *	undisciplined oscillator at the beginning of
+		 *	the second.  The nominal frequency is 0.5115
+		 *	Mhz which is half of 1.023 Mhz GPS data rate. We
+		 *	compute the period of this oscillator by measuring
+		 *	it against the computed GPS time of week (tow)
+		 *	field.  The tow field is actually reported in two
+		 *	parts, a value which drifts with the oscillator
+		 *	and a correction factor.
+		 */
+		if (GTOH16(buf,2) < FIX_2D)
+			return;
+		gwrite(pp->io.fd,date);	/* Ask for the data and time */
+		if (!up->high)
+			return;
+		counter = (GTOH32(buf,22) << CLK_SHIFT)
+			| (GTOH32(buf,26) & CLK_MASK);
+		tow = GTOHD(buf,6) - GTOHD(buf,70);
+		up->period = USEC_PER_SEC * (tow - up->tow0)
+			/ (counter - up->counter0);
+		up->counter0 = counter;
+		up->tow0 = tow;
+		return;
+	}
+	if (PKT_PID(buf) == PID_PVT_DATA) {
+		/*
+		 *	Every second we get a position, velocity,
+		 *	and time (PVT) solution of the GPS receiver.
+		 *	This gives the GPS leap second offset to UTC.
+		 *	The only reason we need this message is to
+		 *	correct the date and time packets.
+		 */
+		if (GTOH16(buf,18) < FIX_2D)
+			return;
+		up->leap = GTOH16(buf,60);
+		if (up->high)
+			/* turn off PID_PVT_DATA */
+			gwrite(pp->io.fd,simplepvt);
+		else
+			up->tow0 = GTOHD(buf,20);
+		return;
+	}
+	if (PKT_PID(buf) == PID_DATE_TIME_DATA) {
+		/*
+		 *	The Garmin documentation says we get back
+		 *	8 bytes including the data and time to the
+		 *	nearest second.  Some versions of the firmware
+		 *	throw in an additional 4 bytes containing the
+		 *	upper bits of the undisciplined oscillator count.
+		 */
+		pp->lastrec = *t;
+		pp->year = GTOH16(buf,4);
+		pp->day = ymd2yd(pp->year,buf[2],buf[3]);
+		pp->hour = GTOH16(buf,6);
+		pp->minute = buf[8];
+		pp->second = buf[9];
+		pp->msec = 0;
+		pp->leap = LEAP_NOWARNING;
+		pp->lencode = sprintf(pp->a_lastcode,
+			"%.02d/%.02d/%d %.02d:%.02d:%.02d",buf[2],buf[3],
+			pp->year,pp->hour,pp->minute,pp->second);
+		/*
+		 *	The time, which is reported to the nearest
+		 *	second, seems to drift relative to real time by
+		 *	a substantial fraction of a second.  This means
+		 *	that we may accidently report that we are in
+		 *	the previous or next second.  Use the GPS tow
+		 *	corrected to UTC instead.
+		 */
+		pp->hour = 0;
+		pp->minute = 0;
+		pp->usec = USEC_PER_SEC * modf(up->tow0,&tow);
+		pp->second = tow;
+		pp->second = (pp->second + SEC_PER_DAY - up->leap)
+			% SEC_PER_DAY;
+		/*
+		 *	Compute the offset into the current second
+		 *	by multiplying the elapsed count since the
+		 *	beginning of the second with the estimated period
+		 *	of the counter.  The response is missing the
+		 *	least significant bits of the oscillator count.
+		 *	This does not reduce the accuracy of the result
+		 *	since device responses seem to occur at some
+		 *	large multiple of the oscillator frequency.
+		 */
+		if (PKT_SIZE(buf) >= 12) {
+			counter = GTOH32(buf,10) << CLK_SHIFT;
+			pp->usec += up->period * (counter - up->counter0);
+			while (pp->usec >= USEC_PER_SEC) {
+				pp->usec -= USEC_PER_SEC;
+				pp->second++;
+			}
+			up->high = TRUE;
+		}
+		else
+			up->high = FALSE;
+		if (!refclock_process(pp))
+			refclock_report(peer,CEVNT_BADTIME);
+		return;
+	}
+}
+
+/*
+ *	An implementation of the Garmin link layer protocol.  As defined
+ *	in the specification, all packet ACKs and NACKs are done only
+ *	at the link layer.
+ */
+
+#define	DLE		16
+#define	ETX		3
+
+#define	GETBYTE(c,up,rp)	{ \
+	if (rp != up->wp) { \
+		(c) = up->buffer[rp++]; \
+		rp = rp % SIZEOF(up->buffer); \
+	} \
+	else \
+		return(0); \
+}
+
+#define	GETBYTE_ESCAPED(c,up,rp)	{ \
+	GETBYTE(c,up,rp); \
+	if (c == DLE) \
+		GETBYTE(c,up,rp); \
+}
+
+#define	PUTBYTE(c,buf,len)	{ \
+	buf[len++] = c; \
+}
+
+#define	PUTBYTE_ESCAPED(c,buf,len)	{ \
+	PUTBYTE(c,buf,len); \
+	if (c == DLE) \
+		PUTBYTE(c,buf,len); \
+}
+
+/*
+ *	Write a packet to the GPS receiver.  Add the proper header,
+ *	trailer, and checksum.  Perform DLE escaping as defined in the
+ *	specification.
+ */
+
+static
+int
+gwrite(int fd,uint8_x *buf)
+{
+	uint8_x c,sum,packet[PKT_MAX];
+	uint16_x i,n,len;
+
+	len = 0;
+	PUTBYTE(DLE,packet,len);
+	sum = PKT_PID(buf);
+	PUTBYTE(sum,packet,len);
+	n = PKT_SIZE(buf) + 2;
+	for (i = 1;i < n; i++) {
+		c = buf[i];
+		PUTBYTE_ESCAPED(c,packet,len);
+		sum += c;
+	}
+	sum = 256 - sum;
+	PUTBYTE_ESCAPED(sum,packet,len);
+	PUTBYTE(DLE,packet,len);
+	PUTBYTE(ETX,packet,len);
+	return(write(fd,packet,len) == len);
+}
+
+/*
+ *	Attempt to parse whole packets.  If successful, ACK the packet if
+ *	necessary and return true.  Bad packets are dropped and get NACKed
+ *	if the PID is known.  There is a subtle flaw in the protocol here.
+ *	A NACK is susposed to return the PID.  But what if the received
+ *	PID byte was corrupted during transmission?  We send back the
+ *	PID we received, right or wrong.
+ */
+
+static
+int
+parse(int fd,struct unit *up,uint8_x *buf,l_fp *t)
+{
+	uint8_x c,sum;
+	uint16_x i,n,rp;
+	static uint8_x response[] = { 0, 2, 0, 0 };
+	/* This is partial list of packets that we should not ACK or NACK */
+	static uint8_x list[] = { PID_ACK_BYTE, PID_NAK_BYTE, PID_PVT_DATA,
+		PID_UNDOC_PVT };
+
+	rp = up->rp;
+	do {
+		*t = up->ts[rp];
+		GETBYTE(sum,up,rp);
+		if (sum != DLE)
+			continue;
+		GETBYTE(sum,up,rp);
+		if (sum == ETX)
+			continue;
+	} while (sum == DLE);
+	PKT_PID(buf) = sum;
+	GETBYTE_ESCAPED(n,up,rp);
+	sum += n;
+	PKT_SIZE(buf) = n;
+	n += 3;
+	for (i = 2;i < n; i++) {
+		GETBYTE_ESCAPED(c,up,rp);
+		sum += c;
+		buf[i] = c;
+	}
+	GETBYTE(c,up,rp);
+	PKT_PID(response) = PID_NAK_BYTE;
+	if (c == DLE) {
+		GETBYTE(c,up,rp);
+		if (c == ETX)
+			if (sum == 0)
+				PKT_PID(response) = PID_ACK_BYTE;
+	}
+	response[2] = PKT_PID(buf);
+	for (i = 0;i < SIZEOF(list); i++)
+		if (list[i] == PKT_PID(buf))
+			break;
+	if (i == SIZEOF(list))
+		gwrite(fd,response);
+	up->rp = rp;
+	if (PKT_PID(response) == PID_NAK_BYTE)
+		return(-1);
+	return(1);
+}
+
+/*
+ *	Collect the bytes as they come in from the serial port.  When
+ *	entire packets have been collected, pass them up to be processed.
+ *	Bad packets are silently dropped as if they were not received.
+ */
+
+static
+void
+gread(struct recvbuf *rbufp,callback func)
+{
+	uint8_x c,packet[PKT_MAX];
+	uint16_x i;
+	l_fp t;
+	int overflow;
+	struct refclockproc *pp;
+	struct peer *peer;
+	struct unit *up;
+
+	peer = (struct peer *)rbufp->recv_srcclock;
+	pp = peer->procptr;
+	up = (struct unit *)pp->unitptr;
+	overflow = FALSE;
+	for (i = 0;i < rbufp->recv_length; i++) {
+		c = rbufp->recv_buffer[i];
+#ifdef	TIMESTAMPS
+		if (up->tcnt < sizeof(up->tv)) {
+			((char *) &up->tv)[up->tcnt++] = c;
+			continue;
+		}
+		up->tcnt = 0;
+		up->tv.tv_sec += JAN_1970;
+		TVTOTS(&up->tv,&up->ts[up->wp]);
+#else	/* TIMESTAMPS */
+		up->ts[up->wp] = rbufp->recv_time;
+#endif	/* TIMESTAMPS */
+		up->buffer[up->wp++] = c;
+		up->wp = up->wp % SIZEOF(up->buffer);
+		overflow |= (up->wp == up->rp);
+	}
+	if (overflow)
+		up->rp = (up->wp + 1) % SIZEOF(up->buffer);
+	while (parse(pp->io.fd,up,packet,&t) > 0)
+		(*func)(rbufp,packet,&t);
+}
+
+#else
+int refclock_garmin_bs;
+#endif	/* REFCLOCK */
