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
33
34
35
36
37DEFINE_SPINLOCK(pps_idr_lock);
38DEFINE_IDR(pps_idr);
39
40
41
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
60
61
62
63
64
65
66
67
68
69
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
89
90
91
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
107
108
109 idr_remove(&pps_idr, pps->id);
110
111exit:
112 spin_unlock_irqrestore(&pps_idr_lock, flags);
113 kfree(pps);
114}
115
116
117
118
119
120
121
122
123
124
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
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
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
162
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
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
181
182
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
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
231
232
233
234
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
257
258
259
260
261
262
263
264
265
266
267
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 int captured = 0;
275
276 if ((event & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR)) == 0) {
277 printk(KERN_ERR "pps: unknown event (%x) for source %d\n",
278 event, source);
279 return;
280 }
281
282 pps = pps_get_source(source);
283 if (!pps)
284 return;
285
286 pr_debug("PPS event on source %d at %llu.%06u\n",
287 pps->id, (unsigned long long) ts->sec, ts->nsec);
288
289 spin_lock_irqsave(&pps->lock, flags);
290
291
292 if ((pps->params.mode & (PPS_ECHOASSERT | PPS_ECHOCLEAR)))
293 pps->info.echo(source, event, data);
294
295
296 pps->current_mode = pps->params.mode;
297 if ((event & PPS_CAPTUREASSERT) &
298 (pps->params.mode & PPS_CAPTUREASSERT)) {
299
300 if (pps->params.mode & PPS_OFFSETASSERT)
301 pps_add_offset(ts, &pps->params.assert_off_tu);
302
303
304 pps->assert_tu = *ts;
305 pps->assert_sequence++;
306 pr_debug("capture assert seq #%u for source %d\n",
307 pps->assert_sequence, source);
308
309 captured = ~0;
310 }
311 if ((event & PPS_CAPTURECLEAR) &
312 (pps->params.mode & PPS_CAPTURECLEAR)) {
313
314 if (pps->params.mode & PPS_OFFSETCLEAR)
315 pps_add_offset(ts, &pps->params.clear_off_tu);
316
317
318 pps->clear_tu = *ts;
319 pps->clear_sequence++;
320 pr_debug("capture clear seq #%u for source %d\n",
321 pps->clear_sequence, source);
322
323 captured = ~0;
324 }
325
326
327 if (captured) {
328 pps->go = ~0;
329 wake_up_interruptible(&pps->queue);
330
331 kill_fasync(&pps->async_queue, SIGIO, POLL_IN);
332 }
333
334 spin_unlock_irqrestore(&pps->lock, flags);
335
336
337 pps_put_source(pps);
338}
339EXPORT_SYMBOL(pps_event);
340