1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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#include <linux/slab.h>
33
34
35
36
37
38DEFINE_SPINLOCK(pps_idr_lock);
39DEFINE_IDR(pps_idr);
40
41
42
43
44
45static void pps_add_offset(struct pps_ktime *ts, struct pps_ktime *offset)
46{
47 ts->nsec += offset->nsec;
48 while (ts->nsec >= NSEC_PER_SEC) {
49 ts->nsec -= NSEC_PER_SEC;
50 ts->sec++;
51 }
52 while (ts->nsec < 0) {
53 ts->nsec += NSEC_PER_SEC;
54 ts->sec--;
55 }
56 ts->sec += offset->sec;
57}
58
59
60
61
62
63
64
65
66
67
68
69
70
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
90
91
92
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
108
109
110 idr_remove(&pps_idr, pps->id);
111
112exit:
113 spin_unlock_irqrestore(&pps_idr_lock, flags);
114 kfree(pps);
115}
116
117
118
119
120
121
122
123
124
125
126
127
128int pps_register_source(struct pps_source_info *info, int default_params)
129{
130 struct pps_device *pps;
131 int id;
132 int err;
133
134
135 if ((info->mode & default_params) != default_params) {
136 printk(KERN_ERR "pps: %s: unsupported default parameters\n",
137 info->name);
138 err = -EINVAL;
139 goto pps_register_source_exit;
140 }
141 if ((info->mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)) != 0 &&
142 info->echo == NULL) {
143 printk(KERN_ERR "pps: %s: echo function is not defined\n",
144 info->name);
145 err = -EINVAL;
146 goto pps_register_source_exit;
147 }
148 if ((info->mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
149 printk(KERN_ERR "pps: %s: unspecified time format\n",
150 info->name);
151 err = -EINVAL;
152 goto pps_register_source_exit;
153 }
154
155
156 pps = kzalloc(sizeof(struct pps_device), GFP_KERNEL);
157 if (pps == NULL) {
158 err = -ENOMEM;
159 goto pps_register_source_exit;
160 }
161
162
163
164
165 pps->params.api_version = PPS_API_VERS;
166 pps->params.mode = default_params;
167 pps->info = *info;
168
169 init_waitqueue_head(&pps->queue);
170 spin_lock_init(&pps->lock);
171 atomic_set(&pps->usage, 1);
172
173
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
182
183
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
204
205 err = pps_register_cdev(pps);
206 if (err < 0) {
207 printk(KERN_ERR "pps: %s: unable to create char device\n",
208 info->name);
209 goto free_idr;
210 }
211
212 pr_info("new PPS source %s at ID %d\n", info->name, id);
213
214 return id;
215
216free_idr:
217 spin_lock_irq(&pps_idr_lock);
218 idr_remove(&pps_idr, id);
219 spin_unlock_irq(&pps_idr_lock);
220
221kfree_pps:
222 kfree(pps);
223
224pps_register_source_exit:
225 printk(KERN_ERR "pps: %s: unable to register source\n", info->name);
226
227 return err;
228}
229EXPORT_SYMBOL(pps_register_source);
230
231
232
233
234
235
236
237
238void pps_unregister_source(int source)
239{
240 struct pps_device *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);
253 pps_put_source(pps);
254}
255EXPORT_SYMBOL(pps_unregister_source);
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271void pps_event(int source, struct pps_ktime *ts, int event, void *data)
272{
273 struct pps_device *pps;
274 unsigned long flags;
275 int captured = 0;
276
277 if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
278 printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
279 event, source);
280 return;
281 }
282
283 pps = pps_get_source(source);
284 if (!pps)
285 return;
286
287 pr_debug("PPS event on source %d at %llu.%06u\n",
288 pps->id, (unsigned long long) ts->sec, ts->nsec);
289
290 spin_lock_irqsave(&pps->lock, flags);
291
292
293 if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
294 pps->info.echo(source, event, data);
295
296
297 pps->current_mode = pps->params.mode;
298 if ((event & PPS_CAPTUREASSERT) &
299 (pps->params.mode & PPS_CAPTUREASSERT)) {
300
301 if (pps->params.mode & PPS_OFFSETASSERT)
302 pps_add_offset(ts, &pps->params.assert_off_tu);
303
304
305 pps->assert_tu = *ts;
306 pps->assert_sequence++;
307 pr_debug("capture assert seq #%u for source %d\n",
308 pps->assert_sequence, source);
309
310 captured = ~0;
311 }
312 if ((event & PPS_CAPTURECLEAR) &
313 (pps->params.mode & PPS_CAPTURECLEAR)) {
314
315 if (pps->params.mode & PPS_OFFSETCLEAR)
316 pps_add_offset(ts, &pps->params.clear_off_tu);
317
318
319 pps->clear_tu = *ts;
320 pps->clear_sequence++;
321 pr_debug("capture clear seq #%u for source %d\n",
322 pps->clear_sequence, source);
323
324 captured = ~0;
325 }
326
327
328 if (captured) {
329 pps->go = ~0;
330 wake_up_interruptible(&pps->queue);
331
332 kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
333 }
334
335 spin_unlock_irqrestore(&pps->lock, flags);
336
337
338 pps_put_source(pps);
339}
340EXPORT_SYMBOL(pps_event);
341