Skip to contentSkip to conversation

LinuxPPS (Version 10): the PPS Linux implementation.

PATCH New Rodolfo Giometti 2 participants 11 messages Nov 26, 2008 – Nov 27, 2008

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

Note: Very few changes since last post! Please, add this patch set
into next available merge window.

This patch set adds the PPS support into Linux.

PPS means "pulse per second" and its API is specified by RFC 2783 (Pulse-Per-Second API for UNIX-like Operating Systems, Version 1.0).

The code has been tested with the NTPD program
(http://www.eecis.udel.edu/~mills/ntp/html/index.html) and several GPS antennae.

Changelog
=========

Version 9 -> 10:
---------------

* Fixes for 2.6.28-rc6

Version 8 -> 9:
---------------

* language fix up.

Version 7 -> 8:
---------------

* PPS ldisc module locking fix up.

* race during ldisc initialization fix up.

Version 6 -> 7:
---------------

* A new line discipline has been added in order to leave untouched the serial ports code (as suggested by Alan).

* n_tty.c exports only GPL symbols.

* ioctl numbers fixed in order to avoid any conflicts.

Note: Last patch (0009-PPS-low-level-IRQ-timestamps-recording.patch)
implements low level IRQs timestamps recording which improves PPS precision but can be dropped for kernel inclusion! As suggested by Alan: "After that is sorted/merged we can come back to working out the best way to improve the IRQ and HARDPPS hacks."

Rodolfo

--

 b/Documentation/ABI/testing/sysfs-pps  |   73 +++++++
 b/Documentation/ioctl/ioctl-number.txt |    2
 b/Documentation/pps/Makefile           |   28 ++
 b/Documentation/pps/pps.txt            |  172 ++++++++++++++++
 b/Documentation/pps/ppsfind            |   17 +
 b/Documentation/pps/ppsldisc.c         |   46 ++++
 b/Documentation/pps/ppstest.c          |  151 ++++++++++++++
 b/Documentation/pps/timepps.h          |  195 +++++++++++++++++++
 b/Documentation/serial/tty.txt         |    4
 b/MAINTAINERS                          |    7
 b/arch/x86/kernel/irq_32.c             |   16 +
 b/arch/x86/kernel/irq_64.c             |   21 +-
 b/drivers/Kconfig                      |    2
 b/drivers/Makefile                     |    1
 b/drivers/char/lp.c                    |   61 ++++++
 b/drivers/char/n_tty.c                 |   32 ++-
 b/drivers/pps/Kconfig                  |   33 +++
 b/drivers/pps/Makefile                 |    8
 b/drivers/pps/clients/Kconfig          |   18 +
 b/drivers/pps/clients/Makefile         |    9
 b/drivers/pps/clients/ktimer.c         |  124 ++++++++++++
 b/drivers/pps/clients/pps-ldisc.c      |  155 +++++++++++++++
 b/drivers/pps/kapi.c                   |  322 +++++++++++++++++++++++++++++++
 b/drivers/pps/pps.c                    |  335 +++++++++++++++++++++++++++++++++
 b/drivers/pps/sysfs.c                  |  104 ++++++++++
 b/drivers/serial/8250.c                |   13 +
 b/include/linux/Kbuild                 |    1
 b/include/linux/parport.h              |   22 ++
 b/include/linux/pps.h                  |  202 +++++++++++++++++++
 b/include/linux/serial_core.h          |   11 -
 b/include/linux/tty.h                  |   16 +
 b/include/linux/tty_ldisc.h            |    8
 drivers/pps/Kconfig                    |   14 +
 drivers/pps/Makefile                   |    1
 drivers/pps/clients/Kconfig            |   17 +
 drivers/pps/clients/Makefile           |    1
 include/linux/pps.h                    |    1
 include/linux/serial_core.h            |    7
 38 files changed, 2235 insertions(+), 15 deletions(-)
#1 lore raw

PATCH 1/9 LinuxPPS core support.

This patch adds the kernel side of the PPS support currently named "LinuxPPS".

PPS means "pulse per second" and a PPS source is just a device which provides a high precision signal each second so that an application can use it to adjust system clock time.

Common use is the combination of the NTPD as userland program with a GPS receiver as PPS source to obtain a wallclock-time with sub-millisecond synchronisation to UTC.

To obtain this goal the userland programs shoud use the PPS API specification (RFC 2783 - Pulse-Per-Second API for UNIX-like Operating Systems, Version 1.0) which in part is implemented by this patch. It provides a set of chars devices, one per PPS source, which can be used to get the time signal. The RFC's functions can be implemented by accessing to these char devices.

---
 Documentation/ABI/testing/sysfs-pps  |   73 ++++++++
 Documentation/ioctl/ioctl-number.txt |    2 +
 Documentation/pps/pps.txt            |  172 +++++++++++++++++
 MAINTAINERS                          |    7 +
 drivers/Kconfig                      |    2 +
 drivers/Makefile                     |    1 +
 drivers/pps/Kconfig                  |   33 ++++
 drivers/pps/Makefile                 |    8 +
 drivers/pps/kapi.c                   |  322 ++++++++++++++++++++++++++++++++
 drivers/pps/pps.c                    |  335 ++++++++++++++++++++++++++++++++++
 drivers/pps/sysfs.c                  |  104 +++++++++++
 include/linux/Kbuild                 |    1 +
 include/linux/pps.h                  |  202 ++++++++++++++++++++
 13 files changed, 1262 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-pps
 create mode 100644 Documentation/pps/pps.txt
 create mode 100644 drivers/pps/Kconfig
 create mode 100644 drivers/pps/Makefile
 create mode 100644 drivers/pps/kapi.c
 create mode 100644 drivers/pps/pps.c
 create mode 100644 drivers/pps/sysfs.c
 create mode 100644 include/linux/pps.h
Documentation/ABI/testing/sysfs-pps new file +73 -0
new file mode 100644
index 0000000..25028c7
@@ -0,0 +1,73 @@
+What:		/sys/class/pps/
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ directory will contain files and
+		directories that will provide a unified interface to
+		the PPS sources.
+
+What:		/sys/class/pps/ppsX/
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ppsX/ directory is related to X-th
+		PPS source into the system. Each directory will
+		contain files to manage and control its PPS source.
+
+What:		/sys/class/pps/ppsX/assert
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ppsX/assert file reports the assert events
+		and the assert sequence number of the X-th source in the form:
+
+			<secs>.<nsec>#<sequence>
+
+		If the source has no assert events the content of this file
+		is empty.
+
+What:		/sys/class/pps/ppsX/clear
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ppsX/clear file reports the clear events
+		and the clear sequence number of the X-th source in the form:
+
+			<secs>.<nsec>#<sequence>
+
+		If the source has no clear events the content of this file
+		is empty.
+
+What:		/sys/class/pps/ppsX/mode
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ppsX/mode file reports the functioning
+		mode of the X-th source in hexadecimal encoding.
+
+		Please, refer to linux/include/linux/pps.h for further
+		info.
+
+What:		/sys/class/pps/ppsX/echo
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ppsX/echo file reports if the X-th does
+		or does not support an "echo" function.
+
+What:		/sys/class/pps/ppsX/name
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ppsX/name file reports the name of the
+		X-th source.
+
+What:		/sys/class/pps/ppsX/path
+Date:		February 2008
+Contact:	Rodolfo Giometti <[email protected]>
+Description:
+		The /sys/class/pps/ppsX/path file reports the path name of
+		the device connected with the X-th source.
+
+		If the source is not connected with any device the content
+		of this file is empty.
Documentation/ioctl/ioctl-number.txt +2 -0
index b880ce5..be021b5 100644
@@ -147,6 +147,8 @@ Code	Seq#	Include File		Comments
 'p'	40-7F	linux/nvram.h
 'p'	80-9F				user-space parport
 					<mailto:[email protected]>
+'p'	a0-a4	linux/pps.h		LinuxPPS
+					<mailto:[email protected]>
 'q'	00-1F	linux/serio.h
 'q'	80-FF				Internet PhoneJACK, Internet LineJACK
 					<http://www.quicknet.net>
Documentation/pps/pps.txt new file +172 -0

172 lines not on this page · raw message

MAINTAINERS +7 -0
index 618c1ef..01d6667 100644
@@ -3421,6 +3421,13 @@ P:	James Chapman
 M:	[email protected]
 S:	Maintained
 
+PPS SUPPORT
+P:	Rodolfo Giometti
+M:	[email protected]
+W:	http://wiki.enneenne.com/index.php/LinuxPPS_support
+L:	[email protected] (subscribers-only)
+S:	Maintained
+
 PREEMPTIBLE KERNEL
 P:	Robert Love
 M:	[email protected]
drivers/Kconfig +2 -0
index 2f557f5..4b679d2 100644
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
 
+source "drivers/pps/Kconfig"
+
 source "drivers/gpio/Kconfig"
 
 source "drivers/w1/Kconfig"
drivers/Makefile +1 -0
index fceb71a..da6329a 100644
@@ -67,6 +67,7 @@ obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
 obj-$(CONFIG_RTC_LIB)		+= rtc/
 obj-y				+= i2c/
+obj-$(CONFIG_PPS)		+= pps/
 obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_POWER_SUPPLY)	+= power/
 obj-$(CONFIG_HWMON)		+= hwmon/
drivers/pps/Kconfig new file +33 -0
new file mode 100644
index 0000000..cc2eb8e
@@ -0,0 +1,33 @@
+#
+# PPS support configuration
+#
+
+menu "PPS support"
+
+config PPS
+	tristate "PPS support"
+	depends on EXPERIMENTAL
+	---help---
+	  PPS (Pulse Per Second) is a special pulse provided by some GPS
+	  antennae. Userland can use it to get a high-precision time
+	  reference.
+
+	  Some antennae's PPS signals are connected with the CD (Carrier
+	  Detect) pin of the serial line they use to communicate with the
+	  host. In this case use the SERIAL_LINE client support.
+
+	  Some antennae's PPS signals are connected with some special host
+	  inputs so you have to enable the corresponding client support.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pps_core.ko.
+
+config PPS_DEBUG
+	bool "PPS debugging messages"
+	depends on PPS
+	help
+	  Say Y here if you want the PPS support to produce a bunch of debug
+	  messages to the system log.  Select this if you are having a
+	  problem with PPS support and want to see more of what is going on.
+
+endmenu
drivers/pps/Makefile new file +8 -0
new file mode 100644
index 0000000..19ea582
@@ -0,0 +1,8 @@
+#
+# Makefile for the PPS core.
+#
+
+pps_core-y			:= pps.o kapi.o sysfs.o
+obj-$(CONFIG_PPS)		:= pps_core.o
+
+ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
drivers/pps/kapi.c new file +322 -0

322 lines not on this page · raw message

drivers/pps/pps.c new file +335 -0

335 lines not on this page · raw message

drivers/pps/sysfs.c new file +104 -0

104 lines not on this page · raw message

include/linux/Kbuild +1 -0
index e531783..7f850e7 100644
@@ -309,6 +309,7 @@ unifdef-y += pmu.h
 unifdef-y += poll.h
 unifdef-y += ppp_defs.h
 unifdef-y += ppp-comp.h
+unifdef-y += pps.h
 unifdef-y += ptrace.h
 unifdef-y += qnx4_fs.h
 unifdef-y += quota.h
include/linux/pps.h new file +202 -0

202 lines not on this page · raw message

Signature · 1 line
1.5.4.3
#2 lore raw

PATCH 2/9 PPS: userland header file for PPS API.

This patch adds into the PPS's documentation directory a possible implementation of the PPS API (RFC 2783) by using the LinuxPPS's char devices.

This file is not just an example but it can be used into real systems. :)

---
 Documentation/pps/timepps.h |  195 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 195 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/pps/timepps.h
Documentation/pps/timepps.h new file +195 -0
new file mode 100644
index 0000000..2372949
@@ -0,0 +1,195 @@
+/*
+ * timepps.h -- PPS API main header
+ *
+ * Copyright (C) 2005-2007   Rodolfo Giometti <[email protected]>
+ *
+ *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _SYS_TIMEPPS_H_
+#define _SYS_TIMEPPS_H_
+
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <errno.h>
+#include <linux/pps.h>
+
+#define LINUXPPS	1		/* signal we are using LinuxPPS */
+
+/*
+ * New data structures
+ */
+
+struct ntp_fp {
+	unsigned int integral;
+	unsigned int fractional;
+};
+
+union pps_timeu {
+	struct timespec tspec;
+	struct ntp_fp ntpfp;
+	unsigned long longpad[3];
+};
+
+struct pps_info {
+	unsigned long assert_sequence;	/* seq. num. of assert event */
+	unsigned long clear_sequence;	/* seq. num. of clear event */
+	union pps_timeu assert_tu;	/* time of assert event */
+	union pps_timeu clear_tu;	/* time of clear event */
+	int current_mode;		/* current mode bits */
+};
+
+struct pps_params {
+	int api_version;		/* API version # */
+	int mode;			/* mode bits */
+	union pps_timeu assert_off_tu;	/* offset compensation for assert */
+	union pps_timeu clear_off_tu;	/* offset compensation for clear */
+};
+
+typedef int pps_handle_t;		/* represents a PPS source */
+typedef unsigned long pps_seq_t;	/* sequence number */
+typedef struct ntp_fp ntp_fp_t;		/* NTP-compatible time stamp */
+typedef union pps_timeu pps_timeu_t;	/* generic data type for time stamps */
+typedef struct pps_info pps_info_t;
+typedef struct pps_params pps_params_t;
+
+#define assert_timestamp        assert_tu.tspec
+#define clear_timestamp         clear_tu.tspec
+
+#define assert_timestamp_ntpfp  assert_tu.ntpfp
+#define clear_timestamp_ntpfp   clear_tu.ntpfp
+
+#define assert_offset		assert_off_tu.tspec
+#define clear_offset		clear_off_tu.tspec
+
+#define assert_offset_ntpfp     assert_off_tu.ntpfp
+#define clear_offset_ntpfp      clear_off_tu.ntpfp
+
+/*
+ * The PPS API
+ */
+
+static __inline int time_pps_create(int source, pps_handle_t *handle)
+{
+	int ret;
+
+	if (!handle) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/* First we check if current device is a PPS valid PPS one...
+	 */
+	ret = ioctl(source, PPS_CHECK);
+	if (ret) {
+		errno = EOPNOTSUPP;
+		return -1;
+	}
+
+	/* ... then since in LinuxPPS there are no differences between a
+	 * "PPS source" and a "PPS handle", we simply return the same value.
+	 */
+	*handle = source;
+
+	return 0;
+}
+
+static __inline int time_pps_destroy(pps_handle_t handle)
+{
+	return close(handle);
+}
+
+static __inline int time_pps_getparams(pps_handle_t handle,
+					pps_params_t *ppsparams)
+{
+	int ret;
+	struct pps_kparams __ppsparams;
+
+	ret = ioctl(handle, PPS_GETPARAMS, &__ppsparams);
+
+	ppsparams->api_version = __ppsparams.api_version;
+	ppsparams->mode = __ppsparams.mode;
+	ppsparams->assert_off_tu.tspec.tv_sec = __ppsparams.assert_off_tu.sec;
+	ppsparams->assert_off_tu.tspec.tv_nsec = __ppsparams.assert_off_tu.nsec;
+	ppsparams->clear_off_tu.tspec.tv_sec = __ppsparams.clear_off_tu.sec;
+	ppsparams->clear_off_tu.tspec.tv_nsec = __ppsparams.clear_off_tu.nsec;
+
+	return ret;
+}
+
+static __inline int time_pps_setparams(pps_handle_t handle,
+					const pps_params_t *ppsparams)
+{
+	struct pps_kparams __ppsparams;
+
+	__ppsparams.api_version = ppsparams->api_version;
+	__ppsparams.mode = ppsparams->mode;
+	__ppsparams.assert_off_tu.sec = ppsparams->assert_off_tu.tspec.tv_sec;
+	__ppsparams.assert_off_tu.nsec = ppsparams->assert_off_tu.tspec.tv_nsec;
+	__ppsparams.clear_off_tu.sec = ppsparams->clear_off_tu.tspec.tv_sec;
+	__ppsparams.clear_off_tu.nsec = ppsparams->clear_off_tu.tspec.tv_nsec;
+
+	return ioctl(handle, PPS_SETPARAMS, &__ppsparams);
+}
+
+/* Get capabilities for handle */
+static __inline int time_pps_getcap(pps_handle_t handle, int *mode)
+{
+	return ioctl(handle, PPS_GETCAP, mode);
+}
+
+static __inline int time_pps_fetch(pps_handle_t handle, const int tsformat,
+					pps_info_t *ppsinfobuf,
+					const struct timespec *timeout)
+{
+	struct pps_fdata __fdata;
+	int ret;
+
+	/* Sanity checks */
+	if (tsformat != PPS_TSFMT_TSPEC) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (timeout) {
+		__fdata.timeout.sec = timeout->tv_sec;
+		__fdata.timeout.nsec = timeout->tv_nsec;
+		__fdata.timeout.flags = ~PPS_TIME_INVALID;
+	} else
+		__fdata.timeout.flags = PPS_TIME_INVALID;
+
+	ret = ioctl(handle, PPS_FETCH, &__fdata);
+
+	ppsinfobuf->assert_sequence = __fdata.info.assert_sequence;
+	ppsinfobuf->clear_sequence = __fdata.info.clear_sequence;
+	ppsinfobuf->assert_tu.tspec.tv_sec = __fdata.info.assert_tu.sec;
+	ppsinfobuf->assert_tu.tspec.tv_nsec = __fdata.info.assert_tu.nsec;
+	ppsinfobuf->clear_tu.tspec.tv_sec = __fdata.info.clear_tu.sec;
+	ppsinfobuf->clear_tu.tspec.tv_nsec = __fdata.info.clear_tu.nsec;
+	ppsinfobuf->current_mode = __fdata.info.current_mode;
+
+	return ret;
+}
+
+static __inline int time_pps_kcbind(pps_handle_t handle,
+					const int kernel_consumer,
+					const int edge, const int tsformat)
+{
+	/* LinuxPPS doesn't implement kernel consumer feature */
+	errno = EOPNOTSUPP;
+	return -1;
+}
+
+#endif				/* _SYS_TIMEPPS_H_ */
Signature · 1 line
1.5.4.3
#3 lore raw

PATCH 3/9 PPS: documentation programs and examples.

Here some utilities and examples about the PPS API and the LinuxPPS support.

* ppsldisc.c shows how to manage PPS line discipline;

* ppstest.c implements an useful testing program, while

* ppsfind tries to help the user into finding a specific PPS source by using its name or path.

---
 Documentation/pps/Makefile   |   28 ++++++++
 Documentation/pps/ppsfind    |   17 +++++
 Documentation/pps/ppsldisc.c |   46 +++++++++++++
 Documentation/pps/ppstest.c  |  151 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 242 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/pps/Makefile
 create mode 100644 Documentation/pps/ppsfind
 create mode 100644 Documentation/pps/ppsldisc.c
 create mode 100644 Documentation/pps/ppstest.c
Documentation/pps/Makefile new file +28 -0
new file mode 100644
index 0000000..9841e6b
@@ -0,0 +1,28 @@
+TARGETS = ppstest ppsldisc
+
+CFLAGS += -Wall -O2 -D_GNU_SOURCE
+CFLAGS += -I .
+CFLAGS += -ggdb
+CFLAGS += -D__N_PPS=$(shell awk '/N_PPS/ {print $$3}' ../../include/linux/tty.h)
+
+# -- Actions section --
+
+.PHONY : all depend dep
+
+all : .depend $(TARGETS)
+
+.depend depend dep :
+	$(CC) $(CFLAGS) -M $(TARGETS:=.c) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+
+
+# -- Clean section --
+
+.PHONY : clean
+
+clean :
+	rm -f *.o *~ core .depend
+	rm -f ${TARGETS}
Documentation/pps/ppsfind new file +17 -0
new file mode 100644
index 0000000..93c0e17
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+SYS="/sys/class/pps/"
+
+if [ $# -lt 1 ] ; then
+	echo "usage: ppsfind <name>" >&2
+	exit 1
+fi
+
+for d in $(ls $SYS) ; do
+	if grep $1 $SYS/$d/name >& /dev/null || \
+	   grep $1 $SYS/$d/path >& /dev/null ; then
+		echo "$d: name=$(cat $SYS/$d/name) path=$(cat $SYS/$d/path)"
+	fi
+done
+
+exit 0
Documentation/pps/ppsldisc.c new file +46 -0

46 lines not on this page · raw message

Documentation/pps/ppstest.c new file +151 -0

151 lines not on this page · raw message

Signature · 1 line
1.5.4.3
#4 lore raw

PATCH 4/9 PPS: LinuxPPS clients support.

Each PPS source can be registered/deregistered into the system by using special modules called "clients". They simply define the PPS sources' attributes and implement the time signal registartion mechanism.

This patch adds a special directory for such clients and adds a dummy client that can be useful to test system integrity on real systems.

---
 drivers/pps/Kconfig          |    2 +
 drivers/pps/Makefile         |    1 +
 drivers/pps/clients/Kconfig  |   18 ++++++
 drivers/pps/clients/Makefile |    9 +++
 drivers/pps/clients/ktimer.c |  124 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+), 0 deletions(-)
 create mode 100644 drivers/pps/clients/Kconfig
 create mode 100644 drivers/pps/clients/Makefile
 create mode 100644 drivers/pps/clients/ktimer.c
drivers/pps/Kconfig +2 -0
index cc2eb8e..1afe4e0 100644
@@ -30,4 +30,6 @@ config PPS_DEBUG
 	  messages to the system log.  Select this if you are having a
 	  problem with PPS support and want to see more of what is going on.
 
+source drivers/pps/clients/Kconfig
+
 endmenu
drivers/pps/Makefile +1 -0
index 19ea582..98960dd 100644
@@ -4,5 +4,6 @@
 
 pps_core-y			:= pps.o kapi.o sysfs.o
 obj-$(CONFIG_PPS)		:= pps_core.o
+obj-y				+= clients/
 
 ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
drivers/pps/clients/Kconfig new file +18 -0
new file mode 100644
index 0000000..60b83be
@@ -0,0 +1,18 @@
+#
+# PPS clients configuration
+#
+
+if PPS
+
+comment "PPS clients support"
+
+config PPS_CLIENT_KTIMER
+	tristate "Kernel timer client (Testing client, use for debug)"
+	help
+	  If you say yes here you get support for a PPS debugging client
+	  which uses a kernel timer to generate the PPS signal.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called ktimer.ko.
+
+endif
drivers/pps/clients/Makefile new file +9 -0
new file mode 100644
index 0000000..f3c1e39
@@ -0,0 +1,9 @@
+#
+# Makefile for PPS clients.
+#
+
+obj-$(CONFIG_PPS_CLIENT_KTIMER)	+= ktimer.o
+
+ifeq ($(CONFIG_PPS_DEBUG),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
drivers/pps/clients/ktimer.c new file +124 -0

124 lines not on this page · raw message

Signature · 1 line
1.5.4.3
#5 lore raw

PATCH 5/9 ldisc: new dcd_change() method for line disciplines.

---
 Documentation/serial/tty.txt |    4 ++++
 include/linux/tty_ldisc.h    |    8 ++++++++
 2 files changed, 12 insertions(+), 0 deletions(-)
Documentation/serial/tty.txt +4 -0
index 8e65c44..3fc812a 100644
@@ -100,6 +100,10 @@ write_wakeup()	-	May be called at any point between open and close.
 			is permitted to call the driver write method from
 			this function. In such a situation defer it.
 
+dcd_change()	-	Report to the tty line the current DCD pin status
+			changes and the relative timestamp. The timestamp
+			can be NULL.
+
 
 Driver Access
 
include/linux/tty_ldisc.h +8 -0
index 40f38d8..526fbf4 100644
@@ -99,6 +99,12 @@
  *	cease I/O to the tty driver. Can sleep. The driver should
  *	seek to perform this action quickly but should wait until
  *	any pending driver I/O is completed.
+ *
+ * void (*dcd_change)(struct tty_struct *tty, unsigned int status,
+ * 			struct timespec *ts)
+ *
+ *	Tells the discipline that the DCD pin has changed its status and
+ *	the relative timestamp. Pointer ts can be NULL.
  */
 
 #include <linux/fs.h>
@@ -136,6 +142,8 @@ struct tty_ldisc_ops {
 	void	(*receive_buf)(struct tty_struct *, const unsigned char *cp,
 			       char *fp, int count);
 	void	(*write_wakeup)(struct tty_struct *);
+	void	(*dcd_change)(struct tty_struct *, unsigned int,
+				struct timespec *);
 
 	struct  module *owner;
 	
Signature · 1 line
1.5.4.3
#6 lore raw

PATCH 6/9 ldisc n_tty: export all N_TTY ldisc methods.

---
 drivers/char/n_tty.c |   32 +++++++++++++++++++++-----------
 include/linux/tty.h  |   16 ++++++++++++++++
 2 files changed, 37 insertions(+), 11 deletions(-)
drivers/char/n_tty.c +21 -11
index efbfe96..9db2e35 100644
@@ -43,10 +43,10 @@
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/poll.h>
 #include <linux/bitops.h>
 #include <linux/audit.h>
 #include <linux/file.h>
+#include <linux/module.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
@@ -194,7 +194,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
  *	Locking: ctrl_lock, read_lock.
  */
 
-static void n_tty_flush_buffer(struct tty_struct *tty)
+void n_tty_flush_buffer(struct tty_struct *tty)
 {
 	unsigned long flags;
 	/* clear everything and unthrottle the driver */
@@ -210,6 +210,7 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
 	}
 	spin_unlock_irqrestore(&tty->ctrl_lock, flags);
 }
+EXPORT_SYMBOL_GPL(n_tty_flush_buffer);
 
 /**
  *	n_tty_chars_in_buffer	-	report available bytes
@@ -221,7 +222,7 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
  *	Locking: read_lock
  */
 
-static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
+ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
 {
 	unsigned long flags;
 	ssize_t n = 0;
@@ -237,6 +238,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
 	spin_unlock_irqrestore(&tty->read_lock, flags);
 	return n;
 }
+EXPORT_SYMBOL_GPL(n_tty_chars_in_buffer);
 
 /**
  *	is_utf8_continuation	-	utf8 multibyte check
@@ -921,13 +923,14 @@ handle_newline:
  *	IO must be woken up
  */
 
-static void n_tty_write_wakeup(struct tty_struct *tty)
+void n_tty_write_wakeup(struct tty_struct *tty)
 {
 	if (tty->fasync) {
 		set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
 		kill_fasync(&tty->fasync, SIGIO, POLL_OUT);
 	}
 }
+EXPORT_SYMBOL_GPL(n_tty_write_wakeup);
 
 /**
  *	n_tty_receive_buf	-	data receive
@@ -942,7 +945,7 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
  *	calls one at a time and in order (or using flush_to_ldisc)
  */
 
-static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 			      char *fp, int count)
 {
 	const unsigned char *p;
@@ -1016,6 +1019,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 	if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
 		tty_throttle(tty);
 }
+EXPORT_SYMBOL_GPL(n_tty_receive_buf);
 
 int is_ignored(int sig)
 {
@@ -1037,7 +1041,7 @@ int is_ignored(int sig)
  *	Locking: Caller holds tty->termios_mutex
  */
 
-static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
+void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 {
 	int canon_change = 1;
 	BUG_ON(!tty);
@@ -1116,6 +1120,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 	wake_up_interruptible(&tty->write_wait);
 	wake_up_interruptible(&tty->read_wait);
 }
+EXPORT_SYMBOL_GPL(n_tty_set_termios);
 
 /**
  *	n_tty_close		-	close the ldisc for this tty
@@ -1127,7 +1132,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
  *	ldisc methods are in progress.
  */
 
-static void n_tty_close(struct tty_struct *tty)
+void n_tty_close(struct tty_struct *tty)
 {
 	n_tty_flush_buffer(tty);
 	if (tty->read_buf) {
@@ -1135,6 +1140,7 @@ static void n_tty_close(struct tty_struct *tty)
 		tty->read_buf = NULL;
 	}
 }
+EXPORT_SYMBOL_GPL(n_tty_close);
 
 /**
  *	n_tty_open		-	open an ldisc
@@ -1146,7 +1152,7 @@ static void n_tty_close(struct tty_struct *tty)
  *	until a close.
  */
 
-static int n_tty_open(struct tty_struct *tty)
+int n_tty_open(struct tty_struct *tty)
 {
 	if (!tty)
 		return -EINVAL;
@@ -1165,6 +1171,7 @@ static int n_tty_open(struct tty_struct *tty)
 	tty->closing = 0;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(n_tty_open);
 
 static inline int input_available_p(struct tty_struct *tty, int amt)
 {
@@ -1279,7 +1286,7 @@ static int job_control(struct tty_struct *tty, struct file *file)
  *	This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
 			 unsigned char __user *buf, size_t nr)
 {
 	unsigned char __user *b = buf;
@@ -1479,6 +1486,7 @@ do_it_again:
 	n_tty_set_room(tty);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(n_tty_read);
 
 /**
  *	n_tty_write		-	write function for tty
@@ -1495,7 +1503,7 @@ do_it_again:
  *	This code must be sure never to sleep through a hangup.
  */
 
-static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
 			  const unsigned char *buf, size_t nr)
 {
 	const unsigned char *b = buf;
@@ -1567,6 +1575,7 @@ break_out:
 	remove_wait_queue(&tty->write_wait, &wait);
 	return (b - buf) ? b - buf : retval;
 }
+EXPORT_SYMBOL_GPL(n_tty_write);
 
 /**
  *	n_tty_poll		-	poll method for N_TTY
@@ -1582,7 +1591,7 @@ break_out:
  *	Called without the kernel lock held - fine
  */
 
-static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
+unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 							poll_table *wait)
 {
 	unsigned int mask = 0;
@@ -1609,6 +1618,7 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
 		mask |= POLLOUT | POLLWRNORM;
 	return mask;
 }
+EXPORT_SYMBOL_GPL(n_tty_poll);
 
 static unsigned long inq_canon(struct tty_struct *tty)
 {
include/linux/tty.h +16 -0
index 3b8121d..190ad4a 100644
@@ -13,6 +13,7 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_ldisc.h>
 #include <linux/mutex.h>
+#include <linux/poll.h>
 
 #include <asm/system.h>
 
@@ -432,6 +433,21 @@ extern void tty_ldisc_begin(void);
 /* This last one is just for the tty layer internals and shouldn't be used elsewhere */
 extern void tty_ldisc_enable(struct tty_struct *tty);
 
+extern void n_tty_flush_buffer(struct tty_struct *tty);
+extern ssize_t n_tty_chars_in_buffer(struct tty_struct *tty);
+extern void n_tty_write_wakeup(struct tty_struct *tty);
+extern void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+			char *fp, int count);
+extern void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old);
+extern void n_tty_close(struct tty_struct *tty);
+extern int n_tty_open(struct tty_struct *tty);
+extern ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
+			unsigned char __user *buf, size_t nr);
+extern ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
+			const unsigned char *buf, size_t nr);
+extern unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
+			poll_table *wait);
+
 
 /* n_tty.c */
 extern struct tty_ldisc_ops tty_ldisc_N_TTY;
Signature · 1 line
1.5.4.3
#7 lore raw

PATCH 7/9 PPS: serial clients support.

Adds support, by using the PPS line discipline, for the PPS sources connected with the CD (Carrier Detect) pin of a serial port.

---
 drivers/pps/clients/Kconfig     |    7 ++
 drivers/pps/clients/Makefile    |    1 +
 drivers/pps/clients/pps-ldisc.c |  155 +++++++++++++++++++++++++++++++++++++++
 drivers/serial/8250.c           |   13 +++
 include/linux/serial_core.h     |   11 +++-
 5 files changed, 186 insertions(+), 1 deletions(-)
 create mode 100644 drivers/pps/clients/pps-ldisc.c
drivers/pps/clients/Kconfig +7 -0
index 60b83be..487c1c8 100644
@@ -15,4 +15,11 @@ config PPS_CLIENT_KTIMER
 	  This driver can also be built as a module.  If so, the module
 	  will be called ktimer.ko.
 
+config PPS_CLIENT_LDISC
+	tristate "PPS line discipline"
+	depends on PPS
+	help
+	  If you say yes here you get support for a PPS source connected
+	  with the CD (Carrier Detect) pin of your serial port.
+
 endif
drivers/pps/clients/Makefile +1 -0
index f3c1e39..9f5b988 100644
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_PPS_CLIENT_KTIMER)	+= ktimer.o
+obj-$(CONFIG_PPS_CLIENT_LDISC)	+= pps-ldisc.o
 
 ifeq ($(CONFIG_PPS_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
drivers/pps/clients/pps-ldisc.c new file +155 -0

155 lines not on this page · raw message

drivers/serial/8250.c +13 -0
index 303272a..b425116 100644
@@ -2313,6 +2313,18 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
 }
 
 static void
+serial8250_set_ldisc(struct uart_port *port)
+{
+	int line = port->line;
+
+	if (line >= port->info->port.tty->driver->num)
+		return;
+
+	if (port->info->port.tty->ldisc.ops->num == N_PPS)
+		serial8250_enable_ms(port);
+}
+
+static void
 serial8250_pm(struct uart_port *port, unsigned int state,
 	      unsigned int oldstate)
 {
@@ -2523,6 +2535,7 @@ static struct uart_ops serial8250_pops = {
 	.startup	= serial8250_startup,
 	.shutdown	= serial8250_shutdown,
 	.set_termios	= serial8250_set_termios,
+	.set_ldisc	= serial8250_set_ldisc,
 	.pm		= serial8250_pm,
 	.type		= serial8250_type,
 	.release_port	= serial8250_release_port,
include/linux/serial_core.h +10 -1
index 4e4f127..cd6af20 100644
@@ -491,9 +491,13 @@ static inline void
 uart_handle_dcd_change(struct uart_port *port, unsigned int status)
 {
 	struct uart_info *info = port->info;
+	struct tty_ldisc *ld = tty_ldisc_ref(info->port.tty);
+	struct timespec ts;
 
-	port->icount.dcd++;
+	if (ld && ld->ops->dcd_change)
+		getnstimeofday(&ts);
 
+	port->icount.dcd++;
 #ifdef CONFIG_HARD_PPS
 	if ((port->flags & UPF_HARDPPS_CD) && status)
 		hardpps();
@@ -505,6 +509,11 @@ uart_handle_dcd_change(struct uart_port *port, unsigned int status)
 		else if (info->port.tty)
 			tty_hangup(info->port.tty);
 	}
+
+	if (ld && ld->ops->dcd_change)
+		ld->ops->dcd_change(port, status, &ts);
+	if (ld)
+		tty_ldisc_deref(ld);
 }
 
 /**
Signature · 1 line
1.5.4.3
#8 lore raw

PATCH 8/9 PPS: parallel port clients support.

Adds support for the PPS sources connected with the interrupt pin of a parallel port.

---
 drivers/char/lp.c           |   61 +++++++++++++++++++++++++++++++++++++++++++
 drivers/pps/clients/Kconfig |   10 +++++++
 include/linux/parport.h     |   22 +++++++++++++++
 3 files changed, 93 insertions(+), 0 deletions(-)
drivers/char/lp.c +61 -0
index e444c2d..dca8a39 100644
@@ -760,6 +760,27 @@ static struct console lpcons = {
 
 #endif /* console on line printer */
 
+/* Support for PPS signal on the line printer */
+
+#ifdef CONFIG_PPS_CLIENT_LP
+
+static void lp_pps_echo(int source, int event, void *data)
+{
+	struct parport *port = data;
+	unsigned char status = parport_read_status(port);
+
+	/* echo event via SEL bit */
+	parport_write_control(port,
+		parport_read_control(port) | PARPORT_CONTROL_SELECT);
+
+	/* signal no event */
+	if ((status & PARPORT_STATUS_ACK) != 0)
+		parport_write_control(port,
+			parport_read_control(port) & ~PARPORT_CONTROL_SELECT);
+}
+
+#endif
+
 /* --- initialisation code ------------------------------------- */
 
 static int parport_nr[LP_NO] = { [0 ... LP_NO-1] = LP_PARPORT_UNSPEC };
@@ -831,6 +852,38 @@ static int lp_register(int nr, struct parport *port)
 	}
 #endif
 
+#ifdef CONFIG_PPS_CLIENT_LP
+	port->pps_info.owner = THIS_MODULE;
+	port->pps_info.dev = port->dev;
+	snprintf(port->pps_info.path, PPS_MAX_NAME_LEN, "/dev/lp%d", nr);
+
+	/* No PPS support if lp port has no IRQ line */
+	if (port->irq != PARPORT_IRQ_NONE) {
+		strncpy(port->pps_info.name, port->name, PPS_MAX_NAME_LEN);
+
+		port->pps_info.mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
+				PPS_ECHOASSERT | \
+				PPS_CANWAIT | PPS_TSFMT_TSPEC;
+
+		port->pps_info.echo = lp_pps_echo;
+
+		port->pps_source = pps_register_source(&(port->pps_info),
+				PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
+		if (port->pps_source < 0)
+			dev_err(port->dev,
+					"cannot register PPS source \"%s\"\n",
+					port->pps_info.path);
+		else
+			dev_info(port->dev, "PPS source #%d \"%s\" added\n",
+					port->pps_source, port->pps_info.path);
+	} else {
+		port->pps_source = -1;
+		dev_err(port->dev, "PPS support disabled because port \"%s\" "
+					"is in polling mode\n",
+					port->pps_info.path);
+	}
+#endif
+
 	return 0;
 }
 
@@ -873,6 +926,14 @@ static void lp_detach (struct parport *port)
 		console_registered = NULL;
 	}
 #endif /* CONFIG_LP_CONSOLE */
+
+#ifdef CONFIG_PPS_CLIENT_LP
+	if (port->pps_source >= 0) {
+		pps_unregister_source(port->pps_source);
+		dev_dbg(port->dev, "PPS source #%d \"%s\" removed\n",
+			port->pps_source, port->pps_info.path);
+	}
+#endif
 }
 
 static struct parport_driver lp_driver = {
drivers/pps/clients/Kconfig +10 -0
index 487c1c8..b4054cd 100644
@@ -22,4 +22,14 @@ config PPS_CLIENT_LDISC
 	  If you say yes here you get support for a PPS source connected
 	  with the CD (Carrier Detect) pin of your serial port.
 
+comment "Parallel printer support (forced off)"
+	depends on !( PRINTER != n && !(PPS = m && PRINTER = y))
+
+config PPS_CLIENT_LP
+	bool "Parallel printer support"
+	depends on PRINTER != n && !(PPS = m && PRINTER = y)
+	help
+	  If you say yes here you get support for a PPS source connected
+	  with the interrupt pin of your parallel port.
+
 endif
include/linux/parport.h +22 -0
index e1f83c5..4276941 100644
@@ -98,6 +98,7 @@ typedef enum {
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <linux/pps.h>
 #include <linux/irqreturn.h>
 #include <linux/semaphore.h>
 #include <asm/system.h>
@@ -326,6 +327,11 @@ struct parport {
 
 	struct list_head full_list;
 	struct parport *slaves[3];
+
+#ifdef CONFIG_PPS_CLIENT_LP
+	struct pps_source_info pps_info;
+	int pps_source;		/* PPS source ID */
+#endif
 };
 
 #define DEFAULT_SPIN_TIME 500 /* us */
@@ -514,6 +520,22 @@ extern int parport_daisy_select (struct parport *port, int daisy, int mode);
 /* Lowlevel drivers _can_ call this support function to handle irqs.  */
 static inline void parport_generic_irq(struct parport *port)
 {
+#ifdef CONFIG_PPS_CLIENT_LP
+	struct timespec __ts;
+	struct pps_ktime ts;
+
+	/* First of all we get the time stamp... */
+	getnstimeofday(&__ts);
+
+	/* ... and translate it to PPS time data struct */
+	ts.sec = __ts.tv_sec;
+	ts.nsec = __ts.tv_nsec;
+
+	pps_event(port->pps_source, &ts, PPS_CAPTUREASSERT, port);
+	dev_dbg(port->dev, "PPS assert at %lu on source #%d\n",
+		jiffies, port->pps_source);
+#endif
+
 	parport_ieee1284_interrupt (port);
 	read_lock(&port->cad_lock);
 	if (port->cad && port->cad->irq_func)
Signature · 1 line
1.5.4.3
#9 lore raw

PATCH 9/9 PPS: low level IRQ timestamps recording.

Add low level IRQ timestamps recording for x86 (32 and 64 bits) platforms and enable UART clients in order to use it.

This improves PPS precision. :)

---
 arch/x86/kernel/irq_32.c    |   16 ++++++++++++++++
 arch/x86/kernel/irq_64.c    |   21 +++++++++++++++++++--
 drivers/pps/Kconfig         |   12 ++++++++++++
 include/linux/pps.h         |    1 +
 include/linux/serial_core.h |    7 ++++++-
 5 files changed, 54 insertions(+), 3 deletions(-)
arch/x86/kernel/irq_32.c +16 -0
index a513826..7fce1e2 100644
@@ -15,6 +15,7 @@
 #include <linux/notifier.h>
 #include <linux/cpu.h>
 #include <linux/delay.h>
+#include <linux/pps.h>
 
 #include <asm/apic.h>
 #include <asm/uaccess.h>
@@ -25,6 +26,11 @@ EXPORT_PER_CPU_SYMBOL(irq_stat);
 DEFINE_PER_CPU(struct pt_regs *, irq_regs);
 EXPORT_PER_CPU_SYMBOL(irq_regs);
 
+#ifdef CONFIG_PPS_IRQ_EVENTS
+struct timespec pps_irq_ts[NR_IRQS];
+EXPORT_SYMBOL(pps_irq_ts);
+#endif
+
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 /* Debugging check for stack overflow: is there less than 1KB free? */
 static int check_stack_overflow(void)
@@ -204,7 +210,12 @@ unsigned int do_IRQ(struct pt_regs *regs)
 	unsigned vector = ~regs->orig_ax;
 	struct irq_desc *desc;
 	unsigned irq;
+#ifdef CONFIG_PPS_IRQ_EVENTS
+	struct timespec ts;
 
+	/* Get IRQ timestamps as soon as possible for the PPS layer */
+	getnstimeofday(&ts);
+#endif
 
 	old_regs = set_irq_regs(regs);
 	irq_enter();
@@ -219,6 +230,11 @@ unsigned int do_IRQ(struct pt_regs *regs)
 		BUG();
 	}
 
+#ifdef CONFIG_PPS_IRQ_EVENTS
+	/* Then, after sanity check, store the IRQ timestamp */
+	pps_irq_ts[irq] = ts;
+#endif
+
 	if (!execute_on_irq_stack(overflow, desc, irq)) {
 		if (unlikely(overflow))
 			print_stack_overflow();
arch/x86/kernel/irq_64.c +19 -2
index 60eb84e..a1457a0 100644
@@ -17,6 +17,12 @@
 #include <asm/io_apic.h>
 #include <asm/idle.h>
 #include <asm/smp.h>
+#include <linux/pps.h>
+
+#ifdef CONFIG_PPS_IRQ_EVENTS
+struct timespec pps_irq_ts[NR_IRQS];
+EXPORT_SYMBOL(pps_irq_ts);
+#endif
 
 #ifdef CONFIG_DEBUG_STACKOVERFLOW
 /*
@@ -51,6 +57,12 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 {
 	struct pt_regs *old_regs = set_irq_regs(regs);
 	struct irq_desc *desc;
+#ifdef CONFIG_PPS_IRQ_EVENTS
+	struct timespec ts;
+
+	/* Get IRQ timestamps as soon as possible for the PPS layer */
+	getnstimeofday(&ts);
+#endif
 
 	/* high bit used in ret_from_ code  */
 	unsigned vector = ~regs->orig_ax;
@@ -65,9 +77,14 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
 #endif
 
 	desc = irq_to_desc(irq);
-	if (likely(desc))
+	if (likely(desc)) {
+#ifdef CONFIG_PPS_IRQ_EVENTS
+		/* Then, after sanity check, store the IRQ timestamp */
+		pps_irq_ts[irq] = ts;
+#endif
+
 		generic_handle_irq_desc(irq, desc);
-	else {
+	} else {
 		if (!disable_apic)
 			ack_APIC_irq();
 
drivers/pps/Kconfig +12 -0
index 1afe4e0..7c0b094 100644
@@ -22,6 +22,18 @@ config PPS
 	  To compile this driver as a module, choose M here: the module
 	  will be called pps_core.ko.
 
+config PPS_IRQ_EVENTS
+	bool "Use low level IRQ timestamps"
+	depends on PPS && (X86_32 || X86_64)
+	default yes
+	help
+	  Say Y here if you wish using low level IRQ timestamps to register
+	  PPS events.
+
+	  This should improve PPS resolution but it delays echo functions
+	  call. Note also that this function is not implemented on all
+	  platforms and PPS clients!
+
 config PPS_DEBUG
 	bool "PPS debugging messages"
 	depends on PPS
include/linux/pps.h +1 -0
index b5c3cf9..191190e 100644
@@ -181,6 +181,7 @@ struct pps_device {
 
 extern spinlock_t pps_idr_lock;
 extern struct idr pps_idr;
+extern struct timespec pps_irq_ts[];
 
 extern struct device_attribute pps_attrs[];
 
include/linux/serial_core.h +6 -1
index cd6af20..eac89e6 100644
@@ -168,6 +168,7 @@
 #include <linux/tty.h>
 #include <linux/mutex.h>
 #include <linux/sysrq.h>
+#include <linux/pps.h>
 
 struct uart_port;
 struct uart_info;
@@ -495,7 +496,11 @@ uart_handle_dcd_change(struct uart_port *port, unsigned int status)
 	struct timespec ts;
 
 	if (ld && ld->ops->dcd_change)
+#ifdef CONFIG_PPS_IRQ_EVENTS
+		ts = pps_irq_ts[port->irq];
+#else
 		getnstimeofday(&ts);
+#endif
 
 	port->icount.dcd++;
 #ifdef CONFIG_HARD_PPS
@@ -511,7 +516,7 @@ uart_handle_dcd_change(struct uart_port *port, unsigned int status)
 	}
 
 	if (ld && ld->ops->dcd_change)
-		ld->ops->dcd_change(port, status, &ts);
+		ld->ops->dcd_change(info->port.tty, status, &ts);
 	if (ld)
 		tty_ldisc_deref(ld);
 }
Signature · 1 line
1.5.4.3
#10 lore raw
In reply to Rodolfo Giometti
Quoted 11 lines · Rodolfo Giometti

Note: Very few changes since last post! Please, add this patch set
into next available merge window.

This patch set adds the PPS support into Linux.

PPS means "pulse per second" and its API is specified by RFC 2783 (Pulse-Per-Second API for UNIX-like Operating Systems, Version 1.0).

The code has been tested with the NTPD program
(http://www.eecis.udel.edu/~mills/ntp/html/index.html) and several GPS antennae.

Yay! Thank you for still working on this. I am using 5.3.1 at the moment on 2.6.26 (was using 3.0.0 for a long time on 2.6.18) and so far things are great.

Signature · 1 line
Len Sorensen