1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * PPS generators core file
4  *
5  * Copyright (C) 2024 Rodolfo Giometti <[email protected]>
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 
pps_gen_cdev_poll(struct file * file,poll_table * wait)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 
pps_gen_cdev_fasync(int fd,struct file * file,int on)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 
pps_gen_cdev_ioctl(struct file * file,unsigned int cmd,unsigned long arg)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 
pps_gen_cdev_open(struct inode * inode,struct file * file)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 
pps_gen_cdev_release(struct inode * inode,struct file * file)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 
pps_gen_device_destruct(struct device * dev)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 
pps_gen_register_cdev(struct pps_gen_device * pps_gen)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 
pps_gen_unregister_cdev(struct pps_gen_device * pps_gen)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  */
pps_gen_register_source(struct pps_gen_source_info * info)228 struct pps_gen_device *pps_gen_register_source(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  */
pps_gen_unregister_source(struct pps_gen_device * pps_gen)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  */
pps_gen_event(struct pps_gen_device * pps_gen,unsigned int event,void * data)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 
pps_gen_exit(void)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 
pps_gen_init(void)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 <[email protected]>");
343 MODULE_DESCRIPTION("LinuxPPS generators support");
344 MODULE_LICENSE("GPL");
345