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