1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * PPS generators core file 4 * 5 * Copyright (C) 2024 Rodolfo Giometti <giometti@enneenne.com> 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/time.h> 15 #include <linux/timex.h> 16 #include <linux/uaccess.h> 17 #include <linux/idr.h> 18 #include <linux/cdev.h> 19 #include <linux/poll.h> 20 #include <linux/fs.h> 21 #include <linux/pps_gen_kernel.h> 22 #include <linux/slab.h> 23 24 /* 25 * Local variables 26 */ 27 28 static dev_t pps_gen_devt; 29 static const struct class pps_gen_class = { 30 .name = "pps-gen", 31 .dev_groups = pps_gen_groups 32 }; 33 34 static DEFINE_IDA(pps_gen_ida); 35 36 /* 37 * Char device methods 38 */ 39 40 static __poll_t pps_gen_cdev_poll(struct file *file, poll_table *wait) 41 { 42 struct pps_gen_device *pps_gen = file->private_data; 43 44 poll_wait(file, &pps_gen->queue, wait); 45 return EPOLLIN | EPOLLRDNORM; 46 } 47 48 static int pps_gen_cdev_fasync(int fd, struct file *file, int on) 49 { 50 struct pps_gen_device *pps_gen = file->private_data; 51 52 return fasync_helper(fd, file, on, &pps_gen->async_queue); 53 } 54 55 static long pps_gen_cdev_ioctl(struct file *file, 56 unsigned int cmd, unsigned long arg) 57 { 58 struct pps_gen_device *pps_gen = file->private_data; 59 void __user *uarg = (void __user *) arg; 60 unsigned int __user *uiuarg = (unsigned int __user *) arg; 61 unsigned int status; 62 int ret; 63 64 switch (cmd) { 65 case PPS_GEN_SETENABLE: 66 dev_dbg(pps_gen->dev, "PPS_GEN_SETENABLE\n"); 67 68 ret = get_user(status, uiuarg); 69 if (ret) 70 return -EFAULT; 71 72 ret = pps_gen->info->enable(pps_gen, status); 73 if (ret) 74 return ret; 75 pps_gen->enabled = status; 76 77 break; 78 79 case PPS_GEN_USESYSTEMCLOCK: 80 dev_dbg(pps_gen->dev, "PPS_GEN_USESYSTEMCLOCK\n"); 81 82 ret = put_user(pps_gen->info->use_system_clock, uiuarg); 83 if (ret) 84 return -EFAULT; 85 86 break; 87 88 case PPS_GEN_FETCHEVENT: { 89 struct pps_gen_event info; 90 unsigned int ev = pps_gen->last_ev; 91 92 dev_dbg(pps_gen->dev, "PPS_GEN_FETCHEVENT\n"); 93 94 ret = wait_event_interruptible(pps_gen->queue, 95 ev != pps_gen->last_ev); 96 if (ret == -ERESTARTSYS) { 97 dev_dbg(pps_gen->dev, "pending signal caught\n"); 98 return -EINTR; 99 } 100 101 spin_lock_irq(&pps_gen->lock); 102 info.sequence = pps_gen->sequence; 103 info.event = pps_gen->event; 104 spin_unlock_irq(&pps_gen->lock); 105 106 ret = copy_to_user(uarg, &info, sizeof(struct pps_gen_event)); 107 if (ret) 108 return -EFAULT; 109 110 break; 111 } 112 default: 113 return -ENOTTY; 114 } 115 116 return 0; 117 } 118 119 static int pps_gen_cdev_open(struct inode *inode, struct file *file) 120 { 121 struct pps_gen_device *pps_gen = container_of(inode->i_cdev, 122 struct pps_gen_device, cdev); 123 124 get_device(pps_gen->dev); 125 file->private_data = pps_gen; 126 return 0; 127 } 128 129 static int pps_gen_cdev_release(struct inode *inode, struct file *file) 130 { 131 struct pps_gen_device *pps_gen = file->private_data; 132 133 put_device(pps_gen->dev); 134 return 0; 135 } 136 137 /* 138 * Char device stuff 139 */ 140 141 static const struct file_operations pps_gen_cdev_fops = { 142 .owner = THIS_MODULE, 143 .poll = pps_gen_cdev_poll, 144 .fasync = pps_gen_cdev_fasync, 145 .unlocked_ioctl = pps_gen_cdev_ioctl, 146 .open = pps_gen_cdev_open, 147 .release = pps_gen_cdev_release, 148 }; 149 150 static void pps_gen_device_destruct(struct device *dev) 151 { 152 struct pps_gen_device *pps_gen = dev_get_drvdata(dev); 153 154 cdev_del(&pps_gen->cdev); 155 156 pr_debug("deallocating pps-gen%d\n", pps_gen->id); 157 ida_free(&pps_gen_ida, pps_gen->id); 158 159 kfree(dev); 160 kfree(pps_gen); 161 } 162 163 static int pps_gen_register_cdev(struct pps_gen_device *pps_gen) 164 { 165 int err; 166 dev_t devt; 167 168 err = ida_alloc_max(&pps_gen_ida, PPS_GEN_MAX_SOURCES - 1, GFP_KERNEL); 169 if (err < 0) { 170 if (err == -ENOSPC) { 171 pr_err("too many PPS sources in the system\n"); 172 err = -EBUSY; 173 } 174 return err; 175 } 176 pps_gen->id = err; 177 178 devt = MKDEV(MAJOR(pps_gen_devt), pps_gen->id); 179 180 cdev_init(&pps_gen->cdev, &pps_gen_cdev_fops); 181 pps_gen->cdev.owner = pps_gen->info->owner; 182 183 err = cdev_add(&pps_gen->cdev, devt, 1); 184 if (err) { 185 pr_err("failed to add char device %d:%d\n", 186 MAJOR(pps_gen_devt), pps_gen->id); 187 goto free_ida; 188 } 189 pps_gen->dev = device_create(&pps_gen_class, pps_gen->info->parent, devt, 190 pps_gen, "pps-gen%d", pps_gen->id); 191 if (IS_ERR(pps_gen->dev)) { 192 err = PTR_ERR(pps_gen->dev); 193 goto del_cdev; 194 } 195 pps_gen->dev->release = pps_gen_device_destruct; 196 dev_set_drvdata(pps_gen->dev, pps_gen); 197 198 pr_debug("generator got cdev (%d:%d)\n", 199 MAJOR(pps_gen_devt), pps_gen->id); 200 201 return 0; 202 203 del_cdev: 204 cdev_del(&pps_gen->cdev); 205 free_ida: 206 ida_free(&pps_gen_ida, pps_gen->id); 207 return err; 208 } 209 210 static void pps_gen_unregister_cdev(struct pps_gen_device *pps_gen) 211 { 212 pr_debug("unregistering pps-gen%d\n", pps_gen->id); 213 device_destroy(&pps_gen_class, pps_gen->dev->devt); 214 } 215 216 /* 217 * Exported functions 218 */ 219 220 /** 221 * pps_gen_register_source() - add a PPS generator in the system 222 * @info: the PPS generator info struct 223 * 224 * This function is used to register a new PPS generator in the system. 225 * When it returns successfully the new generator is up and running, and 226 * it can be managed by the userspace. 227 * 228 * Return: the PPS generator device in case of success, and ERR_PTR(errno) 229 * otherwise. 230 */ 231 struct pps_gen_device *pps_gen_register_source(const struct pps_gen_source_info *info) 232 { 233 struct pps_gen_device *pps_gen; 234 int err; 235 236 pps_gen = kzalloc_obj(struct pps_gen_device); 237 if (pps_gen == NULL) { 238 err = -ENOMEM; 239 goto pps_gen_register_source_exit; 240 } 241 pps_gen->info = info; 242 pps_gen->enabled = false; 243 244 init_waitqueue_head(&pps_gen->queue); 245 spin_lock_init(&pps_gen->lock); 246 247 /* Create the char device */ 248 err = pps_gen_register_cdev(pps_gen); 249 if (err < 0) { 250 pr_err(" unable to create char device\n"); 251 goto kfree_pps_gen; 252 } 253 254 return pps_gen; 255 256 kfree_pps_gen: 257 kfree(pps_gen); 258 259 pps_gen_register_source_exit: 260 pr_err("unable to register generator\n"); 261 262 return ERR_PTR(err); 263 } 264 EXPORT_SYMBOL(pps_gen_register_source); 265 266 /** 267 * pps_gen_unregister_source() - remove a PPS generator from the system 268 * @pps_gen: the PPS generator device to be removed 269 * 270 * This function is used to deregister a PPS generator from the system. When 271 * called, it disables the generator so no pulses are generated anymore. 272 */ 273 void pps_gen_unregister_source(struct pps_gen_device *pps_gen) 274 { 275 pps_gen_unregister_cdev(pps_gen); 276 } 277 EXPORT_SYMBOL(pps_gen_unregister_source); 278 279 /* pps_gen_event - register a PPS generator event into the system 280 * @pps: the PPS generator device 281 * @event: the event type 282 * @data: userdef pointer 283 * 284 * This function is used by each PPS generator in order to register a new 285 * PPS event into the system (it's usually called inside an IRQ handler). 286 */ 287 void pps_gen_event(struct pps_gen_device *pps_gen, 288 unsigned int event, void *data) 289 { 290 unsigned long flags; 291 292 dev_dbg(pps_gen->dev, "PPS generator event %u\n", event); 293 294 spin_lock_irqsave(&pps_gen->lock, flags); 295 296 pps_gen->event = event; 297 pps_gen->sequence++; 298 299 pps_gen->last_ev++; 300 wake_up_interruptible_all(&pps_gen->queue); 301 kill_fasync(&pps_gen->async_queue, SIGIO, POLL_IN); 302 303 spin_unlock_irqrestore(&pps_gen->lock, flags); 304 } 305 EXPORT_SYMBOL(pps_gen_event); 306 307 /* 308 * Module stuff 309 */ 310 311 static void __exit pps_gen_exit(void) 312 { 313 class_unregister(&pps_gen_class); 314 unregister_chrdev_region(pps_gen_devt, PPS_GEN_MAX_SOURCES); 315 } 316 317 static int __init pps_gen_init(void) 318 { 319 int err; 320 321 err = class_register(&pps_gen_class); 322 if (err) { 323 pr_err("failed to register class\n"); 324 return err; 325 } 326 327 err = alloc_chrdev_region(&pps_gen_devt, 0, 328 PPS_GEN_MAX_SOURCES, "pps-gen"); 329 if (err < 0) { 330 pr_err("failed to allocate char device region\n"); 331 goto remove_class; 332 } 333 334 return 0; 335 336 remove_class: 337 class_unregister(&pps_gen_class); 338 return err; 339 } 340 341 subsys_initcall(pps_gen_init); 342 module_exit(pps_gen_exit); 343 344 MODULE_AUTHOR("Rodolfo Giometti <giometti@enneenne.com>"); 345 MODULE_DESCRIPTION("LinuxPPS generators support"); 346 MODULE_LICENSE("GPL"); 347