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 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 #include <linux/init.h> 26 #include <linux/sched.h> 27 #include <linux/uaccess.h> 28 #include <linux/idr.h> 29 #include <linux/cdev.h> 30 #include <linux/poll.h> 31 #include <linux/pps_kernel.h> 32 33 /* 34 * Local variables 35 */ 36 37 static dev_t pps_devt; 38 static struct class *pps_class; 39 40 /* 41 * Char device methods 42 */ 43 44 static unsigned int pps_cdev_poll(struct file *file, poll_table *wait) 45 { 46 struct pps_device *pps = file->private_data; 47 48 poll_wait(file, &pps->queue, wait); 49 50 return POLLIN | POLLRDNORM; 51 } 52 53 static int pps_cdev_fasync(int fd, struct file *file, int on) 54 { 55 struct pps_device *pps = file->private_data; 56 return fasync_helper(fd, file, on, &pps->async_queue); 57 } 58 59 static long pps_cdev_ioctl(struct file *file, 60 unsigned int cmd, unsigned long arg) 61 { 62 struct pps_device *pps = file->private_data; 63 struct pps_kparams params; 64 struct pps_fdata fdata; 65 unsigned long ticks; 66 void __user *uarg = (void __user *) arg; 67 int __user *iuarg = (int __user *) arg; 68 int err; 69 70 switch (cmd) { 71 case PPS_GETPARAMS: 72 pr_debug("PPS_GETPARAMS: source %d\n", pps->id); 73 74 spin_lock_irq(&pps->lock); 75 76 /* Get the current parameters */ 77 params = pps->params; 78 79 spin_unlock_irq(&pps->lock); 80 81 err = copy_to_user(uarg, ¶ms, sizeof(struct pps_kparams)); 82 if (err) 83 return -EFAULT; 84 85 break; 86 87 case PPS_SETPARAMS: 88 pr_debug("PPS_SETPARAMS: source %d\n", pps->id); 89 90 /* Check the capabilities */ 91 if (!capable(CAP_SYS_TIME)) 92 return -EPERM; 93 94 err = copy_from_user(¶ms, uarg, sizeof(struct pps_kparams)); 95 if (err) 96 return -EFAULT; 97 if (!(params.mode & (PPS_CAPTUREASSERT | PPS_CAPTURECLEAR))) { 98 pr_debug("capture mode unspecified (%x)\n", 99 params.mode); 100 return -EINVAL; 101 } 102 103 /* Check for supported capabilities */ 104 if ((params.mode & ~pps->info.mode) != 0) { 105 pr_debug("unsupported capabilities (%x)\n", 106 params.mode); 107 return -EINVAL; 108 } 109 110 spin_lock_irq(&pps->lock); 111 112 /* Save the new parameters */ 113 pps->params = params; 114 115 /* Restore the read only parameters */ 116 if ((params.mode & (PPS_TSFMT_TSPEC | PPS_TSFMT_NTPFP)) == 0) { 117 /* section 3.3 of RFC 2783 interpreted */ 118 pr_debug("time format unspecified (%x)\n", 119 params.mode); 120 pps->params.mode |= PPS_TSFMT_TSPEC; 121 } 122 if (pps->info.mode & PPS_CANWAIT) 123 pps->params.mode |= PPS_CANWAIT; 124 pps->params.api_version = PPS_API_VERS; 125 126 spin_unlock_irq(&pps->lock); 127 128 break; 129 130 case PPS_GETCAP: 131 pr_debug("PPS_GETCAP: source %d\n", pps->id); 132 133 err = put_user(pps->info.mode, iuarg); 134 if (err) 135 return -EFAULT; 136 137 break; 138 139 case PPS_FETCH: 140 pr_debug("PPS_FETCH: source %d\n", pps->id); 141 142 err = copy_from_user(&fdata, uarg, sizeof(struct pps_fdata)); 143 if (err) 144 return -EFAULT; 145 146 pps->go = 0; 147 148 /* Manage the timeout */ 149 if (fdata.timeout.flags & PPS_TIME_INVALID) 150 err = wait_event_interruptible(pps->queue, pps->go); 151 else { 152 pr_debug("timeout %lld.%09d\n", 153 (long long) fdata.timeout.sec, 154 fdata.timeout.nsec); 155 ticks = fdata.timeout.sec * HZ; 156 ticks += fdata.timeout.nsec / (NSEC_PER_SEC / HZ); 157 158 if (ticks != 0) { 159 err = wait_event_interruptible_timeout( 160 pps->queue, pps->go, ticks); 161 if (err == 0) 162 return -ETIMEDOUT; 163 } 164 } 165 166 /* Check for pending signals */ 167 if (err == -ERESTARTSYS) { 168 pr_debug("pending signal caught\n"); 169 return -EINTR; 170 } 171 172 /* Return the fetched timestamp */ 173 spin_lock_irq(&pps->lock); 174 175 fdata.info.assert_sequence = pps->assert_sequence; 176 fdata.info.clear_sequence = pps->clear_sequence; 177 fdata.info.assert_tu = pps->assert_tu; 178 fdata.info.clear_tu = pps->clear_tu; 179 fdata.info.current_mode = pps->current_mode; 180 181 spin_unlock_irq(&pps->lock); 182 183 err = copy_to_user(uarg, &fdata, sizeof(struct pps_fdata)); 184 if (err) 185 return -EFAULT; 186 187 break; 188 189 default: 190 return -ENOTTY; 191 break; 192 } 193 194 return 0; 195 } 196 197 static int pps_cdev_open(struct inode *inode, struct file *file) 198 { 199 struct pps_device *pps = container_of(inode->i_cdev, 200 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; 208 209 return 0; 210 } 211 212 static int pps_cdev_release(struct inode *inode, struct file *file) 213 { 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; 220 } 221 222 /* 223 * Char device stuff 224 */ 225 226 static const struct file_operations pps_cdev_fops = { 227 .owner = THIS_MODULE, 228 .llseek = no_llseek, 229 .poll = pps_cdev_poll, 230 .fasync = pps_cdev_fasync, 231 .unlocked_ioctl = pps_cdev_ioctl, 232 .open = pps_cdev_open, 233 .release = pps_cdev_release, 234 }; 235 236 int pps_register_cdev(struct pps_device *pps) 237 { 238 int err; 239 240 pps->devno = MKDEV(MAJOR(pps_devt), pps->id); 241 cdev_init(&pps->cdev, &pps_cdev_fops); 242 pps->cdev.owner = pps->info.owner; 243 244 err = cdev_add(&pps->cdev, pps->devno, 1); 245 if (err) { 246 printk(KERN_ERR "pps: %s: failed to add char device %d:%d\n", 247 pps->info.name, MAJOR(pps_devt), pps->id); 248 return err; 249 } 250 pps->dev = device_create(pps_class, pps->info.dev, pps->devno, NULL, 251 "pps%d", pps->id); 252 if (IS_ERR(pps->dev)) 253 goto del_cdev; 254 dev_set_drvdata(pps->dev, pps); 255 256 pr_debug("source %s got cdev (%d:%d)\n", pps->info.name, 257 MAJOR(pps_devt), pps->id); 258 259 return 0; 260 261 del_cdev: 262 cdev_del(&pps->cdev); 263 264 return err; 265 } 266 267 void pps_unregister_cdev(struct pps_device *pps) 268 { 269 device_destroy(pps_class, pps->devno); 270 cdev_del(&pps->cdev); 271 } 272 273 /* 274 * Module stuff 275 */ 276 277 static void __exit pps_exit(void) 278 { 279 class_destroy(pps_class); 280 unregister_chrdev_region(pps_devt, PPS_MAX_SOURCES); 281 } 282 283 static int __init pps_init(void) 284 { 285 int err; 286 287 pps_class = class_create(THIS_MODULE, "pps"); 288 if (!pps_class) { 289 printk(KERN_ERR "pps: failed to allocate class\n"); 290 return -ENOMEM; 291 } 292 pps_class->dev_attrs = pps_attrs; 293 294 err = alloc_chrdev_region(&pps_devt, 0, PPS_MAX_SOURCES, "pps"); 295 if (err < 0) { 296 printk(KERN_ERR "pps: failed to allocate char device region\n"); 297 goto remove_class; 298 } 299 300 pr_info("LinuxPPS API ver. %d registered\n", PPS_API_VERS); 301 pr_info("Software ver. %s - Copyright 2005-2007 Rodolfo Giometti " 302 "<giometti@linux.it>\n", PPS_VERSION); 303 304 return 0; 305 306 remove_class: 307 class_destroy(pps_class); 308 309 return err; 310 } 311 312 subsys_initcall(pps_init); 313 module_exit(pps_exit); 314 315 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>"); 316 MODULE_DESCRIPTION("LinuxPPS support (RFC 2783) - ver. " PPS_VERSION); 317 MODULE_LICENSE("GPL"); 318