LinuxPPS (Version 9): the PPS Linux implementation.
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 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-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 | 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/1 ldisc: new dcd_change() method for line disciplines.
--- Documentation/tty.txt | 4 ++++ include/linux/tty_ldisc.h | 10 ++++++++++ 2 files changed, 14 insertions(+), 0 deletions(-)
Documentation/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 +10 -0
@@ -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 {int magic;char *name;
@@ -136,6 +144,8 @@ struct tty_ldisc {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;
Signature · 1 line
1.5.4.3
PATCH 1/1 ldisc n_tty: export all N_TTY ldisc methods.
--- drivers/char/n_tty.c | 54 +++++++++++++++++++++++++++++-------------------- include/linux/tty.h | 17 ++++++++++++++- 2 files changed, 48 insertions(+), 23 deletions(-)
drivers/char/n_tty.c +32 -22
@@ -26,7 +26,7 @@* * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to * waiting writing processes-Sapan Bhatia <[email protected]>. -* 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>
@@ -187,7 +187,7 @@ static void reset_buffer_flags(struct tty_struct *tty)* lock_kernel() still. */ -static void n_tty_flush_buffer (struct tty_struct * tty) +void n_tty_flush_buffer (struct tty_struct * tty) {/* clear everything and unthrottle the driver */ reset_buffer_flags (tty);
@@ -200,6 +200,7 @@ static void n_tty_flush_buffer(struct tty_struct * tty)wake_up_interruptible (&tty->link->read_wait); } } +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 check
@@ -337,7 +339,7 @@ static int opost(unsigned char c, struct tty_struct *tty)* the simple cases normally found and helps to generate blocks of * symbols for the console driver and thus improve performance. * -* Called from write_chan under the tty layer write lock. +* Called from n_tty_write under the tty layer write lock. */ static ssize_t opost_block(struct tty_struct * tty,
@@ -883,7 +885,7 @@ send_signal:* 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) {
@@ -892,6 +894,7 @@ static void n_tty_write_wakeup(struct tty_struct *tty) }return ; } +EXPORT_SYMBOL (n_tty_write_wakeup);/** * n_tty_receive_buf - data receive
@@ -906,7 +909,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;
@@ -984,6 +987,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, tty->driver->throttle (tty); } } +EXPORT_SYMBOL (n_tty_receive_buf);int is_ignored (int sig) {
@@ -1003,7 +1007,7 @@ int is_ignored(int sig)* when the ldisc is closed. */ -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) {if (!tty)return ;
@@ -1067,6 +1071,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios * old) }n_tty_set_room (tty); } +EXPORT_SYMBOL (n_tty_set_termios);/** * n_tty_close - close the ldisc for this tty
@@ -1078,7 +1083,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) {
@@ -1086,6 +1091,7 @@ static void n_tty_close(struct tty_struct *tty) tty->read_buf =NULL ; } } +EXPORT_SYMBOL (n_tty_close);/** * n_tty_open - open an ldisc
@@ -1097,7 +1103,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 ;
@@ -1116,6 +1122,7 @@ static int n_tty_open(struct tty_struct *tty) tty->closing =0 ;return 0 ; } +EXPORT_SYMBOL (n_tty_open);static inline int input_available_p (struct tty_struct *tty,int amt) {
@@ -1134,7 +1141,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt)* @b: user data * @nr: size of data * -* Helper function to speed up read_chan. It is only called when +* Helper function to speed up n_tty_read. It is only called when * ICANON is off; it copies characters straight from the tty queue to * user space directly. It can be profitably called twice; once to * drain the space from the tail pointer to the (physical) end of the
@@ -1195,7 +1202,7 @@ static int job_control(struct tty_struct *tty, struct file *file)if (file->f_op->write != redirected_tty_write && current->signal->tty == tty) {if (!tty->pgrp) -printk ("read_chan: no tty->pgrp!\n" ); +printk ("n_tty_read: no tty->pgrp!\n" );else if (task_pgrp (current) != tty->pgrp) {if (is_ignored (SIGTTIN ) ||is_current_pgrp_orphaned ())
@@ -1210,7 +1217,7 @@ static int job_control(struct tty_struct *tty, struct file *file)/** -* read_chan - read function for tty +* n_tty_read - read function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer
@@ -1224,7 +1231,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 read_chan (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;
@@ -1239,7 +1246,7 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, do_it_again:if (!tty->read_buf) { -printk ("n_tty_read_chan: called with read_buf == NULL?!?\n" ); +printk ("n_tty_read: called with read_buf == NULL?!?\n" );return -EIO ; }
@@ -1422,9 +1429,10 @@ do_it_again:return retval; } +EXPORT_SYMBOL (n_tty_read);/** -* write_chan - write function for tty +* n_tty_write - write function for tty * @tty: tty device * @file: file object * @buf: userspace buffer pointer
@@ -1438,7 +1446,7 @@ do_it_again:* This code must be sure never to sleep through a hangup. */ -static ssize_t write_chan (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;
@@ -1510,9 +1518,10 @@ break_out:remove_wait_queue (&tty->write_wait, &wait);return (b - buf) ? b - buf : retval; } +EXPORT_SYMBOL (n_tty_write);/** -* normal_poll - poll method for N_TTY +* n_tty_poll - poll method for N_TTY * @tty: terminal device * @file: file accessing it * @wait: poll table
@@ -1530,7 +1539,7 @@ break_out:* a read wakeup to fix this bug. */ -static unsigned int normal_poll (struct tty_struct * tty,struct file * file,poll_table *wait) +unsigned int n_tty_poll (struct tty_struct * tty,struct file * file,poll_table *wait) {unsigned int mask =0 ;
@@ -1556,6 +1565,7 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol mask |=POLLOUT |POLLWRNORM ;return mask; } +EXPORT_SYMBOL (n_tty_poll);struct tty_ldisc tty_ldisc_N_TTY = { .magic =TTY_LDISC_MAGIC ,
@@ -1564,11 +1574,11 @@ struct tty_ldisc tty_ldisc_N_TTY = { .close = n_tty_close, .flush_buffer = n_tty_flush_buffer, .chars_in_buffer = n_tty_chars_in_buffer, - .read = read_chan, - .write = write_chan, + .read = n_tty_read, + .write = n_tty_write, .ioctl = n_tty_ioctl, .set_termios = n_tty_set_termios, - .poll = normal_poll, + .poll = n_tty_poll, .receive_buf = n_tty_receive_buf, .write_wakeup = n_tty_write_wakeup };
include/linux/tty.h +16 -1
@@ -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>
@@ -383,7 +384,21 @@ static inline void tty_audit_opening(void)#endif /* tty_ioctl.c */ -extern int n_tty_ioctl (struct tty_struct * tty,struct file * file, +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); +extern int n_tty_ioctl (struct tty_struct *tty,struct file *file,unsigned int cmd,unsigned long arg);/* serial.c */
Signature · 1 line
1.5.4.3
PATCH 1/1 ldisc: new N_PPS (Pulse Per Second) line discipine.
--- include/linux/tty.h | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
include/linux/tty.h +2 -1
@@ -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 17 +#define NR_LDISCS 18/* line disciplines */ #define N_TTY 0
@@ -45,6 +45,7 @@#define N_SYNC_PPP 14/* synchronous PPP */ #define N_HCI 15/* Bluetooth HCI UART */ #define N_GIGASET_M101 16/* Siemens Gigaset M101 serial DECT adapter */ +#define N_PPS 17/* Pulse per Second */ /* * This character is the same as _POSIX_VDISABLE: it cannot be used as
Signature · 1 line
1.5.4.3
PATCH 1/1 PPS: UART PPS support replaced by new N_PPS line discipline.
Starting from now the PPS signal routed to the DCD pin of a serial ports is managed by a dedicated line discipline.
--- drivers/pps/clients/Kconfig | 9 +-- drivers/pps/clients/Makefile | 1 + drivers/pps/clients/pps-ldisc.c | 172 +++++++++++++++++++++++++++++++++++++++ drivers/serial/serial_core.c | 78 ------------------ include/linux/serial_core.h | 39 ++------- 5 files changed, 184 insertions(+), 115 deletions(-) create mode 100644 drivers/pps/clients/pps-ldisc.c
drivers/pps/clients/Kconfig +3 -6
@@ -15,12 +15,9 @@ config PPS_CLIENT_KTIMER This driver can also be built as a module. If so, the module will be called ktimer.ko. -comment "UART serial support (forced off)" - depends on ! (SERIAL_CORE != n && !(PPS = m && SERIAL_CORE = y)) - -config PPS_CLIENT_UART - bool "UART serial support" - depends on SERIAL_CORE != n && !(PPS = m && SERIAL_CORE = y) +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.
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 +172 -0
172 lines not on this page · raw message
drivers/serial/serial_core.c +0 -78
108 lines not on this page · raw message
include/linux/serial_core.h +8 -31
@@ -240,9 +240,6 @@ struct uart_port {unsigned char regshift;/* reg offset shift */ unsigned char iotype;/* io access style */ unsigned char unused1; -#ifdef CONFIG_PPS_CLIENT_UART -int pps_source;/* PPS source ID */ -#endif #define UPIO_PORT (0)#define UPIO_HUB6 (1)
@@ -321,10 +318,6 @@ struct uart_state {struct uart_info *info;struct uart_port *port; -#ifdef CONFIG_PPS_CLIENT_UART -struct pps_source_info pps_info; -#endif -struct mutex mutex; };
@@ -488,31 +481,11 @@ 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->tty); +struct timespec ts; -#ifdef CONFIG_PPS_CLIENT_UART -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; - -if (port->flags &UPF_HARDPPS_CD ) { -pps_event (port->pps_source, -#ifdef CONFIG_PPS_IRQ_EVENTS - &pps_irq_ts[port->irq], -#else - &ts, -#endif - status ?PPS_CAPTUREASSERT :PPS_CAPTURECLEAR , - port); -dev_dbg (port->dev,"PPS %s at %lu on source #%d\n" , - status ?"assert" :"clear" , jiffies, port->pps_source); - } -#endif +if (ld->dcd_change) +getnstimeofday (&ts); port->icount.dcd++;
@@ -522,6 +495,10 @@ uart_handle_dcd_change(struct uart_port *port, unsigned int status)else if (info->tty)tty_hangup (info->tty); } + +if (ld->dcd_change) + ld->dcd_change (port, status, &ts); +tty_ldisc_deref (ld); }/**
Signature · 1 line
1.5.4.3
Re: [PATCH] ldisc: new dcd_change() method for line disciplines.
In reply to Rodolfo Giomettiinclude/linux/tty_ldisc.h line 108
Quoted 13 lines · Rodolfo Giometti
include/linux/tty_ldisc.h +6
-0@@ -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. */
I don't see an actual call to that new method getting added anywhere. Is that planned for a later patch? Which serial drivers will support that mechanism? Should the documentation perhaps mention that not all drivers support this?
Thanks,
Tilman
Signature · 4 lines
Tilman Schmidt E-Mail: [email protected] Bonn, Germany Diese Nachricht besteht zu 100% aus wiederverwerteten Bits. Ungeöffnet mindestens haltbar bis: (siehe Rückseite)
Rodolfo Giometti
maintainerRe: [PATCH] ldisc: new dcd_change() method for line disciplines.
Quoted 11 lines · Tilman Schmidt
Quoted 10 lines · Rodolfo Giometti
include/linux/tty_ldisc.h +4
-0@@ -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) +*
Quoted 8 lines
include/linux/tty_ldisc.h line 108
Quoted 3 lines
include/linux/tty_ldisc.h +2
-0+* Tells the discipline that the DCD pin has changed its status and +* the relative timestamp. Pointer ts can be NULL. */ I don't see an actual call to that new method getting added anywhere. Is that planned for a later patch? Which serial drivers will support that mechanism? Should the documentation perhaps mention that not all drivers support this?
See patch pps-serial-clients-support.patch into this patchset.
Ciao,
Rodolfo
Signature · 4 lines
GNU/Linux Solutions e-mail: [email protected] Linux Device Driver [email protected] Embedded Systems phone: +39 349 2432127 UNIX programming skype: rodolfo.giometti
Re: [PATCH] ldisc: new dcd_change() method for line disciplines.
In reply to Tilman SchmidtQuoted 17 lines · On Fri, 28 Nov 2008 12:39:16 +0100 Tilman Schmidt <[email protected]> wrote:
include/linux/tty_ldisc.h line 108
Quoted 13 lines · Rodolfo Giometti
include/linux/tty_ldisc.h +6
-0@@ -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. */ I don't see an actual call to that new method getting added anywhere. Is that planned for a later patch?
Its used in one of the later patches of the set.
Quoted 1 line · On Tue, 25 Nov 2008 22:11:06 +0100 Rodolfo Giometti <[email protected]> wrote:
This patch set adds the PPS support into Linux.
I'm having way too much trouble getting all this to apply on 2.6.28-rc6, let alone linux-next.
Please redo everything against the latest Linus tree and resend everything with full changelogs, etc.
You could even redo the patches against linux-next, which is after all our candidate 2.6.29 tree. But afacit there are few conflicting changes in there at this time, apart from the fact that lots of files have been moved into different directories, but that's a relatively minor thing.