aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRodolfo Giometti <giometti@linux.it>2009-06-17 19:28:37 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-18 16:04:04 -0400
commiteae9d2ba0cfc27a2ad9765f23efb98fb80d80234 (patch)
treef4be40ca528b2f23f97fa9cb6ebe91b8d6696d5b
parent8820f27ad9a5ad2a62cdcdf425d7921c31831800 (diff)
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. Signed-off-by: Rodolfo Giometti <giometti@linux.it> Cc: David Woodhouse <dwmw2@infradead.org> Cc: Greg KH <greg@kroah.com> Cc: Randy Dunlap <randy.dunlap@oracle.com> Cc: Kay Sievers <kay.sievers@vrfy.org> Acked-by: Alan Cox <alan@lxorguk.ukuu.org.uk> Cc: Michael Kerrisk <mtk.manpages@googlemail.com> Cc: Christoph Hellwig <hch@infradead.org> Cc: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--Documentation/ABI/testing/sysfs-pps73
-rw-r--r--Documentation/ioctl/ioctl-number.txt2
-rw-r--r--Documentation/pps/pps.txt172
-rw-r--r--MAINTAINERS7
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/pps/Kconfig33
-rw-r--r--drivers/pps/Makefile8
-rw-r--r--drivers/pps/kapi.c329
-rw-r--r--drivers/pps/pps.c312
-rw-r--r--drivers/pps/sysfs.c98
-rw-r--r--include/linux/Kbuild1
-rw-r--r--include/linux/pps.h122
-rw-r--r--include/linux/pps_kernel.h89
14 files changed, 1249 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-pps b/Documentation/ABI/testing/sysfs-pps
new file mode 100644
index 000000000000..25028c7bc37d
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-pps
@@ -0,0 +1,73 @@
1What: /sys/class/pps/
2Date: February 2008
3Contact: Rodolfo Giometti <giometti@linux.it>
4Description:
5 The /sys/class/pps/ directory will contain files and
6 directories that will provide a unified interface to
7 the PPS sources.
8
9What: /sys/class/pps/ppsX/
10Date: February 2008
11Contact: Rodolfo Giometti <giometti@linux.it>
12Description:
13 The /sys/class/pps/ppsX/ directory is related to X-th
14 PPS source into the system. Each directory will
15 contain files to manage and control its PPS source.
16
17What: /sys/class/pps/ppsX/assert
18Date: February 2008
19Contact: Rodolfo Giometti <giometti@linux.it>
20Description:
21 The /sys/class/pps/ppsX/assert file reports the assert events
22 and the assert sequence number of the X-th source in the form:
23
24 <secs>.<nsec>#<sequence>
25
26 If the source has no assert events the content of this file
27 is empty.
28
29What: /sys/class/pps/ppsX/clear
30Date: February 2008
31Contact: Rodolfo Giometti <giometti@linux.it>
32Description:
33 The /sys/class/pps/ppsX/clear file reports the clear events
34 and the clear sequence number of the X-th source in the form:
35
36 <secs>.<nsec>#<sequence>
37
38 If the source has no clear events the content of this file
39 is empty.
40
41What: /sys/class/pps/ppsX/mode
42Date: February 2008
43Contact: Rodolfo Giometti <giometti@linux.it>
44Description:
45 The /sys/class/pps/ppsX/mode file reports the functioning
46 mode of the X-th source in hexadecimal encoding.
47
48 Please, refer to linux/include/linux/pps.h for further
49 info.
50
51What: /sys/class/pps/ppsX/echo
52Date: February 2008
53Contact: Rodolfo Giometti <giometti@linux.it>
54Description:
55 The /sys/class/pps/ppsX/echo file reports if the X-th does
56 or does not support an "echo" function.
57
58What: /sys/class/pps/ppsX/name
59Date: February 2008
60Contact: Rodolfo Giometti <giometti@linux.it>
61Description:
62 The /sys/class/pps/ppsX/name file reports the name of the
63 X-th source.
64
65What: /sys/class/pps/ppsX/path
66Date: February 2008
67Contact: Rodolfo Giometti <giometti@linux.it>
68Description:
69 The /sys/class/pps/ppsX/path file reports the path name of
70 the device connected with the X-th source.
71
72 If the source is not connected with any device the content
73 of this file is empty.
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 1f779a25c703..7bb0d934b6d8 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -149,6 +149,8 @@ Code Seq# Include File Comments
149'p' 40-7F linux/nvram.h 149'p' 40-7F linux/nvram.h
150'p' 80-9F user-space parport 150'p' 80-9F user-space parport
151 <mailto:tim@cyberelk.net> 151 <mailto:tim@cyberelk.net>
152'p' a1-a4 linux/pps.h LinuxPPS
153 <mailto:giometti@linux.it>
152'q' 00-1F linux/serio.h 154'q' 00-1F linux/serio.h
153'q' 80-FF Internet PhoneJACK, Internet LineJACK 155'q' 80-FF Internet PhoneJACK, Internet LineJACK
154 <http://www.quicknet.net> 156 <http://www.quicknet.net>
diff --git a/Documentation/pps/pps.txt b/Documentation/pps/pps.txt
new file mode 100644
index 000000000000..125f4ab48998
--- /dev/null
+++ b/Documentation/pps/pps.txt
@@ -0,0 +1,172 @@
1
2 PPS - Pulse Per Second
3 ----------------------
4
5(C) Copyright 2007 Rodolfo Giometti <giometti@enneenne.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or
10(at your option) any later version.
11
12This program is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17
18
19Overview
20--------
21
22LinuxPPS provides a programming interface (API) to define in the
23system several PPS sources.
24
25PPS means "pulse per second" and a PPS source is just a device which
26provides a high precision signal each second so that an application
27can use it to adjust system clock time.
28
29A PPS source can be connected to a serial port (usually to the Data
30Carrier Detect pin) or to a parallel port (ACK-pin) or to a special
31CPU's GPIOs (this is the common case in embedded systems) but in each
32case when a new pulse arrives the system must apply to it a timestamp
33and record it for userland.
34
35Common use is the combination of the NTPD as userland program, with a
36GPS receiver as PPS source, to obtain a wallclock-time with
37sub-millisecond synchronisation to UTC.
38
39
40RFC considerations
41------------------
42
43While implementing a PPS API as RFC 2783 defines and using an embedded
44CPU GPIO-Pin as physical link to the signal, I encountered a deeper
45problem:
46
47 At startup it needs a file descriptor as argument for the function
48 time_pps_create().
49
50This implies that the source has a /dev/... entry. This assumption is
51ok for the serial and parallel port, where you can do something
52useful besides(!) the gathering of timestamps as it is the central
53task for a PPS-API. But this assumption does not work for a single
54purpose GPIO line. In this case even basic file-related functionality
55(like read() and write()) makes no sense at all and should not be a
56precondition for the use of a PPS-API.
57
58The problem can be simply solved if you consider that a PPS source is
59not always connected with a GPS data source.
60
61So your programs should check if the GPS data source (the serial port
62for instance) is a PPS source too, and if not they should provide the
63possibility to open another device as PPS source.
64
65In LinuxPPS the PPS sources are simply char devices usually mapped
66into files /dev/pps0, /dev/pps1, etc..
67
68
69Coding example
70--------------
71
72To register a PPS source into the kernel you should define a struct
73pps_source_info_s as follows:
74
75 static struct pps_source_info pps_ktimer_info = {
76 .name = "ktimer",
77 .path = "",
78 .mode = PPS_CAPTUREASSERT | PPS_OFFSETASSERT | \
79 PPS_ECHOASSERT | \
80 PPS_CANWAIT | PPS_TSFMT_TSPEC,
81 .echo = pps_ktimer_echo,
82 .owner = THIS_MODULE,
83 };
84
85and then calling the function pps_register_source() in your
86intialization routine as follows:
87
88 source = pps_register_source(&pps_ktimer_info,
89 PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
90
91The pps_register_source() prototype is:
92
93 int pps_register_source(struct pps_source_info_s *info, int default_params)
94
95where "info" is a pointer to a structure that describes a particular
96PPS source, "default_params" tells the system what the initial default
97parameters for the device should be (it is obvious that these parameters
98must be a subset of ones defined in the struct
99pps_source_info_s which describe the capabilities of the driver).
100
101Once you have registered a new PPS source into the system you can
102signal an assert event (for example in the interrupt handler routine)
103just using:
104
105 pps_event(source, &ts, PPS_CAPTUREASSERT, ptr)
106
107where "ts" is the event's timestamp.
108
109The same function may also run the defined echo function
110(pps_ktimer_echo(), passing to it the "ptr" pointer) if the user
111asked for that... etc..
112
113Please see the file drivers/pps/clients/ktimer.c for example code.
114
115
116SYSFS support
117-------------
118
119If the SYSFS filesystem is enabled in the kernel it provides a new class:
120
121 $ ls /sys/class/pps/
122 pps0/ pps1/ pps2/
123
124Every directory is the ID of a PPS sources defined in the system and
125inside you find several files:
126
127 $ ls /sys/class/pps/pps0/
128 assert clear echo mode name path subsystem@ uevent
129
130Inside each "assert" and "clear" file you can find the timestamp and a
131sequence number:
132
133 $ cat /sys/class/pps/pps0/assert
134 1170026870.983207967#8
135
136Where before the "#" is the timestamp in seconds; after it is the
137sequence number. Other files are:
138
139* echo: reports if the PPS source has an echo function or not;
140
141* mode: reports available PPS functioning modes;
142
143* name: reports the PPS source's name;
144
145* path: reports the PPS source's device path, that is the device the
146 PPS source is connected to (if it exists).
147
148
149Testing the PPS support
150-----------------------
151
152In order to test the PPS support even without specific hardware you can use
153the ktimer driver (see the client subsection in the PPS configuration menu)
154and the userland tools provided into Documentaion/pps/ directory.
155
156Once you have enabled the compilation of ktimer just modprobe it (if
157not statically compiled):
158
159 # modprobe ktimer
160
161and the run ppstest as follow:
162
163 $ ./ppstest /dev/pps0
164 trying PPS source "/dev/pps1"
165 found PPS source "/dev/pps1"
166 ok, found 1 source(s), now start fetching data...
167 source 0 - assert 1186592699.388832443, sequence: 364 - clear 0.000000000, sequence: 0
168 source 0 - assert 1186592700.388931295, sequence: 365 - clear 0.000000000, sequence: 0
169 source 0 - assert 1186592701.389032765, sequence: 366 - clear 0.000000000, sequence: 0
170
171Please, note that to compile userland programs you need the file timepps.h
172(see Documentation/pps/).
diff --git a/MAINTAINERS b/MAINTAINERS
index 5b7a08d88e4f..035df9d26609 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4577,6 +4577,13 @@ S: Maintained
4577F: drivers/net/pppol2tp.c 4577F: drivers/net/pppol2tp.c
4578F: include/linux/if_pppol2tp.h 4578F: include/linux/if_pppol2tp.h
4579 4579
4580PPS SUPPORT
4581P: Rodolfo Giometti
4582M: giometti@enneenne.com
4583W: http://wiki.enneenne.com/index.php/LinuxPPS_support
4584L: linuxpps@ml.enneenne.com (subscribers-only)
4585S: Maintained
4586
4580PREEMPTIBLE KERNEL 4587PREEMPTIBLE KERNEL
4581P: Robert Love 4588P: Robert Love
4582M: rml@tech9.net 4589M: rml@tech9.net
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a442c8f29fc1..48bbdbe43e69 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
52 52
53source "drivers/spi/Kconfig" 53source "drivers/spi/Kconfig"
54 54
55source "drivers/pps/Kconfig"
56
55source "drivers/gpio/Kconfig" 57source "drivers/gpio/Kconfig"
56 58
57source "drivers/w1/Kconfig" 59source "drivers/w1/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 00b44f4ccf03..bc4205d2fc3c 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -72,6 +72,7 @@ obj-$(CONFIG_INPUT) += input/
72obj-$(CONFIG_I2O) += message/ 72obj-$(CONFIG_I2O) += message/
73obj-$(CONFIG_RTC_LIB) += rtc/ 73obj-$(CONFIG_RTC_LIB) += rtc/
74obj-y += i2c/ media/ 74obj-y += i2c/ media/
75obj-$(CONFIG_PPS) += pps/
75obj-$(CONFIG_W1) += w1/ 76obj-$(CONFIG_W1) += w1/
76obj-$(CONFIG_POWER_SUPPLY) += power/ 77obj-$(CONFIG_POWER_SUPPLY) += power/
77obj-$(CONFIG_HWMON) += hwmon/ 78obj-$(CONFIG_HWMON) += hwmon/
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
new file mode 100644
index 000000000000..cc2eb8edb514
--- /dev/null
+++ b/drivers/pps/Kconfig
@@ -0,0 +1,33 @@
1#
2# PPS support configuration
3#
4
5menu "PPS support"
6
7config PPS
8 tristate "PPS support"
9 depends on EXPERIMENTAL
10 ---help---
11 PPS (Pulse Per Second) is a special pulse provided by some GPS
12 antennae. Userland can use it to get a high-precision time
13 reference.
14
15 Some antennae's PPS signals are connected with the CD (Carrier
16 Detect) pin of the serial line they use to communicate with the
17 host. In this case use the SERIAL_LINE client support.
18
19 Some antennae's PPS signals are connected with some special host
20 inputs so you have to enable the corresponding client support.
21
22 To compile this driver as a module, choose M here: the module
23 will be called pps_core.ko.
24
25config PPS_DEBUG
26 bool "PPS debugging messages"
27 depends on PPS
28 help
29 Say Y here if you want the PPS support to produce a bunch of debug
30 messages to the system log. Select this if you are having a
31 problem with PPS support and want to see more of what is going on.
32
33endmenu
diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile
new file mode 100644
index 000000000000..19ea582f431d
--- /dev/null
+++ b/drivers/pps/Makefile
@@ -0,0 +1,8 @@
1#
2# Makefile for the PPS core.
3#
4
5pps_core-y := pps.o kapi.o sysfs.o
6obj-$(CONFIG_PPS) := pps_core.o
7
8ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
new file mode 100644
index 000000000000..35a0b192d768
--- /dev/null
+++ b/drivers/pps/kapi.c
@@ -0,0 +1,329 @@
1/*
2 * kernel API
3 *
4 *
5 * Copyright (C) 2005-2009 Rodolfo Giometti <giometti@linux.it>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/sched.h>
27#include <linux/time.h>
28#include <linux/spinlock.h>
29#include <linux/idr.h>
30#include <linux/fs.h>
31#include <linux/pps_kernel.h>
32
33/*
34 * Global variables
35 */
36
37DEFINE_SPINLOCK(pps_idr_lock);
38DEFINE_IDR(pps_idr);
39
40/*
41 * Local functions
42 */
43
44static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
45{
46 ts->nsec += offset->nsec;
47 while (ts->nsec >= NSEC_PER_SEC) {
48 ts->nsec -= NSEC_PER_SEC;
49 ts->sec++;
50 }
51 while (ts->nsec < 0) {
52 ts->nsec += NSEC_PER_SEC;
53 ts->sec--;
54 }
55 ts->sec += offset->sec;
56}
57
58/*
59 * Exported functions
60 */
61
62/* pps_get_source - find a PPS source
63 * @source: the PPS source ID.
64 *
65 * This function is used to find an already registered PPS source into the
66 * system.
67 *
68 * The function returns NULL if found nothing, otherwise it returns a pointer
69 * to the PPS source data struct (the refcounter is incremented by 1).
70 */
71
72struct pps_device *pps_get_source(int source)
73{
74 struct pps_device *pps;
75 unsigned long flags;
76
77 spin_lock_irqsave(&pps_idr_lock, flags);
78
79 pps = idr_find(&pps_idr, source);
80 if (pps != NULL)
81 atomic_inc(&pps->usage);
82
83 spin_unlock_irqrestore(&pps_idr_lock, flags);
84
85 return pps;
86}
87
88/* pps_put_source - free the PPS source data
89 * @pps: a pointer to the PPS source.
90 *
91 * This function is used to free a PPS data struct if its refcount is 0.
92 */
93
94void pps_put_source(struct pps_device *pps)
95{
96 unsigned long flags;
97
98 spin_lock_irqsave(&pps_idr_lock, flags);
99 BUG_ON(atomic_read(&pps->usage) == 0);
100
101 if (!atomic_dec_and_test(&pps->usage)) {
102 pps = NULL;
103 goto exit;
104 }
105
106 /* No more reference to the PPS source. We can safely remove the
107 * PPS data struct.
108 */
109 idr_remove(&pps_idr, pps->id);
110
111exit:
112 spin_unlock_irqrestore(&pps_idr_lock, flags);
113 kfree(pps);
114}
115
116/* pps_register_source - add a PPS source in the system
117 * @info: the PPS info struct
118 * @default_params: the default PPS parameters of the new source
119 *
120 * This function is used to add a new PPS source in the system. The new
121 * source is described by info's fields and it will have, as default PPS
122 * parameters, the ones specified into default_params.
123 *
124 * The function returns, in case of success, the PPS source ID.
125 */
126
127int pps_register_source(struct pps_source_info *info, int default_params)
128{
129 struct pps_device *pps;
130 int id;
131 int err;
132
133 /* Sanity checks */
134 if ((info->mode & default_params) != default_params) {
135 printk(KERN_ERR "pps: %s: unsupported default parameters\n",
136 info->name);
137 err = -EINVAL;
138 goto pps_register_source_exit;
139 }
140 if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
141 info->echo == NULL) {
142 printk(KERN_ERR "pps: %s: echo function is not defined\n",
143 info->name);
144 err = -EINVAL;
145 goto pps_register_source_exit;
146 }
147 if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
148 printk(KERN_ERR "pps: %s: unspecified time format\n",
149 info->name);
150 err = -EINVAL;
151 goto pps_register_source_exit;
152 }
153
154 /* Allocate memory for the new PPS source struct */
155 pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
156 if (pps == NULL) {
157 err = -ENOMEM;
158 goto pps_register_source_exit;
159 }
160
161 /* These initializations must be done before calling idr_get_new()
162 * in order to avoid reces into pps_event().
163 */
164 pps->params.api_version = PPS_API_VERS;
165 pps->params.mode = default_params;
166 pps->info = *info;
167
168 init_waitqueue_head(&pps->queue);
169 spin_lock_init(&pps->lock);
170 atomic_set(&pps->usage, 1);
171
172 /* Get new ID for the new PPS source */
173 if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
174 err = -ENOMEM;
175 goto kfree_pps;
176 }
177
178 spin_lock_irq(&pps_idr_lock);
179
180 /* Now really allocate the PPS source.
181 * After idr_get_new() calling the new source will be freely available
182 * into the kernel.
183 */
184 err = idr_get_new(&pps_idr, pps, &id);
185 if (err < 0) {
186 spin_unlock_irq(&pps_idr_lock);
187 goto kfree_pps;
188 }
189
190 id = id & MAX_ID_MASK;
191 if (id >= PPS_MAX_SOURCES) {
192 spin_unlock_irq(&pps_idr_lock);
193
194 printk(KERN_ERR "pps: %s: too many PPS sources in the system\n",
195 info->name);
196 err = -EBUSY;
197 goto free_idr;
198 }
199 pps->id = id;
200
201 spin_unlock_irq(&pps_idr_lock);
202
203 /* Create the char device */
204 err = pps_register_cdev(pps);
205 if (err < 0) {
206 printk(KERN_ERR "pps: %s: unable to create char device\n",
207 info->name);
208 goto free_idr;
209 }
210
211 pr_info("new PPS source %s at ID %d\n", info->name, id);
212
213 return id;
214
215free_idr:
216 spin_lock_irq(&pps_idr_lock);
217 idr_remove(&pps_idr, id);
218 spin_unlock_irq(&pps_idr_lock);
219
220kfree_pps:
221 kfree(pps);
222
223pps_register_source_exit:
224 printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
225
226 return err;
227}
228EXPORT_SYMBOL(pps_register_source);
229
230/* pps_unregister_source - remove a PPS source from the system
231 * @source: the PPS source ID
232 *
233 * This function is used to remove a previously registered PPS source from
234 * the system.
235 */
236
237void pps_unregister_source(int source)
238{
239 struct pps_device *pps;
240
241 spin_lock_irq(&pps_idr_lock);
242 pps = idr_find(&pps_idr, source);
243
244 if (!pps) {
245 BUG();
246 spin_unlock_irq(&pps_idr_lock);
247 return;
248 }
249 spin_unlock_irq(&pps_idr_lock);
250
251 pps_unregister_cdev(pps);
252 pps_put_source(pps);
253}
254EXPORT_SYMBOL(pps_unregister_source);
255
256/* pps_event - register a PPS event into the system
257 * @source: the PPS source ID
258 * @ts: the event timestamp
259 * @event: the event type
260 * @data: userdef pointer
261 *
262 * This function is used by each PPS client in order to register a new
263 * PPS event into the system (it's usually called inside an IRQ handler).
264 *
265 * If an echo function is associated with the PPS source it will be called
266 * as:
267 * pps->info.echo(source, event, data);
268 */
269
270void pps_event(int source, struct pps_ktime *ts, int event, void *data)
271{
272 struct pps_device *pps;
273 unsigned long flags;
274
275 if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
276 printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
277 event, source);
278 return;
279 }
280
281 pps = pps_get_source(source);
282 if (!pps)
283 return;
284
285 pr_debug("PPS event on source %d at %llu.%06u\n",
286 pps->id, (unsigned long long) ts->sec, ts->nsec);
287
288 spin_lock_irqsave(&pps->lock, flags);
289
290 /* Must call the echo function? */
291 if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
292 pps->info.echo(source, event, data);
293
294 /* Check the event */
295 pps->current_mode = pps->params.mode;
296 if (event & PPS_CAPTUREASSERT) {
297 /* We have to add an offset? */
298 if (pps->params.mode & PPS_OFFSETASSERT)
299 pps_add_offset(ts, &pps->params.assert_off_tu);
300
301 /* Save the time stamp */
302 pps->assert_tu = *ts;
303 pps->assert_sequence++;
304 pr_debug("capture assert seq #%u for source %d\n",
305 pps->assert_sequence, source);
306 }
307 if (event & PPS_CAPTURECLEAR) {
308 /* We have to add an offset? */
309 if (pps->params.mode & PPS_OFFSETCLEAR)
310 pps_add_offset(ts, &pps->params.clear_off_tu);
311
312 /* Save the time stamp */
313 pps->clear_tu = *ts;
314 pps->clear_sequence++;
315 pr_debug("capture clear seq #%u for source %d\n",
316 pps->clear_sequence, source);
317 }
318
319 pps->go = ~0;
320 wake_up_interruptible(&pps->queue);
321
322 kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
323
324 spin_unlock_irqrestore(&pps->lock, flags);
325
326 /* Now we can release the PPS source for (possible) deregistration */
327 pps_put_source(pps);
328}
329EXPORT_SYMBOL(pps_event);
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
new file mode 100644
index 000000000000..ac8cc8cea1e3
--- /dev/null
+++ b/drivers/pps/pps.c
@@ -0,0 +1,312 @@
1/*
2 * PPS core file
3 *
4 *
5 * Copyright (C) 2005-2009 Rodolfo Giometti <giometti@linux.it>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/init.h>
26#include <linux/sched.h>
27#include <linux/uaccess.h>
28#include <linux/idr.h>
29#include <linux/cdev.h>
30#include <linux/poll.h>
31#include <linux/pps_kernel.h>
32
33/*
34 * Local variables
35 */
36
37static dev_t pps_devt;
38static struct class *pps_class;
39
40/*
41 * Char device methods
42 */
43
44static unsigned int pps_cdev_poll(struct file *file, poll_table *wait)
45{
46 struct pps_device *pps = file->private_data;
47
48 poll_wait(file, &pps->queue, wait);
49
50 return POLLIN | POLLRDNORM;
51}
52
53static int pps_cdev_fasync(int fd, struct file *file, int on)
54{
55 struct pps_device *pps = file->private_data;
56 return fasync_helper(fd, file, on, &pps->async_queue);
57}
58
59static long pps_cdev_ioctl(struct file *file,
60 unsigned int cmd, unsigned long arg)
61{
62 struct pps_device *pps = file->private_data;
63 struct pps_kparams params;
64 struct pps_fdata fdata;
65 unsigned long ticks;
66 void __user *uarg = (void __user *) arg;
67 int __user *iuarg = (int __user *) arg;
68 int err;
69
70 switch (cmd) {
71 case PPS_GETPARAMS:
72 pr_debug("PPS_GETPARAMS: source %d\n", pps->id);
73
74 /* Return current parameters */
75 err = copy_to_user(uarg, &pps->params,
76 sizeof(struct pps_kparams));
77 if (err)
78 return -EFAULT;
79
80 break;
81
82 case PPS_SETPARAMS:
83 pr_debug("PPS_SETPARAMS: source %d\n", pps->id);
84
85 /* Check the capabilities */
86 if (!capable(CAP_SYS_TIME))
87 return -EPERM;
88
89 err = copy_from_user(&params, uarg, sizeof(struct pps_kparams));
90 if (err)
91 return -EFAULT;
92 if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
93 pr_debug("capture mode unspecified (%x)\n",
94 params.mode);
95 return -EINVAL;
96 }
97
98 /* Check for supported capabilities */
99 if ((params.mode & ~pps->info.mode) != 0) {
100 pr_debug("unsupported capabilities (%x)\n",
101 params.mode);
102 return -EINVAL;
103 }
104
105 spin_lock_irq(&pps->lock);
106
107 /* Save the new parameters */
108 pps->params = params;
109
110 /* Restore the read only parameters */
111 if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
112 /* section 3.3 of RFC 2783 interpreted */
113 pr_debug("time format unspecified (%x)\n",
114 params.mode);
115 pps->params.mode |= PPS_TSFMT_TSPEC;
116 }
117 if (pps->info.mode & PPS_CANWAIT)
118 pps->params.mode |= PPS_CANWAIT;
119 pps->params.api_version = PPS_API_VERS;
120
121 spin_unlock_irq(&pps->lock);
122
123 break;
124
125 case PPS_GETCAP:
126 pr_debug("PPS_GETCAP: source %d\n", pps->id);
127
128 err = put_user(pps->info.mode, iuarg);
129 if (err)
130 return -EFAULT;
131
132 break;
133
134 case PPS_FETCH:
135 pr_debug("PPS_FETCH: source %d\n", pps->id);
136
137 err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
138 if (err)
139 return -EFAULT;
140
141 pps->go = 0;
142
143 /* Manage the timeout */
144 if (fdata.timeout.flags & PPS_TIME_INVALID)
145 err = wait_event_interruptible(pps->queue, pps->go);
146 else {
147 pr_debug("timeout %lld.%09d\n",
148 (long long) fdata.timeout.sec,
149 fdata.timeout.nsec);
150 ticks = fdata.timeout.sec * HZ;
151 ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ);
152
153 if (ticks != 0) {
154 err = wait_event_interruptible_timeout(
155 pps->queue, pps->go, ticks);
156 if (err == 0)
157 return -ETIMEDOUT;
158 }
159 }
160
161 /* Check for pending signals */
162 if (err == -ERESTARTSYS) {
163 pr_debug("pending signal caught\n");
164 return -EINTR;
165 }
166
167 /* Return the fetched timestamp */
168 spin_lock_irq(&pps->lock);
169
170 fdata.info.assert_sequence = pps->assert_sequence;
171 fdata.info.clear_sequence = pps->clear_sequence;
172 fdata.info.assert_tu = pps->assert_tu;
173 fdata.info.clear_tu = pps->clear_tu;
174 fdata.info.current_mode = pps->current_mode;
175
176 spin_unlock_irq(&pps->lock);
177
178 err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata));
179 if (err)
180 return -EFAULT;
181
182 break;
183
184 default:
185 return -ENOTTY;
186 break;
187 }
188
189 return 0;
190}
191
192static int pps_cdev_open(struct inode *inode, struct file *file)
193{
194 struct pps_device *pps = container_of(inode->i_cdev,
195 struct pps_device, cdev);
196 int found;
197
198 found = pps_get_source(pps->id) != 0;
199 if (!found)
200 return -ENODEV;
201
202 file->private_data = pps;
203
204 return 0;
205}
206
207static int pps_cdev_release(struct inode *inode, struct file *file)
208{
209 struct pps_device *pps = file->private_data;
210
211 /* Free the PPS source and wake up (possible) deregistration */
212 pps_put_source(pps);
213
214 return 0;
215}
216
217/*
218 * Char device stuff
219 */
220
221static const struct file_operations pps_cdev_fops = {
222 .owner = THIS_MODULE,
223 .llseek = no_llseek,
224 .poll = pps_cdev_poll,
225 .fasync = pps_cdev_fasync,
226 .unlocked_ioctl = pps_cdev_ioctl,
227 .open = pps_cdev_open,
228 .release = pps_cdev_release,
229};
230
231int pps_register_cdev(struct pps_device *pps)
232{
233 int err;
234
235 pps->devno = MKDEV(MAJOR(pps_devt), pps->id);
236 cdev_init(&pps->cdev, &pps_cdev_fops);
237 pps->cdev.owner = pps->info.owner;
238
239 err = cdev_add(&pps->cdev, pps->devno, 1);
240 if (err) {
241 printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n",
242 pps->info.name, MAJOR(pps_devt), pps->id);
243 return err;
244 }
245 pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL,
246 "pps%d", pps->id);
247 if (err)
248 goto del_cdev;
249 dev_set_drvdata(pps->dev, pps);
250
251 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
252 MAJOR(pps_devt), pps->id);
253
254 return 0;
255
256del_cdev:
257 cdev_del(&pps->cdev);
258
259 return err;
260}
261
262void pps_unregister_cdev(struct pps_device *pps)
263{
264 device_destroy(pps_class, pps->devno);
265 cdev_del(&pps->cdev);
266}
267
268/*
269 * Module stuff
270 */
271
272static void __exit pps_exit(void)
273{
274 class_destroy(pps_class);
275 unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES);
276}
277
278static int __init pps_init(void)
279{
280 int err;
281
282 pps_class = class_create(THIS_MODULE, "pps");
283 if (!pps_class) {
284 printk(KERN_ERR "pps: failed to allocate class\n");
285 return -ENOMEM;
286 }
287 pps_class->dev_attrs = pps_attrs;
288
289 err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
290 if (err < 0) {
291 printk(KERN_ERR "pps: failed to allocate char device region\n");
292 goto remove_class;
293 }
294
295 pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS);
296 pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti "
297 "<giometti@linux.it>\n", PPS_VERSION);
298
299 return 0;
300
301remove_class:
302 class_destroy(pps_class);
303
304 return err;
305}
306
307subsys_initcall(pps_init);
308module_exit(pps_exit);
309
310MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
311MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION);
312MODULE_LICENSE("GPL");
diff --git a/drivers/pps/sysfs.c b/drivers/pps/sysfs.c
new file mode 100644
index 000000000000..ef0978c71eee
--- /dev/null
+++ b/drivers/pps/sysfs.c
@@ -0,0 +1,98 @@
1/*
2 * PPS sysfs support
3 *
4 *
5 * Copyright (C) 2007-2009 Rodolfo Giometti <giometti@linux.it>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22
23#include <linux/device.h>
24#include <linux/module.h>
25#include <linux/string.h>
26#include <linux/pps_kernel.h>
27
28/*
29 * Attribute functions
30 */
31
32static ssize_t pps_show_assert(struct device *dev,
33 struct device_attribute *attr, char *buf)
34{
35 struct pps_device *pps = dev_get_drvdata(dev);
36
37 if (!(pps->info.mode & PPS_CAPTUREASSERT))
38 return 0;
39
40 return sprintf(buf, "%lld.%09d#%d\n",
41 (long long) pps->assert_tu.sec, pps->assert_tu.nsec,
42 pps->assert_sequence);
43}
44
45static ssize_t pps_show_clear(struct device *dev,
46 struct device_attribute *attr, char *buf)
47{
48 struct pps_device *pps = dev_get_drvdata(dev);
49
50 if (!(pps->info.mode & PPS_CAPTURECLEAR))
51 return 0;
52
53 return sprintf(buf, "%lld.%09d#%d\n",
54 (long long) pps->clear_tu.sec, pps->clear_tu.nsec,
55 pps->clear_sequence);
56}
57
58static ssize_t pps_show_mode(struct device *dev,
59 struct device_attribute *attr, char *buf)
60{
61 struct pps_device *pps = dev_get_drvdata(dev);
62
63 return sprintf(buf, "%4x\n", pps->info.mode);
64}
65
66static ssize_t pps_show_echo(struct device *dev,
67 struct device_attribute *attr, char *buf)
68{
69 struct pps_device *pps = dev_get_drvdata(dev);
70
71 return sprintf(buf, "%d\n", !!pps->info.echo);
72}
73
74static ssize_t pps_show_name(struct device *dev,
75 struct device_attribute *attr, char *buf)
76{
77 struct pps_device *pps = dev_get_drvdata(dev);
78
79 return sprintf(buf, "%s\n", pps->info.name);
80}
81
82static ssize_t pps_show_path(struct device *dev,
83 struct device_attribute *attr, char *buf)
84{
85 struct pps_device *pps = dev_get_drvdata(dev);
86
87 return sprintf(buf, "%s\n", pps->info.path);
88}
89
90struct device_attribute pps_attrs[] = {
91 __ATTR(assert, S_IRUGO, pps_show_assert, NULL),
92 __ATTR(clear, S_IRUGO, pps_show_clear, NULL),
93 __ATTR(mode, S_IRUGO, pps_show_mode, NULL),
94 __ATTR(echo, S_IRUGO, pps_show_echo, NULL),
95 __ATTR(name, S_IRUGO, pps_show_name, NULL),
96 __ATTR(path, S_IRUGO, pps_show_path, NULL),
97 __ATTR_NULL,
98};
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index a2df7030d49d..03f22076381f 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -308,6 +308,7 @@ unifdef-y += pmu.h
308unifdef-y += poll.h 308unifdef-y += poll.h
309unifdef-y += ppp_defs.h 309unifdef-y += ppp_defs.h
310unifdef-y += ppp-comp.h 310unifdef-y += ppp-comp.h
311unifdef-y += pps.h
311unifdef-y += ptrace.h 312unifdef-y += ptrace.h
312unifdef-y += quota.h 313unifdef-y += quota.h
313unifdef-y += random.h 314unifdef-y += random.h
diff --git a/include/linux/pps.h b/include/linux/pps.h
new file mode 100644
index 000000000000..cfe5c7214ec6
--- /dev/null
+++ b/include/linux/pps.h
@@ -0,0 +1,122 @@
1/*
2 * PPS API header
3 *
4 * Copyright (C) 2005-2009 Rodolfo Giometti <giometti@linux.it>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21
22#ifndef _PPS_H_
23#define _PPS_H_
24
25#define PPS_VERSION "5.3.6"
26#define PPS_MAX_SOURCES 16 /* should be enough... */
27
28/* Implementation note: the logical states ``assert'' and ``clear''
29 * are implemented in terms of the chip register, i.e. ``assert''
30 * means the bit is set. */
31
32/*
33 * 3.2 New data structures
34 */
35
36#define PPS_API_VERS_1 1
37#define PPS_API_VERS PPS_API_VERS_1 /* we use API version 1 */
38#define PPS_MAX_NAME_LEN 32
39
40/* 32-bit vs. 64-bit compatibility.
41 *
42 * 0n i386, the alignment of a uint64_t is only 4 bytes, while on most other
43 * architectures it's 8 bytes. On i386, there will be no padding between the
44 * two consecutive 'struct pps_ktime' members of struct pps_kinfo and struct
45 * pps_kparams. But on most platforms there will be padding to ensure correct
46 * alignment.
47 *
48 * The simple fix is probably to add an explicit padding.
49 * [David Woodhouse]
50 */
51struct pps_ktime {
52 __s64 sec;
53 __s32 nsec;
54 __u32 flags;
55};
56#define PPS_TIME_INVALID (1<<0) /* used to specify timeout==NULL */
57
58struct pps_kinfo {
59 __u32 assert_sequence; /* seq. num. of assert event */
60 __u32 clear_sequence; /* seq. num. of clear event */
61 struct pps_ktime assert_tu; /* time of assert event */
62 struct pps_ktime clear_tu; /* time of clear event */
63 int current_mode; /* current mode bits */
64};
65
66struct pps_kparams {
67 int api_version; /* API version # */
68 int mode; /* mode bits */
69 struct pps_ktime assert_off_tu; /* offset compensation for assert */
70 struct pps_ktime clear_off_tu; /* offset compensation for clear */
71};
72
73/*
74 * 3.3 Mode bit definitions
75 */
76
77/* Device/implementation parameters */
78#define PPS_CAPTUREASSERT 0x01 /* capture assert events */
79#define PPS_CAPTURECLEAR 0x02 /* capture clear events */
80#define PPS_CAPTUREBOTH 0x03 /* capture assert and clear events */
81
82#define PPS_OFFSETASSERT 0x10 /* apply compensation for assert ev. */
83#define PPS_OFFSETCLEAR 0x20 /* apply compensation for clear ev. */
84
85#define PPS_CANWAIT 0x100 /* can we wait for an event? */
86#define PPS_CANPOLL 0x200 /* bit reserved for future use */
87
88/* Kernel actions */
89#define PPS_ECHOASSERT 0x40 /* feed back assert event to output */
90#define PPS_ECHOCLEAR 0x80 /* feed back clear event to output */
91
92/* Timestamp formats */
93#define PPS_TSFMT_TSPEC 0x1000 /* select timespec format */
94#define PPS_TSFMT_NTPFP 0x2000 /* select NTP format */
95
96/*
97 * 3.4.4 New functions: disciplining the kernel timebase
98 */
99
100/* Kernel consumers */
101#define PPS_KC_HARDPPS 0 /* hardpps() (or equivalent) */
102#define PPS_KC_HARDPPS_PLL 1 /* hardpps() constrained to
103 use a phase-locked loop */
104#define PPS_KC_HARDPPS_FLL 2 /* hardpps() constrained to
105 use a frequency-locked loop */
106/*
107 * Here begins the implementation-specific part!
108 */
109
110struct pps_fdata {
111 struct pps_kinfo info;
112 struct pps_ktime timeout;
113};
114
115#include <linux/ioctl.h>
116
117#define PPS_GETPARAMS _IOR('p', 0xa1, struct pps_kparams *)
118#define PPS_SETPARAMS _IOW('p', 0xa2, struct pps_kparams *)
119#define PPS_GETCAP _IOR('p', 0xa3, int *)
120#define PPS_FETCH _IOWR('p', 0xa4, struct pps_fdata *)
121
122#endif /* _PPS_H_ */
diff --git a/include/linux/pps_kernel.h b/include/linux/pps_kernel.h
new file mode 100644
index 000000000000..e0a193f830ef
--- /dev/null
+++ b/include/linux/pps_kernel.h
@@ -0,0 +1,89 @@
1/*
2 * PPS API kernel header
3 *
4 * Copyright (C) 2009 Rodolfo Giometti <giometti@linux.it>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include <linux/pps.h>
22
23#include <linux/cdev.h>
24#include <linux/device.h>
25#include <linux/time.h>
26
27/*
28 * Global defines
29 */
30
31/* The specific PPS source info */
32struct pps_source_info {
33 char name[PPS_MAX_NAME_LEN]; /* simbolic name */
34 char path[PPS_MAX_NAME_LEN]; /* path of connected device */
35 int mode; /* PPS's allowed mode */
36
37 void (*echo)(int source, int event, void *data); /* PPS echo function */
38
39 struct module *owner;
40 struct device *dev;
41};
42
43/* The main struct */
44struct pps_device {
45 struct pps_source_info info; /* PSS source info */
46
47 struct pps_kparams params; /* PPS's current params */
48
49 __u32 assert_sequence; /* PPS' assert event seq # */
50 __u32 clear_sequence; /* PPS' clear event seq # */
51 struct pps_ktime assert_tu;
52 struct pps_ktime clear_tu;
53 int current_mode; /* PPS mode at event time */
54
55 int go; /* PPS event is arrived? */
56 wait_queue_head_t queue; /* PPS event queue */
57
58 unsigned int id; /* PPS source unique ID */
59 struct cdev cdev;
60 struct device *dev;
61 int devno;
62 struct fasync_struct *async_queue; /* fasync method */
63 spinlock_t lock;
64
65 atomic_t usage; /* usage count */
66};
67
68/*
69 * Global variables
70 */
71
72extern spinlock_t pps_idr_lock;
73extern struct idr pps_idr;
74extern struct timespec pps_irq_ts[];
75
76extern struct device_attribute pps_attrs[];
77
78/*
79 * Exported functions
80 */
81
82struct pps_device *pps_get_source(int source);
83extern void pps_put_source(struct pps_device *pps);
84extern int pps_register_source(struct pps_source_info *info,
85 int default_params);
86extern void pps_unregister_source(int source);
87extern int pps_register_cdev(struct pps_device *pps);
88extern void pps_unregister_cdev(struct pps_device *pps);
89extern void pps_event(int source, struct pps_ktime *ts, int event, void *data);