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. Please, note that since last submit a new line discipline has been added in order to leave untouched the serial ports code (as suggested by Alan). Rodolfo -- b/Documentation/ABI/testing/sysfs-pps | 73 +++++++ b/Documentation/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/tty.txt | 4 b/MAINTAINERS | 7 b/arch/x86/kernel/irq_32.c | 18 + b/arch/x86/kernel/irq_64.c | 22 ++ b/drivers/Kconfig | 2 b/drivers/Makefile | 1 b/drivers/char/lp.c | 61 ++++++ b/drivers/char/n_tty.c | 54 +++-- 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 | 154 +++++++++++++++ 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 ++ ...
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. Signed-off-by: Rodolfo Giometti <giometti@linux.it> --- Documentation/ABI/testing/sysfs-pps | 73 ++++++++ Documentation/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 diff --git ...
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. :)
Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
Documentation/pps/timepps.h | 195 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 195 insertions(+), 0 deletions(-)
create mode 100644 Documentation/pps/timepps.h
diff --git a/Documentation/pps/timepps.h b/Documentation/pps/timepps.h
new file mode 100644
index 0000000..2372949
--- /dev/null
+++ b/Documentation/pps/timepps.h
@@ -0,0 +1,195 @@
+/*
+ * timepps.h -- PPS API main header
+ *
+ * Copyright (C) 2005-2007 Rodolfo Giometti <giometti@linux.it>
+ *
+ * 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 ...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.
Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
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
diff --git a/Documentation/pps/Makefile b/Documentation/pps/Makefile
new file mode 100644
index 0000000..9841e6b
--- /dev/null
+++ b/Documentation/pps/Makefile
@@ -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}
diff --git a/Documentation/pps/ppsfind b/Documentation/pps/ppsfind
new file mode 100644
index 0000000..93c0e17
--- /dev/null
+++ b/Documentation/pps/ppsfind
@@ -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 ...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. Signed-off-by: Rodolfo Giometti <giometti@linux.it> --- 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 diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig index cc2eb8e..1afe4e0 100644 --- a/drivers/pps/Kconfig +++ b/drivers/pps/Kconfig @@ -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 diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile index 19ea582..98960dd 100644 --- a/drivers/pps/Makefile +++ b/drivers/pps/Makefile @@ -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 diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig new file mode 100644 index 0000000..60b83be --- /dev/null +++ b/drivers/pps/clients/Kconfig @@ -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 ...
Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
Documentation/tty.txt | 4 ++++
include/linux/tty_ldisc.h | 10 ++++++++++
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/Documentation/tty.txt b/Documentation/tty.txt
index 8e65c44..3fc812a 100644
--- a/Documentation/tty.txt
+++ b/Documentation/tty.txt
@@ -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
diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h
index 40f38d8..e74a28b 100644
--- a/include/linux/tty_ldisc.h
+++ b/include/linux/tty_ldisc.h
@@ -99,11 +99,19 @@
* 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 uart_port *port, 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>
#include <linux/wait.h>
+struct uart_port;
+
struct tty_ldisc_ops {
int magic;
char *name;
@@ -136,6 +144,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 uart_port *, unsigned int,
+ struct timespec *);
struct module *owner;
--
1.5.4.3
--
Signed-off-by: Rodolfo Giometti <giometti@linux.it>
---
drivers/char/n_tty.c | 54 +++++++++++++++++++++++++++++--------------------
include/linux/tty.h | 16 ++++++++++++++
2 files changed, 48 insertions(+), 22 deletions(-)
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index 708c2b1..10d037e 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -26,7 +26,7 @@
*
* 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to
* waiting writing processes-Sapan Bhatia <sapan@corewars.org>.
- * Also fixed a bug in BLOCKING mode where write_chan returns
+ * Also fixed a bug in BLOCKING mode where n_tty_write returns
* EAGAIN
*/
@@ -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>
@@ -184,7 +184,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
* Locking: ctrl_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 */
@@ -200,6 +200,7 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
}
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
}
+EXPORT_SYMBOL(n_tty_flush_buffer);
/**
* n_tty_chars_in_buffer - report available bytes
@@ -209,7 +210,7 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
* at this instant in time.
*/
-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;
@@ -225,6 +226,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty)
spin_unlock_irqrestore(&tty->read_lock, flags);
return n;
}
+EXPORT_SYMBOL(n_tty_chars_in_buffer);
/**
* is_utf8_continuation - utf8 multibyte ...Add a new line discipline for "pulse per second" devices connected to a serial port. Signed-off-by: Rodolfo Giometti <giometti@linux.it> --- include/linux/tty.h | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/include/linux/tty.h b/include/linux/tty.h index 826d695..1857db2 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -24,7 +24,7 @@ */ #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ -#define NR_LDISCS 18 +#define NR_LDISCS 19 /* line disciplines */ #define N_TTY 0 @@ -46,6 +46,7 @@ #define N_HCI 15 /* Bluetooth HCI UART */ #define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */ #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ +#define N_PPS 18 /* Pulse per Second */ /* * This character is the same as _POSIX_VDISABLE: it cannot be used as -- 1.5.4.3 --
Adds support, by using the PPS line discipline, for the PPS sources connected with the CD (Carrier Detect) pin of a serial port. Signed-off-by: Rodolfo Giometti <giometti@linux.it> --- drivers/pps/clients/Kconfig | 7 ++ drivers/pps/clients/Makefile | 1 + drivers/pps/clients/pps-ldisc.c | 154 +++++++++++++++++++++++++++++++++++++++ drivers/serial/8250.c | 13 +++ include/linux/serial_core.h | 10 ++- 5 files changed, 184 insertions(+), 1 deletions(-) create mode 100644 drivers/pps/clients/pps-ldisc.c diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig index 60b83be..487c1c8 100644 --- a/drivers/pps/clients/Kconfig +++ b/drivers/pps/clients/Kconfig @@ -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 diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile index f3c1e39..9f5b988 100644 --- a/drivers/pps/clients/Makefile +++ b/drivers/pps/clients/Makefile @@ -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 diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c new file mode 100644 index 0000000..f1efa26 --- /dev/null +++ b/drivers/pps/clients/pps-ldisc.c @@ -0,0 +1,154 @@ +/* + * pps-ldisc.c -- PPS line discipline + * + * + * Copyright (C) 2008 Rodolfo Giometti <giometti@linux.it> + * + * 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. + ...
See you really do want to pass struct tty * upwards anyway 8) Rest of this looks good. Maybe pps ldisc belongs in the n_tty file in the end but again that can be twiddled with after the merge. --
On Tue, 19 Aug 2008 23:50:09 +0200 Ack this and I'll push it upstream anyway so there is a stable number even if this doesn't all get upstream for a while. Acked-by: Alan Cox <alan@redhat.com> --
On Tue, 19 Aug 2008 23:50:08 +0200 Renames are really not part of the same change set but very sensible so no objection. EXPORT_SYMBOL_GPL please - pps is (with permission) sticking its nose into the innards of n_tty. Those are not good general interfaces however. With the small changes noted I'm happy for the tty stuff to go upstream. --
uart_port is a specific property of a few random types of interface, pass a tty struct up. Otherwise looks fine. Might one day expand it to a more generic change type and pass info on what changed but thats a future mystery. --
How can I get the struct uart_port pointer starting from struct tty_struct one? I need it in order to know which is the IRQ line of a single port. Thanks, Rodolfo -- GNU/Linux Solutions e-mail: giometti@enneenne.com Linux Device Driver giometti@linux.it Embedded Systems phone: +39 349 2432127 UNIX programming skype: rodolfo.giometti --
On Wed, 20 Aug 2008 00:49:31 +0200 A tty may not even have a uart structure. Why do you need to know the interrupt (if such a concept even exists for the given tty) ? Alan --
If you look at patch 9
(0009-PPS-low-level-IRQ-timestamps-recording.patch) you can see that
we add a (dirty?) trick to improve PPS precision a lot: we record all
IRQ timestamps into static array and then we return those values
instead of ones passed by dcd_change()...
Maybe I can solve the problem defining dcd_change() as follow:
void (*dcd_change)(struct tty_struct *tty, unsigned int status,
void *data)
and then passing the timestamp or struct uart_port pointer?
Thanks,
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@linux.it
Embedded Systems phone: +39 349 2432127
UNIX programming skype: rodolfo.giometti
--
After sleeping this night :) I think is better defing the
uart_handle_dcd_change() into serial_core.h as follow:
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;
if (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
if ((port->flags & UPF_HARDPPS_CD) && status)
hardpps();
#endif
if (info->flags & UIF_CHECK_CD) {
if (status)
wake_up_interruptible(&info->port.open_wait);
else if (info->port.tty)
tty_hangup(info->port.tty);
}
if (ld->ops->dcd_change)
ld->ops->dcd_change(info->port.tty, status, &ts);
tty_ldisc_deref(ld);
}
This completely hides the (dirty) trick to the PPS clients and allow
using struct tty_struct as first parameter.
Is that acceptable?
Rodolfo
--
GNU/Linux Solutions e-mail: giometti@enneenne.com
Linux Device Driver giometti@linux.it
Embedded Systems phone: +39 349 2432127
UNIX programming skype: rodolfo.giometti
--
That bit won't work very shortly - IRQ numbers are going sparse not a Can we get the basics right first - drop the IRQ_EVENTS and HARDPPS hackery out of the patchset and the core code then looks quite clean. After that is sorted/merged we can come back to working out the best way to improve the IRQ and HARDPPS hacks. Alan --
Ok, I'll propose a new patch set without the IRQ_EVENTS part (or with this support as last patch to be easily discarted) to get kernel inclusion, but we had to solve this issue soon since without this trick the PPS precision is quite low. Thanks, Rodolfo -- GNU/Linux Solutions e-mail: giometti@enneenne.com Linux Device Driver giometti@linux.it Embedded Systems phone: +39 349 2432127 UNIX programming skype: rodolfo.giometti --
well, i didnt suggest you kill that aspect of the patchset - i suggested you change it to hook into kernel/irq/*.c instead of arch/x86/kernel/irq*.c. That way all other architectures will benefit from it, not just x86. Doing an x86-only thing for such features is completely unacceptable. Ingo --
I see, but I agree with Alan that is better to get a first working I see but doing like this I can record IRQs timestamps sooner than in kernel/irq/*.c, is that right? PPS precision is as better as sooner we record the timestamps. Ciao, Rodolfo -- GNU/Linux Solutions e-mail: giometti@enneenne.com Linux Device Driver giometti@linux.it Embedded Systems phone: +39 349 2432127 UNIX programming skype: rodolfo.giometti --
This represents a reservation conflict even if it doesn't represent an actual conflict. If it is a reservation conflict only, please adjust the range reserved for soundcards (and verify with the sound maintainers that it's okay to do so); if it's an actual conflict please reassign. -hpa --
I think is quicker that I reassing the codes. I'll use 'p' a0-a4 which are free. Ciao, Rodolfo -- GNU/Linux Solutions e-mail: giometti@enneenne.com Linux Device Driver giometti@linux.it Embedded Systems phone: +39 349 2432127 UNIX programming skype: rodolfo.giometti --
