LinuxPPS (Version 10): the PPS Linux implementation.
Subsystems (6)
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(-)
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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
@@ -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 __inlineint 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 __inlineint time_pps_destroy (pps_handle_t handle) +{ +return close (handle); +} + +static __inlineint 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 __inlineint 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 __inlineint time_pps_getcap (pps_handle_t handle,int *mode) +{ +return ioctl (handle,PPS_GETCAP , mode); +} + +static __inlineint 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 __inlineint 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
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
@@ -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
@@ -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
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
@@ -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
@@ -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
@@ -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
@@ -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
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
@@ -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
@@ -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
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
@@ -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
@@ -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
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
@@ -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
@@ -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
@@ -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
@@ -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
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
@@ -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
@@ -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
@@ -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
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
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