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