• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23 
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/init.h>
27 #include <linux/sched.h>
28 #include <linux/uaccess.h>
29 #include <linux/idr.h>
30 #include <linux/mutex.h>
31 #include <linux/cdev.h>
32 #include <linux/poll.h>
33 #include <linux/pps_kernel.h>
34 #include <linux/slab.h>
35 
36 #include "kc.h"
37 
38 /*
39  * Local variables
40  */
41 
42 static dev_t pps_devt;
43 static struct class *pps_class;
44 
45 static DEFINE_MUTEX(pps_idr_lock);
46 static DEFINE_IDR(pps_idr);
47 
48 /*
49  * Char device methods
50  */
51 
pps_cdev_poll(struct file * file,poll_table * wait)52 static unsigned int pps_cdev_poll(struct file *file, poll_table *wait)
53 {
54 	struct pps_device *pps = file->private_data;
55 
56 	poll_wait(file, &pps->queue, wait);
57 
58 	return POLLIN | POLLRDNORM;
59 }
60 
pps_cdev_fasync(int fd,struct file * file,int on)61 static int pps_cdev_fasync(int fd, struct file *file, int on)
62 {
63 	struct pps_device *pps = file->private_data;
64 	return fasync_helper(fd, file, on, &pps->async_queue);
65 }
66 
pps_cdev_ioctl(struct file * file,unsigned int cmd,unsigned long arg)67 static long pps_cdev_ioctl(struct file *file,
68 		unsigned int cmd, unsigned long arg)
69 {
70 	struct pps_device *pps = file->private_data;
71 	struct pps_kparams params;
72 	void __user *uarg = (void __user *) arg;
73 	int __user *iuarg = (int __user *) arg;
74 	int err;
75 
76 	switch (cmd) {
77 	case PPS_GETPARAMS:
78 		dev_dbg(pps->dev, "PPS_GETPARAMS\n");
79 
80 		spin_lock_irq(&pps->lock);
81 
82 		/* Get the current parameters */
83 		params = pps->params;
84 
85 		spin_unlock_irq(&pps->lock);
86 
87 		err = copy_to_user(uarg, &params, sizeof(struct pps_kparams));
88 		if (err)
89 			return -EFAULT;
90 
91 		break;
92 
93 	case PPS_SETPARAMS:
94 		dev_dbg(pps->dev, "PPS_SETPARAMS\n");
95 
96 		/* Check the capabilities */
97 		if (!capable(CAP_SYS_TIME))
98 			return -EPERM;
99 
100 		err = copy_from_user(&params, uarg, sizeof(struct pps_kparams));
101 		if (err)
102 			return -EFAULT;
103 		if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) {
104 			dev_dbg(pps->dev, "capture mode unspecified (%x)\n",
105 								params.mode);
106 			return -EINVAL;
107 		}
108 
109 		/* Check for supported capabilities */
110 		if ((params.mode & ~pps->info.mode) != 0) {
111 			dev_dbg(pps->dev, "unsupported capabilities (%x)\n",
112 								params.mode);
113 			return -EINVAL;
114 		}
115 
116 		spin_lock_irq(&pps->lock);
117 
118 		/* Save the new parameters */
119 		pps->params = params;
120 
121 		/* Restore the read only parameters */
122 		if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) {
123 			/* section 3.3 of RFC 2783 interpreted */
124 			dev_dbg(pps->dev, "time format unspecified (%x)\n",
125 								params.mode);
126 			pps->params.mode |= PPS_TSFMT_TSPEC;
127 		}
128 		if (pps->info.mode & PPS_CANWAIT)
129 			pps->params.mode |= PPS_CANWAIT;
130 		pps->params.api_version = PPS_API_VERS;
131 
132 		/*
133 		 * Clear unused fields of pps_kparams to avoid leaking
134 		 * uninitialized data of the PPS_SETPARAMS caller via
135 		 * PPS_GETPARAMS
136 		 */
137 		pps->params.assert_off_tu.flags = 0;
138 		pps->params.clear_off_tu.flags = 0;
139 
140 		spin_unlock_irq(&pps->lock);
141 
142 		break;
143 
144 	case PPS_GETCAP:
145 		dev_dbg(pps->dev, "PPS_GETCAP\n");
146 
147 		err = put_user(pps->info.mode, iuarg);
148 		if (err)
149 			return -EFAULT;
150 
151 		break;
152 
153 	case PPS_FETCH: {
154 		struct pps_fdata fdata;
155 		unsigned int ev;
156 
157 		dev_dbg(pps->dev, "PPS_FETCH\n");
158 
159 		err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata));
160 		if (err)
161 			return -EFAULT;
162 
163 		ev = pps->last_ev;
164 
165 		/* Manage the timeout */
166 		if (fdata.timeout.flags & PPS_TIME_INVALID)
167 			err = wait_event_interruptible(pps->queue,
168 					ev != pps->last_ev);
169 		else {
170 			unsigned long ticks;
171 
172 			dev_dbg(pps->dev, "timeout %lld.%09d\n",
173 					(long long) fdata.timeout.sec,
174 					fdata.timeout.nsec);
175 			ticks = fdata.timeout.sec * HZ;
176 			ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ);
177 
178 			if (ticks != 0) {
179 				err = wait_event_interruptible_timeout(
180 						pps->queue,
181 						ev != pps->last_ev,
182 						ticks);
183 				if (err == 0)
184 					return -ETIMEDOUT;
185 			}
186 		}
187 
188 		/* Check for pending signals */
189 		if (err == -ERESTARTSYS) {
190 			dev_dbg(pps->dev, "pending signal caught\n");
191 			return -EINTR;
192 		}
193 
194 		/* Return the fetched timestamp */
195 		spin_lock_irq(&pps->lock);
196 
197 		fdata.info.assert_sequence = pps->assert_sequence;
198 		fdata.info.clear_sequence = pps->clear_sequence;
199 		fdata.info.assert_tu = pps->assert_tu;
200 		fdata.info.clear_tu = pps->clear_tu;
201 		fdata.info.current_mode = pps->current_mode;
202 
203 		spin_unlock_irq(&pps->lock);
204 
205 		err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata));
206 		if (err)
207 			return -EFAULT;
208 
209 		break;
210 	}
211 	case PPS_KC_BIND: {
212 		struct pps_bind_args bind_args;
213 
214 		dev_dbg(pps->dev, "PPS_KC_BIND\n");
215 
216 		/* Check the capabilities */
217 		if (!capable(CAP_SYS_TIME))
218 			return -EPERM;
219 
220 		if (copy_from_user(&bind_args, uarg,
221 					sizeof(struct pps_bind_args)))
222 			return -EFAULT;
223 
224 		/* Check for supported capabilities */
225 		if ((bind_args.edge & ~pps->info.mode) != 0) {
226 			dev_err(pps->dev, "unsupported capabilities (%x)\n",
227 					bind_args.edge);
228 			return -EINVAL;
229 		}
230 
231 		/* Validate parameters roughly */
232 		if (bind_args.tsformat != PPS_TSFMT_TSPEC ||
233 				(bind_args.edge & ~PPS_CAPTUREBOTH) != 0 ||
234 				bind_args.consumer != PPS_KC_HARDPPS) {
235 			dev_err(pps->dev, "invalid kernel consumer bind"
236 					" parameters (%x)\n", bind_args.edge);
237 			return -EINVAL;
238 		}
239 
240 		err = pps_kc_bind(pps, &bind_args);
241 		if (err < 0)
242 			return err;
243 
244 		break;
245 	}
246 	default:
247 		return -ENOTTY;
248 	}
249 
250 	return 0;
251 }
252 
pps_cdev_open(struct inode * inode,struct file * file)253 static int pps_cdev_open(struct inode *inode, struct file *file)
254 {
255 	struct pps_device *pps = container_of(inode->i_cdev,
256 						struct pps_device, cdev);
257 	file->private_data = pps;
258 	kobject_get(&pps->dev->kobj);
259 	return 0;
260 }
261 
pps_cdev_release(struct inode * inode,struct file * file)262 static int pps_cdev_release(struct inode *inode, struct file *file)
263 {
264 	struct pps_device *pps = container_of(inode->i_cdev,
265 						struct pps_device, cdev);
266 	kobject_put(&pps->dev->kobj);
267 	return 0;
268 }
269 
270 /*
271  * Char device stuff
272  */
273 
274 static const struct file_operations pps_cdev_fops = {
275 	.owner		= THIS_MODULE,
276 	.llseek		= no_llseek,
277 	.poll		= pps_cdev_poll,
278 	.fasync		= pps_cdev_fasync,
279 	.unlocked_ioctl	= pps_cdev_ioctl,
280 	.open		= pps_cdev_open,
281 	.release	= pps_cdev_release,
282 };
283 
pps_device_destruct(struct device * dev)284 static void pps_device_destruct(struct device *dev)
285 {
286 	struct pps_device *pps = dev_get_drvdata(dev);
287 
288 	cdev_del(&pps->cdev);
289 
290 	/* Now we can release the ID for re-use */
291 	pr_debug("deallocating pps%d\n", pps->id);
292 	mutex_lock(&pps_idr_lock);
293 	idr_remove(&pps_idr, pps->id);
294 	mutex_unlock(&pps_idr_lock);
295 
296 	kfree(dev);
297 	kfree(pps);
298 }
299 
pps_register_cdev(struct pps_device * pps)300 int pps_register_cdev(struct pps_device *pps)
301 {
302 	int err;
303 	dev_t devt;
304 
305 	mutex_lock(&pps_idr_lock);
306 	/*
307 	 * Get new ID for the new PPS source.  After idr_alloc() calling
308 	 * the new source will be freely available into the kernel.
309 	 */
310 	err = idr_alloc(&pps_idr, pps, 0, PPS_MAX_SOURCES, GFP_KERNEL);
311 	if (err < 0) {
312 		if (err == -ENOSPC) {
313 			pr_err("%s: too many PPS sources in the system\n",
314 			       pps->info.name);
315 			err = -EBUSY;
316 		}
317 		goto out_unlock;
318 	}
319 	pps->id = err;
320 	mutex_unlock(&pps_idr_lock);
321 
322 	devt = MKDEV(MAJOR(pps_devt), pps->id);
323 
324 	cdev_init(&pps->cdev, &pps_cdev_fops);
325 	pps->cdev.owner = pps->info.owner;
326 
327 	err = cdev_add(&pps->cdev, devt, 1);
328 	if (err) {
329 		pr_err("%s: failed to add char device %d:%d\n",
330 				pps->info.name, MAJOR(pps_devt), pps->id);
331 		goto free_idr;
332 	}
333 	pps->dev = device_create(pps_class, pps->info.dev, devt, pps,
334 							"pps%d", pps->id);
335 	if (IS_ERR(pps->dev)) {
336 		err = PTR_ERR(pps->dev);
337 		goto del_cdev;
338 	}
339 
340 	/* Override the release function with our own */
341 	pps->dev->release = pps_device_destruct;
342 
343 	pr_debug("source %s got cdev (%d:%d)\n", pps->info.name,
344 			MAJOR(pps_devt), pps->id);
345 
346 	return 0;
347 
348 del_cdev:
349 	cdev_del(&pps->cdev);
350 
351 free_idr:
352 	mutex_lock(&pps_idr_lock);
353 	idr_remove(&pps_idr, pps->id);
354 out_unlock:
355 	mutex_unlock(&pps_idr_lock);
356 	return err;
357 }
358 
pps_unregister_cdev(struct pps_device * pps)359 void pps_unregister_cdev(struct pps_device *pps)
360 {
361 	pr_debug("unregistering pps%d\n", pps->id);
362 	pps->lookup_cookie = NULL;
363 	device_destroy(pps_class, pps->dev->devt);
364 }
365 
366 /*
367  * Look up a pps device by magic cookie.
368  * The cookie is usually a pointer to some enclosing device, but this
369  * code doesn't care; you should never be dereferencing it.
370  *
371  * This is a bit of a kludge that is currently used only by the PPS
372  * serial line discipline.  It may need to be tweaked when a second user
373  * is found.
374  *
375  * There is no function interface for setting the lookup_cookie field.
376  * It's initialized to NULL when the pps device is created, and if a
377  * client wants to use it, just fill it in afterward.
378  *
379  * The cookie is automatically set to NULL in pps_unregister_source()
380  * so that it will not be used again, even if the pps device cannot
381  * be removed from the idr due to pending references holding the minor
382  * number in use.
383  */
pps_lookup_dev(void const * cookie)384 struct pps_device *pps_lookup_dev(void const *cookie)
385 {
386 	struct pps_device *pps;
387 	unsigned id;
388 
389 	rcu_read_lock();
390 	idr_for_each_entry(&pps_idr, pps, id)
391 		if (cookie == pps->lookup_cookie)
392 			break;
393 	rcu_read_unlock();
394 	return pps;
395 }
396 EXPORT_SYMBOL(pps_lookup_dev);
397 
398 /*
399  * Module stuff
400  */
401 
pps_exit(void)402 static void __exit pps_exit(void)
403 {
404 	class_destroy(pps_class);
405 	unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES);
406 }
407 
pps_init(void)408 static int __init pps_init(void)
409 {
410 	int err;
411 
412 	pps_class = class_create(THIS_MODULE, "pps");
413 	if (IS_ERR(pps_class)) {
414 		pr_err("failed to allocate class\n");
415 		return PTR_ERR(pps_class);
416 	}
417 	pps_class->dev_groups = pps_groups;
418 
419 	err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps");
420 	if (err < 0) {
421 		pr_err("failed to allocate char device region\n");
422 		goto remove_class;
423 	}
424 
425 	pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS);
426 	pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti "
427 		"<giometti@linux.it>\n", PPS_VERSION);
428 
429 	return 0;
430 
431 remove_class:
432 	class_destroy(pps_class);
433 
434 	return err;
435 }
436 
437 subsys_initcall(pps_init);
438 module_exit(pps_exit);
439 
440 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
441 MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION);
442 MODULE_LICENSE("GPL");
443