aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pps
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/pps
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'drivers/pps')
-rw-r--r--drivers/pps/Kconfig11
-rw-r--r--drivers/pps/Makefile3
-rw-r--r--drivers/pps/clients/Kconfig7
-rw-r--r--drivers/pps/clients/Makefile5
-rw-r--r--drivers/pps/clients/pps-ktimer.c44
-rw-r--r--drivers/pps/clients/pps-ldisc.c59
-rw-r--r--drivers/pps/clients/pps_parport.c258
-rw-r--r--drivers/pps/generators/Kconfig13
-rw-r--r--drivers/pps/generators/Makefile9
-rw-r--r--drivers/pps/generators/pps_gen_parport.c277
-rw-r--r--drivers/pps/kapi.c210
-rw-r--r--drivers/pps/kc.c122
-rw-r--r--drivers/pps/kc.h46
-rw-r--r--drivers/pps/pps.c156
14 files changed, 963 insertions, 257 deletions
diff --git a/drivers/pps/Kconfig b/drivers/pps/Kconfig
index 1afe4e03440f..258ca596e1bc 100644
--- a/drivers/pps/Kconfig
+++ b/drivers/pps/Kconfig
@@ -30,6 +30,17 @@ config PPS_DEBUG
30 messages to the system log. Select this if you are having a 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. 31 problem with PPS support and want to see more of what is going on.
32 32
33config NTP_PPS
34 bool "PPS kernel consumer support"
35 depends on PPS && !NO_HZ
36 help
37 This option adds support for direct in-kernel time
38 synchronization using an external PPS signal.
39
40 It doesn't work on tickless systems at the moment.
41
33source drivers/pps/clients/Kconfig 42source drivers/pps/clients/Kconfig
34 43
44source drivers/pps/generators/Kconfig
45
35endmenu 46endmenu
diff --git a/drivers/pps/Makefile b/drivers/pps/Makefile
index 98960ddd3188..4483eaadaddd 100644
--- a/drivers/pps/Makefile
+++ b/drivers/pps/Makefile
@@ -3,7 +3,8 @@
3# 3#
4 4
5pps_core-y := pps.o kapi.o sysfs.o 5pps_core-y := pps.o kapi.o sysfs.o
6pps_core-$(CONFIG_NTP_PPS) += kc.o
6obj-$(CONFIG_PPS) := pps_core.o 7obj-$(CONFIG_PPS) := pps_core.o
7obj-y += clients/ 8obj-y += clients/ generators/
8 9
9ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG 10ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
diff --git a/drivers/pps/clients/Kconfig b/drivers/pps/clients/Kconfig
index 4e801bd7254f..8520a7f4dd62 100644
--- a/drivers/pps/clients/Kconfig
+++ b/drivers/pps/clients/Kconfig
@@ -22,4 +22,11 @@ config PPS_CLIENT_LDISC
22 If you say yes here you get support for a PPS source connected 22 If you say yes here you get support for a PPS source connected
23 with the CD (Carrier Detect) pin of your serial port. 23 with the CD (Carrier Detect) pin of your serial port.
24 24
25config PPS_CLIENT_PARPORT
26 tristate "Parallel port PPS client"
27 depends on PPS && PARPORT
28 help
29 If you say yes here you get support for a PPS source connected
30 with the interrupt pin of your parallel port.
31
25endif 32endif
diff --git a/drivers/pps/clients/Makefile b/drivers/pps/clients/Makefile
index 812c9b19b430..4feb7e9e71ee 100644
--- a/drivers/pps/clients/Makefile
+++ b/drivers/pps/clients/Makefile
@@ -4,7 +4,6 @@
4 4
5obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o 5obj-$(CONFIG_PPS_CLIENT_KTIMER) += pps-ktimer.o
6obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o 6obj-$(CONFIG_PPS_CLIENT_LDISC) += pps-ldisc.o
7obj-$(CONFIG_PPS_CLIENT_PARPORT) += pps_parport.o
7 8
8ifeq ($(CONFIG_PPS_DEBUG),y) 9ccflags-$(CONFIG_PPS_DEBUG) := -DDEBUG
9EXTRA_CFLAGS += -DDEBUG
10endif
diff --git a/drivers/pps/clients/pps-ktimer.c b/drivers/pps/clients/pps-ktimer.c
index e7ef5b8186d0..82583b0ff82d 100644
--- a/drivers/pps/clients/pps-ktimer.c
+++ b/drivers/pps/clients/pps-ktimer.c
@@ -19,6 +19,7 @@
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */ 20 */
21 21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22 23
23#include <linux/kernel.h> 24#include <linux/kernel.h>
24#include <linux/module.h> 25#include <linux/module.h>
@@ -31,7 +32,7 @@
31 * Global variables 32 * Global variables
32 */ 33 */
33 34
34static int source; 35static struct pps_device *pps;
35static struct timer_list ktimer; 36static struct timer_list ktimer;
36 37
37/* 38/*
@@ -40,19 +41,12 @@ static struct timer_list ktimer;
40 41
41static void pps_ktimer_event(unsigned long ptr) 42static void pps_ktimer_event(unsigned long ptr)
42{ 43{
43 struct timespec __ts; 44 struct pps_event_time ts;
44 struct pps_ktime ts;
45 45
46 /* First of all we get the time stamp... */ 46 /* First of all we get the time stamp... */
47 getnstimeofday(&__ts); 47 pps_get_ts(&ts);
48 48
49 pr_info("PPS event at %lu\n", jiffies); 49 pps_event(pps, &ts, PPS_CAPTUREASSERT, NULL);
50
51 /* ... and translate it to PPS time data struct */
52 ts.sec = __ts.tv_sec;
53 ts.nsec = __ts.tv_nsec;
54
55 pps_event(source, &ts, PPS_CAPTUREASSERT, NULL);
56 50
57 mod_timer(&ktimer, jiffies + HZ); 51 mod_timer(&ktimer, jiffies + HZ);
58} 52}
@@ -61,12 +55,11 @@ static void pps_ktimer_event(unsigned long ptr)
61 * The echo function 55 * The echo function
62 */ 56 */
63 57
64static void pps_ktimer_echo(int source, int event, void *data) 58static void pps_ktimer_echo(struct pps_device *pps, int event, void *data)
65{ 59{
66 pr_info("echo %s %s for source %d\n", 60 dev_info(pps->dev, "echo %s %s\n",
67 event & PPS_CAPTUREASSERT ? "assert" : "", 61 event & PPS_CAPTUREASSERT ? "assert" : "",
68 event & PPS_CAPTURECLEAR ? "clear" : "", 62 event & PPS_CAPTURECLEAR ? "clear" : "");
69 source);
70} 63}
71 64
72/* 65/*
@@ -89,30 +82,27 @@ static struct pps_source_info pps_ktimer_info = {
89 82
90static void __exit pps_ktimer_exit(void) 83static void __exit pps_ktimer_exit(void)
91{ 84{
92 del_timer_sync(&ktimer); 85 dev_info(pps->dev, "ktimer PPS source unregistered\n");
93 pps_unregister_source(source);
94 86
95 pr_info("ktimer PPS source unregistered\n"); 87 del_timer_sync(&ktimer);
88 pps_unregister_source(pps);
96} 89}
97 90
98static int __init pps_ktimer_init(void) 91static int __init pps_ktimer_init(void)
99{ 92{
100 int ret; 93 pps = pps_register_source(&pps_ktimer_info,
101
102 ret = pps_register_source(&pps_ktimer_info,
103 PPS_CAPTUREASSERT | PPS_OFFSETASSERT); 94 PPS_CAPTUREASSERT | PPS_OFFSETASSERT);
104 if (ret < 0) { 95 if (pps == NULL) {
105 printk(KERN_ERR "cannot register ktimer source\n"); 96 pr_err("cannot register PPS source\n");
106 return ret; 97 return -ENOMEM;
107 } 98 }
108 source = ret;
109 99
110 setup_timer(&ktimer, pps_ktimer_event, 0); 100 setup_timer(&ktimer, pps_ktimer_event, 0);
111 mod_timer(&ktimer, jiffies + HZ); 101 mod_timer(&ktimer, jiffies + HZ);
112 102
113 pr_info("ktimer PPS source registered at %d\n", source); 103 dev_info(pps->dev, "ktimer PPS source registered\n");
114 104
115 return 0; 105 return 0;
116} 106}
117 107
118module_init(pps_ktimer_init); 108module_init(pps_ktimer_init);
diff --git a/drivers/pps/clients/pps-ldisc.c b/drivers/pps/clients/pps-ldisc.c
index 8e1932d29fd4..79451f2dea6a 100644
--- a/drivers/pps/clients/pps-ldisc.c
+++ b/drivers/pps/clients/pps-ldisc.c
@@ -19,6 +19,8 @@
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */ 20 */
21 21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
22#include <linux/module.h> 24#include <linux/module.h>
23#include <linux/serial_core.h> 25#include <linux/serial_core.h>
24#include <linux/tty.h> 26#include <linux/tty.h>
@@ -27,30 +29,18 @@
27#define PPS_TTY_MAGIC 0x0001 29#define PPS_TTY_MAGIC 0x0001
28 30
29static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status, 31static void pps_tty_dcd_change(struct tty_struct *tty, unsigned int status,
30 struct timespec *ts) 32 struct pps_event_time *ts)
31{ 33{
32 int id = (long)tty->disc_data; 34 struct pps_device *pps = (struct pps_device *)tty->disc_data;
33 struct timespec __ts; 35
34 struct pps_ktime pps_ts; 36 BUG_ON(pps == NULL);
35
36 /* First of all we get the time stamp... */
37 getnstimeofday(&__ts);
38
39 /* Does caller give us a timestamp? */
40 if (ts) { /* Yes. Let's use it! */
41 pps_ts.sec = ts->tv_sec;
42 pps_ts.nsec = ts->tv_nsec;
43 } else { /* No. Do it ourself! */
44 pps_ts.sec = __ts.tv_sec;
45 pps_ts.nsec = __ts.tv_nsec;
46 }
47 37
48 /* Now do the PPS event report */ 38 /* Now do the PPS event report */
49 pps_event(id, &pps_ts, status ? PPS_CAPTUREASSERT : PPS_CAPTURECLEAR, 39 pps_event(pps, ts, status ? PPS_CAPTUREASSERT :
50 NULL); 40 PPS_CAPTURECLEAR, NULL);
51 41
52 pr_debug("PPS %s at %lu on source #%d\n", 42 dev_dbg(pps->dev, "PPS %s at %lu\n",
53 status ? "assert" : "clear", jiffies, id); 43 status ? "assert" : "clear", jiffies);
54} 44}
55 45
56static int (*alias_n_tty_open)(struct tty_struct *tty); 46static int (*alias_n_tty_open)(struct tty_struct *tty);
@@ -60,6 +50,7 @@ static int pps_tty_open(struct tty_struct *tty)
60 struct pps_source_info info; 50 struct pps_source_info info;
61 struct tty_driver *drv = tty->driver; 51 struct tty_driver *drv = tty->driver;
62 int index = tty->index + drv->name_base; 52 int index = tty->index + drv->name_base;
53 struct pps_device *pps;
63 int ret; 54 int ret;
64 55
65 info.owner = THIS_MODULE; 56 info.owner = THIS_MODULE;
@@ -70,34 +61,42 @@ static int pps_tty_open(struct tty_struct *tty)
70 PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \ 61 PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
71 PPS_CANWAIT | PPS_TSFMT_TSPEC; 62 PPS_CANWAIT | PPS_TSFMT_TSPEC;
72 63
73 ret = pps_register_source(&info, PPS_CAPTUREBOTH | \ 64 pps = pps_register_source(&info, PPS_CAPTUREBOTH | \
74 PPS_OFFSETASSERT | PPS_OFFSETCLEAR); 65 PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
75 if (ret < 0) { 66 if (pps == NULL) {
76 pr_err("cannot register PPS source \"%s\"\n", info.path); 67 pr_err("cannot register PPS source \"%s\"\n", info.path);
77 return ret; 68 return -ENOMEM;
78 } 69 }
79 tty->disc_data = (void *)(long)ret; 70 tty->disc_data = pps;
80 71
81 /* Should open N_TTY ldisc too */ 72 /* Should open N_TTY ldisc too */
82 ret = alias_n_tty_open(tty); 73 ret = alias_n_tty_open(tty);
83 if (ret < 0) 74 if (ret < 0) {
84 pps_unregister_source((long)tty->disc_data); 75 pr_err("cannot open tty ldisc \"%s\"\n", info.path);
76 goto err_unregister;
77 }
85 78
86 pr_info("PPS source #%d \"%s\" added\n", ret, info.path); 79 dev_info(pps->dev, "source \"%s\" added\n", info.path);
87 80
88 return 0; 81 return 0;
82
83err_unregister:
84 tty->disc_data = NULL;
85 pps_unregister_source(pps);
86 return ret;
89} 87}
90 88
91static void (*alias_n_tty_close)(struct tty_struct *tty); 89static void (*alias_n_tty_close)(struct tty_struct *tty);
92 90
93static void pps_tty_close(struct tty_struct *tty) 91static void pps_tty_close(struct tty_struct *tty)
94{ 92{
95 int id = (long)tty->disc_data; 93 struct pps_device *pps = (struct pps_device *)tty->disc_data;
96 94
97 pps_unregister_source(id);
98 alias_n_tty_close(tty); 95 alias_n_tty_close(tty);
99 96
100 pr_info("PPS source #%d removed\n", id); 97 tty->disc_data = NULL;
98 dev_info(pps->dev, "removed\n");
99 pps_unregister_source(pps);
101} 100}
102 101
103static struct tty_ldisc_ops pps_ldisc_ops; 102static struct tty_ldisc_ops pps_ldisc_ops;
diff --git a/drivers/pps/clients/pps_parport.c b/drivers/pps/clients/pps_parport.c
new file mode 100644
index 000000000000..c571d6dd8f61
--- /dev/null
+++ b/drivers/pps/clients/pps_parport.c
@@ -0,0 +1,258 @@
1/*
2 * pps_parport.c -- kernel parallel port PPS client
3 *
4 *
5 * Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su>
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/*
24 * TODO:
25 * implement echo over SEL pin
26 */
27
28#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29
30#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/init.h>
33#include <linux/irqnr.h>
34#include <linux/time.h>
35#include <linux/parport.h>
36#include <linux/pps_kernel.h>
37
38#define DRVDESC "parallel port PPS client"
39
40/* module parameters */
41
42#define CLEAR_WAIT_MAX 100
43#define CLEAR_WAIT_MAX_ERRORS 5
44
45static unsigned int clear_wait = 100;
46MODULE_PARM_DESC(clear_wait,
47 "Maximum number of port reads when polling for signal clear,"
48 " zero turns clear edge capture off entirely");
49module_param(clear_wait, uint, 0);
50
51
52/* internal per port structure */
53struct pps_client_pp {
54 struct pardevice *pardev; /* parport device */
55 struct pps_device *pps; /* PPS device */
56 unsigned int cw; /* port clear timeout */
57 unsigned int cw_err; /* number of timeouts */
58};
59
60static inline int signal_is_set(struct parport *port)
61{
62 return (port->ops->read_status(port) & PARPORT_STATUS_ACK) != 0;
63}
64
65/* parport interrupt handler */
66static void parport_irq(void *handle)
67{
68 struct pps_event_time ts_assert, ts_clear;
69 struct pps_client_pp *dev = handle;
70 struct parport *port = dev->pardev->port;
71 unsigned int i;
72 unsigned long flags;
73
74 /* first of all we get the time stamp... */
75 pps_get_ts(&ts_assert);
76
77 if (dev->cw == 0)
78 /* clear edge capture disabled */
79 goto out_assert;
80
81 /* try capture the clear edge */
82
83 /* We have to disable interrupts here. The idea is to prevent
84 * other interrupts on the same processor to introduce random
85 * lags while polling the port. Reading from IO port is known
86 * to take approximately 1us while other interrupt handlers can
87 * take much more potentially.
88 *
89 * Interrupts won't be disabled for a long time because the
90 * number of polls is limited by clear_wait parameter which is
91 * kept rather low. So it should never be an issue.
92 */
93 local_irq_save(flags);
94 /* check the signal (no signal means the pulse is lost this time) */
95 if (!signal_is_set(port)) {
96 local_irq_restore(flags);
97 dev_err(dev->pps->dev, "lost the signal\n");
98 goto out_assert;
99 }
100
101 /* poll the port until the signal is unset */
102 for (i = dev->cw; i; i--)
103 if (!signal_is_set(port)) {
104 pps_get_ts(&ts_clear);
105 local_irq_restore(flags);
106 dev->cw_err = 0;
107 goto out_both;
108 }
109 local_irq_restore(flags);
110
111 /* timeout */
112 dev->cw_err++;
113 if (dev->cw_err >= CLEAR_WAIT_MAX_ERRORS) {
114 dev_err(dev->pps->dev, "disabled clear edge capture after %d"
115 " timeouts\n", dev->cw_err);
116 dev->cw = 0;
117 dev->cw_err = 0;
118 }
119
120out_assert:
121 /* fire assert event */
122 pps_event(dev->pps, &ts_assert,
123 PPS_CAPTUREASSERT, NULL);
124 return;
125
126out_both:
127 /* fire assert event */
128 pps_event(dev->pps, &ts_assert,
129 PPS_CAPTUREASSERT, NULL);
130 /* fire clear event */
131 pps_event(dev->pps, &ts_clear,
132 PPS_CAPTURECLEAR, NULL);
133 return;
134}
135
136/* the PPS echo function */
137static void pps_echo(struct pps_device *pps, int event, void *data)
138{
139 dev_info(pps->dev, "echo %s %s\n",
140 event & PPS_CAPTUREASSERT ? "assert" : "",
141 event & PPS_CAPTURECLEAR ? "clear" : "");
142}
143
144static void parport_attach(struct parport *port)
145{
146 struct pps_client_pp *device;
147 struct pps_source_info info = {
148 .name = KBUILD_MODNAME,
149 .path = "",
150 .mode = PPS_CAPTUREBOTH | \
151 PPS_OFFSETASSERT | PPS_OFFSETCLEAR | \
152 PPS_ECHOASSERT | PPS_ECHOCLEAR | \
153 PPS_CANWAIT | PPS_TSFMT_TSPEC,
154 .echo = pps_echo,
155 .owner = THIS_MODULE,
156 .dev = NULL
157 };
158
159 device = kzalloc(sizeof(struct pps_client_pp), GFP_KERNEL);
160 if (!device) {
161 pr_err("memory allocation failed, not attaching\n");
162 return;
163 }
164
165 device->pardev = parport_register_device(port, KBUILD_MODNAME,
166 NULL, NULL, parport_irq, PARPORT_FLAG_EXCL, device);
167 if (!device->pardev) {
168 pr_err("couldn't register with %s\n", port->name);
169 goto err_free;
170 }
171
172 if (parport_claim_or_block(device->pardev) < 0) {
173 pr_err("couldn't claim %s\n", port->name);
174 goto err_unregister_dev;
175 }
176
177 device->pps = pps_register_source(&info,
178 PPS_CAPTUREBOTH | PPS_OFFSETASSERT | PPS_OFFSETCLEAR);
179 if (device->pps == NULL) {
180 pr_err("couldn't register PPS source\n");
181 goto err_release_dev;
182 }
183
184 device->cw = clear_wait;
185
186 port->ops->enable_irq(port);
187
188 pr_info("attached to %s\n", port->name);
189
190 return;
191
192err_release_dev:
193 parport_release(device->pardev);
194err_unregister_dev:
195 parport_unregister_device(device->pardev);
196err_free:
197 kfree(device);
198}
199
200static void parport_detach(struct parport *port)
201{
202 struct pardevice *pardev = port->cad;
203 struct pps_client_pp *device;
204
205 /* FIXME: oooh, this is ugly! */
206 if (strcmp(pardev->name, KBUILD_MODNAME))
207 /* not our port */
208 return;
209
210 device = pardev->private;
211
212 port->ops->disable_irq(port);
213 pps_unregister_source(device->pps);
214 parport_release(pardev);
215 parport_unregister_device(pardev);
216 kfree(device);
217}
218
219static struct parport_driver pps_parport_driver = {
220 .name = KBUILD_MODNAME,
221 .attach = parport_attach,
222 .detach = parport_detach,
223};
224
225/* module staff */
226
227static int __init pps_parport_init(void)
228{
229 int ret;
230
231 pr_info(DRVDESC "\n");
232
233 if (clear_wait > CLEAR_WAIT_MAX) {
234 pr_err("clear_wait value should be not greater"
235 " then %d\n", CLEAR_WAIT_MAX);
236 return -EINVAL;
237 }
238
239 ret = parport_register_driver(&pps_parport_driver);
240 if (ret) {
241 pr_err("unable to register with parport\n");
242 return ret;
243 }
244
245 return 0;
246}
247
248static void __exit pps_parport_exit(void)
249{
250 parport_unregister_driver(&pps_parport_driver);
251}
252
253module_init(pps_parport_init);
254module_exit(pps_parport_exit);
255
256MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>");
257MODULE_DESCRIPTION(DRVDESC);
258MODULE_LICENSE("GPL");
diff --git a/drivers/pps/generators/Kconfig b/drivers/pps/generators/Kconfig
new file mode 100644
index 000000000000..e4c4f3dc0728
--- /dev/null
+++ b/drivers/pps/generators/Kconfig
@@ -0,0 +1,13 @@
1#
2# PPS generators configuration
3#
4
5comment "PPS generators support"
6
7config PPS_GENERATOR_PARPORT
8 tristate "Parallel port PPS signal generator"
9 depends on PARPORT && BROKEN
10 help
11 If you say yes here you get support for a PPS signal generator which
12 utilizes STROBE pin of a parallel port to send PPS signals. It uses
13 parport abstraction layer and hrtimers to precisely control the signal.
diff --git a/drivers/pps/generators/Makefile b/drivers/pps/generators/Makefile
new file mode 100644
index 000000000000..303304a6b8ec
--- /dev/null
+++ b/drivers/pps/generators/Makefile
@@ -0,0 +1,9 @@
1#
2# Makefile for PPS generators.
3#
4
5obj-$(CONFIG_PPS_GENERATOR_PARPORT) += pps_gen_parport.o
6
7ifeq ($(CONFIG_PPS_DEBUG),y)
8EXTRA_CFLAGS += -DDEBUG
9endif
diff --git a/drivers/pps/generators/pps_gen_parport.c b/drivers/pps/generators/pps_gen_parport.c
new file mode 100644
index 000000000000..dcd39fba6ddd
--- /dev/null
+++ b/drivers/pps/generators/pps_gen_parport.c
@@ -0,0 +1,277 @@
1/*
2 * pps_gen_parport.c -- kernel parallel port PPS signal generator
3 *
4 *
5 * Copyright (C) 2009 Alexander Gordeev <lasaine@lvk.cs.msu.su>
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/*
24 * TODO:
25 * fix issues when realtime clock is adjusted in a leap
26 */
27
28#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29
30#include <linux/kernel.h>
31#include <linux/module.h>
32#include <linux/init.h>
33#include <linux/time.h>
34#include <linux/hrtimer.h>
35#include <linux/parport.h>
36
37#define DRVDESC "parallel port PPS signal generator"
38
39#define SIGNAL 0
40#define NO_SIGNAL PARPORT_CONTROL_STROBE
41
42/* module parameters */
43
44#define SEND_DELAY_MAX 100000
45
46static unsigned int send_delay = 30000;
47MODULE_PARM_DESC(delay,
48 "Delay between setting and dropping the signal (ns)");
49module_param_named(delay, send_delay, uint, 0);
50
51
52#define SAFETY_INTERVAL 3000 /* set the hrtimer earlier for safety (ns) */
53
54/* internal per port structure */
55struct pps_generator_pp {
56 struct pardevice *pardev; /* parport device */
57 struct hrtimer timer;
58 long port_write_time; /* calibrated port write time (ns) */
59};
60
61static struct pps_generator_pp device = {
62 .pardev = NULL,
63};
64
65static int attached;
66
67/* calibrated time between a hrtimer event and the reaction */
68static long hrtimer_error = SAFETY_INTERVAL;
69
70/* the kernel hrtimer event */
71static enum hrtimer_restart hrtimer_event(struct hrtimer *timer)
72{
73 struct timespec expire_time, ts1, ts2, ts3, dts;
74 struct pps_generator_pp *dev;
75 struct parport *port;
76 long lim, delta;
77 unsigned long flags;
78
79 /* We have to disable interrupts here. The idea is to prevent
80 * other interrupts on the same processor to introduce random
81 * lags while polling the clock. getnstimeofday() takes <1us on
82 * most machines while other interrupt handlers can take much
83 * more potentially.
84 *
85 * NB: approx time with blocked interrupts =
86 * send_delay + 3 * SAFETY_INTERVAL
87 */
88 local_irq_save(flags);
89
90 /* first of all we get the time stamp... */
91 getnstimeofday(&ts1);
92 expire_time = ktime_to_timespec(hrtimer_get_softexpires(timer));
93 dev = container_of(timer, struct pps_generator_pp, timer);
94 lim = NSEC_PER_SEC - send_delay - dev->port_write_time;
95
96 /* check if we are late */
97 if (expire_time.tv_sec != ts1.tv_sec || ts1.tv_nsec > lim) {
98 local_irq_restore(flags);
99 pr_err("we are late this time %ld.%09ld\n",
100 ts1.tv_sec, ts1.tv_nsec);
101 goto done;
102 }
103
104 /* busy loop until the time is right for an assert edge */
105 do {
106 getnstimeofday(&ts2);
107 } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim);
108
109 /* set the signal */
110 port = dev->pardev->port;
111 port->ops->write_control(port, SIGNAL);
112
113 /* busy loop until the time is right for a clear edge */
114 lim = NSEC_PER_SEC - dev->port_write_time;
115 do {
116 getnstimeofday(&ts2);
117 } while (expire_time.tv_sec == ts2.tv_sec && ts2.tv_nsec < lim);
118
119 /* unset the signal */
120 port->ops->write_control(port, NO_SIGNAL);
121
122 getnstimeofday(&ts3);
123
124 local_irq_restore(flags);
125
126 /* update calibrated port write time */
127 dts = timespec_sub(ts3, ts2);
128 dev->port_write_time =
129 (dev->port_write_time + timespec_to_ns(&dts)) >> 1;
130
131done:
132 /* update calibrated hrtimer error */
133 dts = timespec_sub(ts1, expire_time);
134 delta = timespec_to_ns(&dts);
135 /* If the new error value is bigger then the old, use the new
136 * value, if not then slowly move towards the new value. This
137 * way it should be safe in bad conditions and efficient in
138 * good conditions.
139 */
140 if (delta >= hrtimer_error)
141 hrtimer_error = delta;
142 else
143 hrtimer_error = (3 * hrtimer_error + delta) >> 2;
144
145 /* update the hrtimer expire time */
146 hrtimer_set_expires(timer,
147 ktime_set(expire_time.tv_sec + 1,
148 NSEC_PER_SEC - (send_delay +
149 dev->port_write_time + SAFETY_INTERVAL +
150 2 * hrtimer_error)));
151
152 return HRTIMER_RESTART;
153}
154
155/* calibrate port write time */
156#define PORT_NTESTS_SHIFT 5
157static void calibrate_port(struct pps_generator_pp *dev)
158{
159 struct parport *port = dev->pardev->port;
160 int i;
161 long acc = 0;
162
163 for (i = 0; i < (1 << PORT_NTESTS_SHIFT); i++) {
164 struct timespec a, b;
165 unsigned long irq_flags;
166
167 local_irq_save(irq_flags);
168 getnstimeofday(&a);
169 port->ops->write_control(port, NO_SIGNAL);
170 getnstimeofday(&b);
171 local_irq_restore(irq_flags);
172
173 b = timespec_sub(b, a);
174 acc += timespec_to_ns(&b);
175 }
176
177 dev->port_write_time = acc >> PORT_NTESTS_SHIFT;
178 pr_info("port write takes %ldns\n", dev->port_write_time);
179}
180
181static inline ktime_t next_intr_time(struct pps_generator_pp *dev)
182{
183 struct timespec ts;
184
185 getnstimeofday(&ts);
186
187 return ktime_set(ts.tv_sec +
188 ((ts.tv_nsec > 990 * NSEC_PER_MSEC) ? 1 : 0),
189 NSEC_PER_SEC - (send_delay +
190 dev->port_write_time + 3 * SAFETY_INTERVAL));
191}
192
193static void parport_attach(struct parport *port)
194{
195 if (attached) {
196 /* we already have a port */
197 return;
198 }
199
200 device.pardev = parport_register_device(port, KBUILD_MODNAME,
201 NULL, NULL, NULL, PARPORT_FLAG_EXCL, &device);
202 if (!device.pardev) {
203 pr_err("couldn't register with %s\n", port->name);
204 return;
205 }
206
207 if (parport_claim_or_block(device.pardev) < 0) {
208 pr_err("couldn't claim %s\n", port->name);
209 goto err_unregister_dev;
210 }
211
212 pr_info("attached to %s\n", port->name);
213 attached = 1;
214
215 calibrate_port(&device);
216
217 hrtimer_init(&device.timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
218 device.timer.function = hrtimer_event;
219 hrtimer_start(&device.timer, next_intr_time(&device), HRTIMER_MODE_ABS);
220
221 return;
222
223err_unregister_dev:
224 parport_unregister_device(device.pardev);
225}
226
227static void parport_detach(struct parport *port)
228{
229 if (port->cad != device.pardev)
230 return; /* not our port */
231
232 hrtimer_cancel(&device.timer);
233 parport_release(device.pardev);
234 parport_unregister_device(device.pardev);
235}
236
237static struct parport_driver pps_gen_parport_driver = {
238 .name = KBUILD_MODNAME,
239 .attach = parport_attach,
240 .detach = parport_detach,
241};
242
243/* module staff */
244
245static int __init pps_gen_parport_init(void)
246{
247 int ret;
248
249 pr_info(DRVDESC "\n");
250
251 if (send_delay > SEND_DELAY_MAX) {
252 pr_err("delay value should be not greater"
253 " then %d\n", SEND_DELAY_MAX);
254 return -EINVAL;
255 }
256
257 ret = parport_register_driver(&pps_gen_parport_driver);
258 if (ret) {
259 pr_err("unable to register with parport\n");
260 return ret;
261 }
262
263 return 0;
264}
265
266static void __exit pps_gen_parport_exit(void)
267{
268 parport_unregister_driver(&pps_gen_parport_driver);
269 pr_info("hrtimer avg error is %ldns\n", hrtimer_error);
270}
271
272module_init(pps_gen_parport_init);
273module_exit(pps_gen_parport_exit);
274
275MODULE_AUTHOR("Alexander Gordeev <lasaine@lvk.cs.msu.su>");
276MODULE_DESCRIPTION(DRVDESC);
277MODULE_LICENSE("GPL");
diff --git a/drivers/pps/kapi.c b/drivers/pps/kapi.c
index 1aa02db3ff4e..a4e8eb9fece6 100644
--- a/drivers/pps/kapi.c
+++ b/drivers/pps/kapi.c
@@ -19,24 +19,20 @@
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */ 20 */
21 21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22 23
23#include <linux/kernel.h> 24#include <linux/kernel.h>
24#include <linux/module.h> 25#include <linux/module.h>
25#include <linux/init.h> 26#include <linux/init.h>
26#include <linux/sched.h> 27#include <linux/sched.h>
27#include <linux/time.h> 28#include <linux/time.h>
29#include <linux/timex.h>
28#include <linux/spinlock.h> 30#include <linux/spinlock.h>
29#include <linux/idr.h>
30#include <linux/fs.h> 31#include <linux/fs.h>
31#include <linux/pps_kernel.h> 32#include <linux/pps_kernel.h>
32#include <linux/slab.h> 33#include <linux/slab.h>
33 34
34/* 35#include "kc.h"
35 * Global variables
36 */
37
38DEFINE_SPINLOCK(pps_idr_lock);
39DEFINE_IDR(pps_idr);
40 36
41/* 37/*
42 * Local functions 38 * Local functions
@@ -60,60 +56,6 @@ static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
60 * Exported functions 56 * Exported functions
61 */ 57 */
62 58
63/* pps_get_source - find a PPS source
64 * @source: the PPS source ID.
65 *
66 * This function is used to find an already registered PPS source into the
67 * system.
68 *
69 * The function returns NULL if found nothing, otherwise it returns a pointer
70 * to the PPS source data struct (the refcounter is incremented by 1).
71 */
72
73struct pps_device *pps_get_source(int source)
74{
75 struct pps_device *pps;
76 unsigned long flags;
77
78 spin_lock_irqsave(&pps_idr_lock, flags);
79
80 pps = idr_find(&pps_idr, source);
81 if (pps != NULL)
82 atomic_inc(&pps->usage);
83
84 spin_unlock_irqrestore(&pps_idr_lock, flags);
85
86 return pps;
87}
88
89/* pps_put_source - free the PPS source data
90 * @pps: a pointer to the PPS source.
91 *
92 * This function is used to free a PPS data struct if its refcount is 0.
93 */
94
95void pps_put_source(struct pps_device *pps)
96{
97 unsigned long flags;
98
99 spin_lock_irqsave(&pps_idr_lock, flags);
100 BUG_ON(atomic_read(&pps->usage) == 0);
101
102 if (!atomic_dec_and_test(&pps->usage)) {
103 pps = NULL;
104 goto exit;
105 }
106
107 /* No more reference to the PPS source. We can safely remove the
108 * PPS data struct.
109 */
110 idr_remove(&pps_idr, pps->id);
111
112exit:
113 spin_unlock_irqrestore(&pps_idr_lock, flags);
114 kfree(pps);
115}
116
117/* pps_register_source - add a PPS source in the system 59/* pps_register_source - add a PPS source in the system
118 * @info: the PPS info struct 60 * @info: the PPS info struct
119 * @default_params: the default PPS parameters of the new source 61 * @default_params: the default PPS parameters of the new source
@@ -122,31 +64,31 @@ exit:
122 * source is described by info's fields and it will have, as default PPS 64 * source is described by info's fields and it will have, as default PPS
123 * parameters, the ones specified into default_params. 65 * parameters, the ones specified into default_params.
124 * 66 *
125 * The function returns, in case of success, the PPS source ID. 67 * The function returns, in case of success, the PPS device. Otherwise NULL.
126 */ 68 */
127 69
128int pps_register_source(struct pps_source_info *info, int default_params) 70struct pps_device *pps_register_source(struct pps_source_info *info,
71 int default_params)
129{ 72{
130 struct pps_device *pps; 73 struct pps_device *pps;
131 int id;
132 int err; 74 int err;
133 75
134 /* Sanity checks */ 76 /* Sanity checks */
135 if ((info->mode & default_params) != default_params) { 77 if ((info->mode & default_params) != default_params) {
136 printk(KERN_ERR "pps: %s: unsupported default parameters\n", 78 pr_err("%s: unsupported default parameters\n",
137 info->name); 79 info->name);
138 err = -EINVAL; 80 err = -EINVAL;
139 goto pps_register_source_exit; 81 goto pps_register_source_exit;
140 } 82 }
141 if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 && 83 if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
142 info->echo == NULL) { 84 info->echo == NULL) {
143 printk(KERN_ERR "pps: %s: echo function is not defined\n", 85 pr_err("%s: echo function is not defined\n",
144 info->name); 86 info->name);
145 err = -EINVAL; 87 err = -EINVAL;
146 goto pps_register_source_exit; 88 goto pps_register_source_exit;
147 } 89 }
148 if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { 90 if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
149 printk(KERN_ERR "pps: %s: unspecified time format\n", 91 pr_err("%s: unspecified time format\n",
150 info->name); 92 info->name);
151 err = -EINVAL; 93 err = -EINVAL;
152 goto pps_register_source_exit; 94 goto pps_register_source_exit;
@@ -168,94 +110,48 @@ int pps_register_source(struct pps_source_info *info, int default_params)
168 110
169 init_waitqueue_head(&pps->queue); 111 init_waitqueue_head(&pps->queue);
170 spin_lock_init(&pps->lock); 112 spin_lock_init(&pps->lock);
171 atomic_set(&pps->usage, 1);
172
173 /* Get new ID for the new PPS source */
174 if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
175 err = -ENOMEM;
176 goto kfree_pps;
177 }
178
179 spin_lock_irq(&pps_idr_lock);
180
181 /* Now really allocate the PPS source.
182 * After idr_get_new() calling the new source will be freely available
183 * into the kernel.
184 */
185 err = idr_get_new(&pps_idr, pps, &id);
186 if (err < 0) {
187 spin_unlock_irq(&pps_idr_lock);
188 goto kfree_pps;
189 }
190
191 id = id & MAX_ID_MASK;
192 if (id >= PPS_MAX_SOURCES) {
193 spin_unlock_irq(&pps_idr_lock);
194
195 printk(KERN_ERR "pps: %s: too many PPS sources in the system\n",
196 info->name);
197 err = -EBUSY;
198 goto free_idr;
199 }
200 pps->id = id;
201
202 spin_unlock_irq(&pps_idr_lock);
203 113
204 /* Create the char device */ 114 /* Create the char device */
205 err = pps_register_cdev(pps); 115 err = pps_register_cdev(pps);
206 if (err < 0) { 116 if (err < 0) {
207 printk(KERN_ERR "pps: %s: unable to create char device\n", 117 pr_err("%s: unable to create char device\n",
208 info->name); 118 info->name);
209 goto free_idr; 119 goto kfree_pps;
210 } 120 }
211 121
212 pr_info("new PPS source %s at ID %d\n", info->name, id); 122 dev_info(pps->dev, "new PPS source %s\n", info->name);
213 123
214 return id; 124 return pps;
215
216free_idr:
217 spin_lock_irq(&pps_idr_lock);
218 idr_remove(&pps_idr, id);
219 spin_unlock_irq(&pps_idr_lock);
220 125
221kfree_pps: 126kfree_pps:
222 kfree(pps); 127 kfree(pps);
223 128
224pps_register_source_exit: 129pps_register_source_exit:
225 printk(KERN_ERR "pps: %s: unable to register source\n", info->name); 130 pr_err("%s: unable to register source\n", info->name);
226 131
227 return err; 132 return NULL;
228} 133}
229EXPORT_SYMBOL(pps_register_source); 134EXPORT_SYMBOL(pps_register_source);
230 135
231/* pps_unregister_source - remove a PPS source from the system 136/* pps_unregister_source - remove a PPS source from the system
232 * @source: the PPS source ID 137 * @pps: the PPS source
233 * 138 *
234 * This function is used to remove a previously registered PPS source from 139 * This function is used to remove a previously registered PPS source from
235 * the system. 140 * the system.
236 */ 141 */
237 142
238void pps_unregister_source(int source) 143void pps_unregister_source(struct pps_device *pps)
239{ 144{
240 struct pps_device *pps; 145 pps_kc_remove(pps);
241
242 spin_lock_irq(&pps_idr_lock);
243 pps = idr_find(&pps_idr, source);
244
245 if (!pps) {
246 BUG();
247 spin_unlock_irq(&pps_idr_lock);
248 return;
249 }
250 spin_unlock_irq(&pps_idr_lock);
251
252 pps_unregister_cdev(pps); 146 pps_unregister_cdev(pps);
253 pps_put_source(pps); 147
148 /* don't have to kfree(pps) here because it will be done on
149 * device destruction */
254} 150}
255EXPORT_SYMBOL(pps_unregister_source); 151EXPORT_SYMBOL(pps_unregister_source);
256 152
257/* pps_event - register a PPS event into the system 153/* pps_event - register a PPS event into the system
258 * @source: the PPS source ID 154 * @pps: the PPS device
259 * @ts: the event timestamp 155 * @ts: the event timestamp
260 * @event: the event type 156 * @event: the event type
261 * @data: userdef pointer 157 * @data: userdef pointer
@@ -263,78 +159,72 @@ EXPORT_SYMBOL(pps_unregister_source);
263 * This function is used by each PPS client in order to register a new 159 * This function is used by each PPS client in order to register a new
264 * PPS event into the system (it's usually called inside an IRQ handler). 160 * PPS event into the system (it's usually called inside an IRQ handler).
265 * 161 *
266 * If an echo function is associated with the PPS source it will be called 162 * If an echo function is associated with the PPS device it will be called
267 * as: 163 * as:
268 * pps->info.echo(source, event, data); 164 * pps->info.echo(pps, event, data);
269 */ 165 */
270 166void pps_event(struct pps_device *pps, struct pps_event_time *ts, int event,
271void pps_event(int source, struct pps_ktime *ts, int event, void *data) 167 void *data)
272{ 168{
273 struct pps_device *pps;
274 unsigned long flags; 169 unsigned long flags;
275 int captured = 0; 170 int captured = 0;
171 struct pps_ktime ts_real = { .sec = 0, .nsec = 0, .flags = 0 };
276 172
277 if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) { 173 /* check event type */
278 printk(KERN_ERR "pps: unknown event (%x) for source %d\n", 174 BUG_ON((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0);
279 event, source);
280 return;
281 }
282 175
283 pps = pps_get_source(source); 176 dev_dbg(pps->dev, "PPS event at %ld.%09ld\n",
284 if (!pps) 177 ts->ts_real.tv_sec, ts->ts_real.tv_nsec);
285 return;
286 178
287 pr_debug("PPS event on source %d at %llu.%06u\n", 179 timespec_to_pps_ktime(&ts_real, ts->ts_real);
288 pps->id, (unsigned long long) ts->sec, ts->nsec);
289 180
290 spin_lock_irqsave(&pps->lock, flags); 181 spin_lock_irqsave(&pps->lock, flags);
291 182
292 /* Must call the echo function? */ 183 /* Must call the echo function? */
293 if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR))) 184 if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
294 pps->info.echo(source, event, data); 185 pps->info.echo(pps, event, data);
295 186
296 /* Check the event */ 187 /* Check the event */
297 pps->current_mode = pps->params.mode; 188 pps->current_mode = pps->params.mode;
298 if ((event & PPS_CAPTUREASSERT) & 189 if (event & pps->params.mode & PPS_CAPTUREASSERT) {
299 (pps->params.mode & PPS_CAPTUREASSERT)) {
300 /* We have to add an offset? */ 190 /* We have to add an offset? */
301 if (pps->params.mode & PPS_OFFSETASSERT) 191 if (pps->params.mode & PPS_OFFSETASSERT)
302 pps_add_offset(ts, &pps->params.assert_off_tu); 192 pps_add_offset(&ts_real,
193 &pps->params.assert_off_tu);
303 194
304 /* Save the time stamp */ 195 /* Save the time stamp */
305 pps->assert_tu = *ts; 196 pps->assert_tu = ts_real;
306 pps->assert_sequence++; 197 pps->assert_sequence++;
307 pr_debug("capture assert seq #%u for source %d\n", 198 dev_dbg(pps->dev, "capture assert seq #%u\n",
308 pps->assert_sequence, source); 199 pps->assert_sequence);
309 200
310 captured = ~0; 201 captured = ~0;
311 } 202 }
312 if ((event & PPS_CAPTURECLEAR) & 203 if (event & pps->params.mode & PPS_CAPTURECLEAR) {
313 (pps->params.mode & PPS_CAPTURECLEAR)) {
314 /* We have to add an offset? */ 204 /* We have to add an offset? */
315 if (pps->params.mode & PPS_OFFSETCLEAR) 205 if (pps->params.mode & PPS_OFFSETCLEAR)
316 pps_add_offset(ts, &pps->params.clear_off_tu); 206 pps_add_offset(&ts_real,
207 &pps->params.clear_off_tu);
317 208
318 /* Save the time stamp */ 209 /* Save the time stamp */
319 pps->clear_tu = *ts; 210 pps->clear_tu = ts_real;
320 pps->clear_sequence++; 211 pps->clear_sequence++;
321 pr_debug("capture clear seq #%u for source %d\n", 212 dev_dbg(pps->dev, "capture clear seq #%u\n",
322 pps->clear_sequence, source); 213 pps->clear_sequence);
323 214
324 captured = ~0; 215 captured = ~0;
325 } 216 }
326 217
327 /* Wake up iif captured somthing */ 218 pps_kc_event(pps, ts, event);
219
220 /* Wake up if captured something */
328 if (captured) { 221 if (captured) {
329 pps->go = ~0; 222 pps->last_ev++;
330 wake_up_interruptible(&pps->queue); 223 wake_up_interruptible_all(&pps->queue);
331 224
332 kill_fasync(&pps->async_queue, SIGIO, POLL_IN); 225 kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
333 } 226 }
334 227
335 spin_unlock_irqrestore(&pps->lock, flags); 228 spin_unlock_irqrestore(&pps->lock, flags);
336
337 /* Now we can release the PPS source for (possible) deregistration */
338 pps_put_source(pps);
339} 229}
340EXPORT_SYMBOL(pps_event); 230EXPORT_SYMBOL(pps_event);
diff --git a/drivers/pps/kc.c b/drivers/pps/kc.c
new file mode 100644
index 000000000000..079e930b1938
--- /dev/null
+++ b/drivers/pps/kc.c
@@ -0,0 +1,122 @@
1/*
2 * PPS kernel consumer API
3 *
4 * Copyright (C) 2009-2010 Alexander Gordeev <lasaine@lvk.cs.msu.su>
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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/device.h>
26#include <linux/init.h>
27#include <linux/spinlock.h>
28#include <linux/pps_kernel.h>
29
30#include "kc.h"
31
32/*
33 * Global variables
34 */
35
36/* state variables to bind kernel consumer */
37DEFINE_SPINLOCK(pps_kc_hardpps_lock);
38/* PPS API (RFC 2783): current source and mode for kernel consumer */
39struct pps_device *pps_kc_hardpps_dev; /* unique pointer to device */
40int pps_kc_hardpps_mode; /* mode bits for kernel consumer */
41
42/* pps_kc_bind - control PPS kernel consumer binding
43 * @pps: the PPS source
44 * @bind_args: kernel consumer bind parameters
45 *
46 * This function is used to bind or unbind PPS kernel consumer according to
47 * supplied parameters. Should not be called in interrupt context.
48 */
49int pps_kc_bind(struct pps_device *pps, struct pps_bind_args *bind_args)
50{
51 /* Check if another consumer is already bound */
52 spin_lock_irq(&pps_kc_hardpps_lock);
53
54 if (bind_args->edge == 0)
55 if (pps_kc_hardpps_dev == pps) {
56 pps_kc_hardpps_mode = 0;
57 pps_kc_hardpps_dev = NULL;
58 spin_unlock_irq(&pps_kc_hardpps_lock);
59 dev_info(pps->dev, "unbound kernel"
60 " consumer\n");
61 } else {
62 spin_unlock_irq(&pps_kc_hardpps_lock);
63 dev_err(pps->dev, "selected kernel consumer"
64 " is not bound\n");
65 return -EINVAL;
66 }
67 else
68 if (pps_kc_hardpps_dev == NULL ||
69 pps_kc_hardpps_dev == pps) {
70 pps_kc_hardpps_mode = bind_args->edge;
71 pps_kc_hardpps_dev = pps;
72 spin_unlock_irq(&pps_kc_hardpps_lock);
73 dev_info(pps->dev, "bound kernel consumer: "
74 "edge=0x%x\n", bind_args->edge);
75 } else {
76 spin_unlock_irq(&pps_kc_hardpps_lock);
77 dev_err(pps->dev, "another kernel consumer"
78 " is already bound\n");
79 return -EINVAL;
80 }
81
82 return 0;
83}
84
85/* pps_kc_remove - unbind kernel consumer on PPS source removal
86 * @pps: the PPS source
87 *
88 * This function is used to disable kernel consumer on PPS source removal
89 * if this source was bound to PPS kernel consumer. Can be called on any
90 * source safely. Should not be called in interrupt context.
91 */
92void pps_kc_remove(struct pps_device *pps)
93{
94 spin_lock_irq(&pps_kc_hardpps_lock);
95 if (pps == pps_kc_hardpps_dev) {
96 pps_kc_hardpps_mode = 0;
97 pps_kc_hardpps_dev = NULL;
98 spin_unlock_irq(&pps_kc_hardpps_lock);
99 dev_info(pps->dev, "unbound kernel consumer"
100 " on device removal\n");
101 } else
102 spin_unlock_irq(&pps_kc_hardpps_lock);
103}
104
105/* pps_kc_event - call hardpps() on PPS event
106 * @pps: the PPS source
107 * @ts: PPS event timestamp
108 * @event: PPS event edge
109 *
110 * This function calls hardpps() when an event from bound PPS source occurs.
111 */
112void pps_kc_event(struct pps_device *pps, struct pps_event_time *ts,
113 int event)
114{
115 unsigned long flags;
116
117 /* Pass some events to kernel consumer if activated */
118 spin_lock_irqsave(&pps_kc_hardpps_lock, flags);
119 if (pps == pps_kc_hardpps_dev && event & pps_kc_hardpps_mode)
120 hardpps(&ts->ts_real, &ts->ts_raw);
121 spin_unlock_irqrestore(&pps_kc_hardpps_lock, flags);
122}
diff --git a/drivers/pps/kc.h b/drivers/pps/kc.h
new file mode 100644
index 000000000000..d296fcd0a175
--- /dev/null
+++ b/drivers/pps/kc.h
@@ -0,0 +1,46 @@
1/*
2 * PPS kernel consumer API header
3 *
4 * Copyright (C) 2009-2010 Alexander Gordeev <lasaine@lvk.cs.msu.su>
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#ifndef LINUX_PPS_KC_H
22#define LINUX_PPS_KC_H
23
24#include <linux/errno.h>
25#include <linux/pps_kernel.h>
26
27#ifdef CONFIG_NTP_PPS
28
29extern int pps_kc_bind(struct pps_device *pps,
30 struct pps_bind_args *bind_args);
31extern void pps_kc_remove(struct pps_device *pps);
32extern void pps_kc_event(struct pps_device *pps,
33 struct pps_event_time *ts, int event);
34
35
36#else /* CONFIG_NTP_PPS */
37
38static inline int pps_kc_bind(struct pps_device *pps,
39 struct pps_bind_args *bind_args) { return -EOPNOTSUPP; }
40static inline void pps_kc_remove(struct pps_device *pps) {}
41static inline void pps_kc_event(struct pps_device *pps,
42 struct pps_event_time *ts, int event) {}
43
44#endif /* CONFIG_NTP_PPS */
45
46#endif /* LINUX_PPS_KC_H */
diff --git a/drivers/pps/pps.c b/drivers/pps/pps.c
index ca5183bdad85..2baadd21b7a6 100644
--- a/drivers/pps/pps.c
+++ b/drivers/pps/pps.c
@@ -19,6 +19,7 @@
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */ 20 */
21 21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
22 23
23#include <linux/kernel.h> 24#include <linux/kernel.h>
24#include <linux/module.h> 25#include <linux/module.h>
@@ -26,9 +27,13 @@
26#include <linux/sched.h> 27#include <linux/sched.h>
27#include <linux/uaccess.h> 28#include <linux/uaccess.h>
28#include <linux/idr.h> 29#include <linux/idr.h>
30#include <linux/mutex.h>
29#include <linux/cdev.h> 31#include <linux/cdev.h>
30#include <linux/poll.h> 32#include <linux/poll.h>
31#include <linux/pps_kernel.h> 33#include <linux/pps_kernel.h>
34#include <linux/slab.h>
35
36#include "kc.h"
32 37
33/* 38/*
34 * Local variables 39 * Local variables
@@ -37,6 +42,9 @@
37static dev_t pps_devt; 42static dev_t pps_devt;
38static struct class *pps_class; 43static struct class *pps_class;
39 44
45static DEFINE_MUTEX(pps_idr_lock);
46static DEFINE_IDR(pps_idr);
47
40/* 48/*
41 * Char device methods 49 * Char device methods
42 */ 50 */
@@ -61,15 +69,13 @@ static long pps_cdev_ioctl(struct file *file,
61{ 69{
62 struct pps_device *pps = file->private_data; 70 struct pps_device *pps = file->private_data;
63 struct pps_kparams params; 71 struct pps_kparams params;
64 struct pps_fdata fdata;
65 unsigned long ticks;
66 void __user *uarg = (void __user *) arg; 72 void __user *uarg = (void __user *) arg;
67 int __user *iuarg = (int __user *) arg; 73 int __user *iuarg = (int __user *) arg;
68 int err; 74 int err;
69 75
70 switch (cmd) { 76 switch (cmd) {
71 case PPS_GETPARAMS: 77 case PPS_GETPARAMS:
72 pr_debug("PPS_GETPARAMS: source %d\n", pps->id); 78 dev_dbg(pps->dev, "PPS_GETPARAMS\n");
73 79
74 spin_lock_irq(&pps->lock); 80 spin_lock_irq(&pps->lock);
75 81
@@ -85,7 +91,7 @@ static long pps_cdev_ioctl(struct file *file,
85 break; 91 break;
86 92
87 case PPS_SETPARAMS: 93 case PPS_SETPARAMS:
88 pr_debug("PPS_SETPARAMS: source %d\n", pps->id); 94 dev_dbg(pps->dev, "PPS_SETPARAMS\n");
89 95
90 /* Check the capabilities */ 96 /* Check the capabilities */
91 if (!capable(CAP_SYS_TIME)) 97 if (!capable(CAP_SYS_TIME))
@@ -95,14 +101,14 @@ static long pps_cdev_ioctl(struct file *file,
95 if (err) 101 if (err)
96 return -EFAULT; 102 return -EFAULT;
97 if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { 103 if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
98 pr_debug("capture mode unspecified (%x)\n", 104 dev_dbg(pps->dev, "capture mode unspecified (%x)\n",
99 params.mode); 105 params.mode);
100 return -EINVAL; 106 return -EINVAL;
101 } 107 }
102 108
103 /* Check for supported capabilities */ 109 /* Check for supported capabilities */
104 if ((params.mode & ~pps->info.mode) != 0) { 110 if ((params.mode & ~pps->info.mode) != 0) {
105 pr_debug("unsupported capabilities (%x)\n", 111 dev_dbg(pps->dev, "unsupported capabilities (%x)\n",
106 params.mode); 112 params.mode);
107 return -EINVAL; 113 return -EINVAL;
108 } 114 }
@@ -115,7 +121,7 @@ static long pps_cdev_ioctl(struct file *file,
115 /* Restore the read only parameters */ 121 /* Restore the read only parameters */
116 if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { 122 if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
117 /* section 3.3 of RFC 2783 interpreted */ 123 /* section 3.3 of RFC 2783 interpreted */
118 pr_debug("time format unspecified (%x)\n", 124 dev_dbg(pps->dev, "time format unspecified (%x)\n",
119 params.mode); 125 params.mode);
120 pps->params.mode |= PPS_TSFMT_TSPEC; 126 pps->params.mode |= PPS_TSFMT_TSPEC;
121 } 127 }
@@ -128,7 +134,7 @@ static long pps_cdev_ioctl(struct file *file,
128 break; 134 break;
129 135
130 case PPS_GETCAP: 136 case PPS_GETCAP:
131 pr_debug("PPS_GETCAP: source %d\n", pps->id); 137 dev_dbg(pps->dev, "PPS_GETCAP\n");
132 138
133 err = put_user(pps->info.mode, iuarg); 139 err = put_user(pps->info.mode, iuarg);
134 if (err) 140 if (err)
@@ -136,20 +142,26 @@ static long pps_cdev_ioctl(struct file *file,
136 142
137 break; 143 break;
138 144
139 case PPS_FETCH: 145 case PPS_FETCH: {
140 pr_debug("PPS_FETCH: source %d\n", pps->id); 146 struct pps_fdata fdata;
147 unsigned int ev;
148
149 dev_dbg(pps->dev, "PPS_FETCH\n");
141 150
142 err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata)); 151 err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
143 if (err) 152 if (err)
144 return -EFAULT; 153 return -EFAULT;
145 154
146 pps->go = 0; 155 ev = pps->last_ev;
147 156
148 /* Manage the timeout */ 157 /* Manage the timeout */
149 if (fdata.timeout.flags & PPS_TIME_INVALID) 158 if (fdata.timeout.flags & PPS_TIME_INVALID)
150 err = wait_event_interruptible(pps->queue, pps->go); 159 err = wait_event_interruptible(pps->queue,
160 ev != pps->last_ev);
151 else { 161 else {
152 pr_debug("timeout %lld.%09d\n", 162 unsigned long ticks;
163
164 dev_dbg(pps->dev, "timeout %lld.%09d\n",
153 (long long) fdata.timeout.sec, 165 (long long) fdata.timeout.sec,
154 fdata.timeout.nsec); 166 fdata.timeout.nsec);
155 ticks = fdata.timeout.sec * HZ; 167 ticks = fdata.timeout.sec * HZ;
@@ -157,7 +169,9 @@ static long pps_cdev_ioctl(struct file *file,
157 169
158 if (ticks != 0) { 170 if (ticks != 0) {
159 err = wait_event_interruptible_timeout( 171 err = wait_event_interruptible_timeout(
160 pps->queue, pps->go, ticks); 172 pps->queue,
173 ev != pps->last_ev,
174 ticks);
161 if (err == 0) 175 if (err == 0)
162 return -ETIMEDOUT; 176 return -ETIMEDOUT;
163 } 177 }
@@ -165,7 +179,7 @@ static long pps_cdev_ioctl(struct file *file,
165 179
166 /* Check for pending signals */ 180 /* Check for pending signals */
167 if (err == -ERESTARTSYS) { 181 if (err == -ERESTARTSYS) {
168 pr_debug("pending signal caught\n"); 182 dev_dbg(pps->dev, "pending signal caught\n");
169 return -EINTR; 183 return -EINTR;
170 } 184 }
171 185
@@ -185,10 +199,44 @@ static long pps_cdev_ioctl(struct file *file,
185 return -EFAULT; 199 return -EFAULT;
186 200
187 break; 201 break;
202 }
203 case PPS_KC_BIND: {
204 struct pps_bind_args bind_args;
205
206 dev_dbg(pps->dev, "PPS_KC_BIND\n");
207
208 /* Check the capabilities */
209 if (!capable(CAP_SYS_TIME))
210 return -EPERM;
211
212 if (copy_from_user(&bind_args, uarg,
213 sizeof(struct pps_bind_args)))
214 return -EFAULT;
188 215
216 /* Check for supported capabilities */
217 if ((bind_args.edge & ~pps->info.mode) != 0) {
218 dev_err(pps->dev, "unsupported capabilities (%x)\n",
219 bind_args.edge);
220 return -EINVAL;
221 }
222
223 /* Validate parameters roughly */
224 if (bind_args.tsformat != PPS_TSFMT_TSPEC ||
225 (bind_args.edge & ~PPS_CAPTUREBOTH) != 0 ||
226 bind_args.consumer != PPS_KC_HARDPPS) {
227 dev_err(pps->dev, "invalid kernel consumer bind"
228 " parameters (%x)\n", bind_args.edge);
229 return -EINVAL;
230 }
231
232 err = pps_kc_bind(pps, &bind_args);
233 if (err < 0)
234 return err;
235
236 break;
237 }
189 default: 238 default:
190 return -ENOTTY; 239 return -ENOTTY;
191 break;
192 } 240 }
193 241
194 return 0; 242 return 0;
@@ -198,12 +246,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
198{ 246{
199 struct pps_device *pps = container_of(inode->i_cdev, 247 struct pps_device *pps = container_of(inode->i_cdev,
200 struct pps_device, cdev); 248 struct pps_device, cdev);
201 int found;
202
203 found = pps_get_source(pps->id) != 0;
204 if (!found)
205 return -ENODEV;
206
207 file->private_data = pps; 249 file->private_data = pps;
208 250
209 return 0; 251 return 0;
@@ -211,11 +253,6 @@ static int pps_cdev_open(struct inode *inode, struct file *file)
211 253
212static int pps_cdev_release(struct inode *inode, struct file *file) 254static int pps_cdev_release(struct inode *inode, struct file *file)
213{ 255{
214 struct pps_device *pps = file->private_data;
215
216 /* Free the PPS source and wake up (possible) deregistration */
217 pps_put_source(pps);
218
219 return 0; 256 return 0;
220} 257}
221 258
@@ -233,25 +270,67 @@ static const struct file_operations pps_cdev_fops = {
233 .release = pps_cdev_release, 270 .release = pps_cdev_release,
234}; 271};
235 272
273static void pps_device_destruct(struct device *dev)
274{
275 struct pps_device *pps = dev_get_drvdata(dev);
276
277 /* release id here to protect others from using it while it's
278 * still in use */
279 mutex_lock(&pps_idr_lock);
280 idr_remove(&pps_idr, pps->id);
281 mutex_unlock(&pps_idr_lock);
282
283 kfree(dev);
284 kfree(pps);
285}
286
236int pps_register_cdev(struct pps_device *pps) 287int pps_register_cdev(struct pps_device *pps)
237{ 288{
238 int err; 289 int err;
290 dev_t devt;
291
292 mutex_lock(&pps_idr_lock);
293 /* Get new ID for the new PPS source */
294 if (idr_pre_get(&pps_idr, GFP_KERNEL) == 0) {
295 mutex_unlock(&pps_idr_lock);
296 return -ENOMEM;
297 }
298
299 /* Now really allocate the PPS source.
300 * After idr_get_new() calling the new source will be freely available
301 * into the kernel.
302 */
303 err = idr_get_new(&pps_idr, pps, &pps->id);
304 mutex_unlock(&pps_idr_lock);
305
306 if (err < 0)
307 return err;
308
309 pps->id &= MAX_ID_MASK;
310 if (pps->id >= PPS_MAX_SOURCES) {
311 pr_err("%s: too many PPS sources in the system\n",
312 pps->info.name);
313 err = -EBUSY;
314 goto free_idr;
315 }
316
317 devt = MKDEV(MAJOR(pps_devt), pps->id);
239 318
240 pps->devno = MKDEV(MAJOR(pps_devt), pps->id);
241 cdev_init(&pps->cdev, &pps_cdev_fops); 319 cdev_init(&pps->cdev, &pps_cdev_fops);
242 pps->cdev.owner = pps->info.owner; 320 pps->cdev.owner = pps->info.owner;
243 321
244 err = cdev_add(&pps->cdev, pps->devno, 1); 322 err = cdev_add(&pps->cdev, devt, 1);
245 if (err) { 323 if (err) {
246 printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n", 324 pr_err("%s: failed to add char device %d:%d\n",
247 pps->info.name, MAJOR(pps_devt), pps->id); 325 pps->info.name, MAJOR(pps_devt), pps->id);
248 return err; 326 goto free_idr;
249 } 327 }
250 pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL, 328 pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
251 "pps%d", pps->id); 329 "pps%d", pps->id);
252 if (IS_ERR(pps->dev)) 330 if (IS_ERR(pps->dev))
253 goto del_cdev; 331 goto del_cdev;
254 dev_set_drvdata(pps->dev, pps); 332
333 pps->dev->release = pps_device_destruct;
255 334
256 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, 335 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
257 MAJOR(pps_devt), pps->id); 336 MAJOR(pps_devt), pps->id);
@@ -261,12 +340,17 @@ int pps_register_cdev(struct pps_device *pps)
261del_cdev: 340del_cdev:
262 cdev_del(&pps->cdev); 341 cdev_del(&pps->cdev);
263 342
343free_idr:
344 mutex_lock(&pps_idr_lock);
345 idr_remove(&pps_idr, pps->id);
346 mutex_unlock(&pps_idr_lock);
347
264 return err; 348 return err;
265} 349}
266 350
267void pps_unregister_cdev(struct pps_device *pps) 351void pps_unregister_cdev(struct pps_device *pps)
268{ 352{
269 device_destroy(pps_class, pps->devno); 353 device_destroy(pps_class, pps->dev->devt);
270 cdev_del(&pps->cdev); 354 cdev_del(&pps->cdev);
271} 355}
272 356
@@ -286,14 +370,14 @@ static int __init pps_init(void)
286 370
287 pps_class = class_create(THIS_MODULE, "pps"); 371 pps_class = class_create(THIS_MODULE, "pps");
288 if (!pps_class) { 372 if (!pps_class) {
289 printk(KERN_ERR "pps: failed to allocate class\n"); 373 pr_err("failed to allocate class\n");
290 return -ENOMEM; 374 return -ENOMEM;
291 } 375 }
292 pps_class->dev_attrs = pps_attrs; 376 pps_class->dev_attrs = pps_attrs;
293 377
294 err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps"); 378 err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
295 if (err < 0) { 379 if (err < 0) {
296 printk(KERN_ERR "pps: failed to allocate char device region\n"); 380 pr_err("failed to allocate char device region\n");
297 goto remove_class; 381 goto remove_class;
298 } 382 }
299 383