Adjust dependencies for Navigation demo app
[AGL/meta-agl-demo.git] / recipes-kernel / aim-cdev / files / cdev.c
1 /*
2  * cdev.c - Application interfacing module for character devices
3  *
4  * Copyright (C) 2013-2015 Microchip Technology Germany II GmbH & Co. KG
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  * GNU General Public License for more details.
10  *
11  * This file is licensed under GPLv2.
12  */
13
14 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 #include <linux/module.h>
16 #include <linux/sched.h>
17 #include <linux/fs.h>
18 #include <linux/slab.h>
19 #include <linux/device.h>
20 #include <linux/cdev.h>
21 #include <linux/poll.h>
22 #include <linux/kfifo.h>
23 #include <linux/uaccess.h>
24 #include <linux/idr.h>
25 #include "mostcore.h"
26
27 static dev_t aim_devno;
28 static struct class *aim_class;
29 static struct ida minor_id;
30 static unsigned int major;
31 static struct most_aim cdev_aim;
32
33 struct aim_channel {
34         wait_queue_head_t wq;
35         spinlock_t unlink;      /* synchronization lock to unlink channels */
36         struct cdev cdev;
37         struct device *dev;
38         struct mutex io_mutex;
39         struct most_interface *iface;
40         struct most_channel_config *cfg;
41         unsigned int channel_id;
42         dev_t devno;
43         size_t mbo_offs;
44         DECLARE_KFIFO_PTR(fifo, typeof(struct mbo *));
45         int access_ref;
46         struct list_head list;
47 };
48
49 #define to_channel(d) container_of(d, struct aim_channel, cdev)
50 static struct list_head channel_list;
51 static spinlock_t ch_list_lock;
52
53 static inline bool ch_has_mbo(struct aim_channel *c)
54 {
55         return channel_has_mbo(c->iface, c->channel_id, &cdev_aim) > 0;
56 }
57
58 static inline bool ch_get_mbo(struct aim_channel *c, struct mbo **mbo)
59 {
60         *mbo = most_get_mbo(c->iface, c->channel_id, &cdev_aim);
61         return *mbo;
62 }
63
64 static struct aim_channel *get_channel(struct most_interface *iface, int id)
65 {
66         struct aim_channel *c, *tmp;
67         unsigned long flags;
68         int found_channel = 0;
69
70         spin_lock_irqsave(&ch_list_lock, flags);
71         list_for_each_entry_safe(c, tmp, &channel_list, list) {
72                 if ((c->iface == iface) && (c->channel_id == id)) {
73                         found_channel = 1;
74                         break;
75                 }
76         }
77         spin_unlock_irqrestore(&ch_list_lock, flags);
78         if (!found_channel)
79                 return NULL;
80         return c;
81 }
82
83 static void stop_channel(struct aim_channel *c)
84 {
85         struct mbo *mbo;
86
87         while (kfifo_out((struct kfifo *)&c->fifo, &mbo, 1))
88                 most_put_mbo(mbo);
89         most_stop_channel(c->iface, c->channel_id, &cdev_aim);
90 }
91
92 static void destroy_cdev(struct aim_channel *c)
93 {
94         unsigned long flags;
95
96         device_destroy(aim_class, c->devno);
97         cdev_del(&c->cdev);
98         kfifo_free(&c->fifo);
99         spin_lock_irqsave(&ch_list_lock, flags);
100         list_del(&c->list);
101         spin_unlock_irqrestore(&ch_list_lock, flags);
102         ida_simple_remove(&minor_id, MINOR(c->devno));
103 }
104
105 /**
106  * aim_open - implements the syscall to open the device
107  * @inode: inode pointer
108  * @filp: file pointer
109  *
110  * This stores the channel pointer in the private data field of
111  * the file structure and activates the channel within the core.
112  */
113 static int aim_open(struct inode *inode, struct file *filp)
114 {
115         struct aim_channel *c;
116         int ret;
117
118         c = to_channel(inode->i_cdev);
119         filp->private_data = c;
120
121         if (((c->cfg->direction == MOST_CH_RX) &&
122              ((filp->f_flags & O_ACCMODE) != O_RDONLY)) ||
123              ((c->cfg->direction == MOST_CH_TX) &&
124                 ((filp->f_flags & O_ACCMODE) != O_WRONLY))) {
125                 pr_info("WARN: Access flags mismatch\n");
126                 return -EACCES;
127         }
128
129         mutex_lock(&c->io_mutex);
130         if (!c->dev) {
131                 pr_info("WARN: Device is destroyed\n");
132                 mutex_unlock(&c->io_mutex);
133                 return -EBUSY;
134         }
135
136         if (c->access_ref) {
137                 pr_info("WARN: Device is busy\n");
138                 mutex_unlock(&c->io_mutex);
139                 return -EBUSY;
140         }
141
142         c->mbo_offs = 0;
143         ret = most_start_channel(c->iface, c->channel_id, &cdev_aim);
144         if (!ret)
145                 c->access_ref = 1;
146         mutex_unlock(&c->io_mutex);
147         return ret;
148 }
149
150 /**
151  * aim_close - implements the syscall to close the device
152  * @inode: inode pointer
153  * @filp: file pointer
154  *
155  * This stops the channel within the core.
156  */
157 static int aim_close(struct inode *inode, struct file *filp)
158 {
159         struct aim_channel *c = to_channel(inode->i_cdev);
160
161         mutex_lock(&c->io_mutex);
162         spin_lock(&c->unlink);
163         c->access_ref = 0;
164         spin_unlock(&c->unlink);
165         if (c->dev) {
166                 stop_channel(c);
167                 mutex_unlock(&c->io_mutex);
168         } else {
169                 destroy_cdev(c);
170                 mutex_unlock(&c->io_mutex);
171                 kfree(c);
172         }
173         return 0;
174 }
175
176 /**
177  * aim_write - implements the syscall to write to the device
178  * @filp: file pointer
179  * @buf: pointer to user buffer
180  * @count: number of bytes to write
181  * @offset: offset from where to start writing
182  */
183 static ssize_t aim_write(struct file *filp, const char __user *buf,
184                          size_t count, loff_t *offset)
185 {
186         int ret;
187         size_t actual_len;
188         size_t max_len;
189         struct mbo *mbo = NULL;
190         struct aim_channel *c = filp->private_data;
191
192         mutex_lock(&c->io_mutex);
193         while (c->dev && !ch_get_mbo(c, &mbo)) {
194                 mutex_unlock(&c->io_mutex);
195
196                 if ((filp->f_flags & O_NONBLOCK))
197                         return -EAGAIN;
198                 if (wait_event_interruptible(c->wq, ch_has_mbo(c) || !c->dev))
199                         return -ERESTARTSYS;
200                 mutex_lock(&c->io_mutex);
201         }
202
203         if (unlikely(!c->dev)) {
204                 ret = -EPIPE;
205                 goto unlock;
206         }
207
208         max_len = c->cfg->buffer_size;
209         actual_len = min(count, max_len);
210         mbo->buffer_length = actual_len;
211
212         if (copy_from_user(mbo->virt_address, buf, mbo->buffer_length)) {
213                 ret = -EFAULT;
214                 goto put_mbo;
215         }
216
217         ret = most_submit_mbo(mbo);
218         if (ret)
219                 goto put_mbo;
220
221         mutex_unlock(&c->io_mutex);
222         return actual_len;
223 put_mbo:
224         most_put_mbo(mbo);
225 unlock:
226         mutex_unlock(&c->io_mutex);
227         return ret;
228 }
229
230 /**
231  * aim_read - implements the syscall to read from the device
232  * @filp: file pointer
233  * @buf: pointer to user buffer
234  * @count: number of bytes to read
235  * @offset: offset from where to start reading
236  */
237 static ssize_t
238 aim_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
239 {
240         size_t to_copy, not_copied, copied;
241         struct mbo *mbo;
242         struct aim_channel *c = filp->private_data;
243
244         mutex_lock(&c->io_mutex);
245         while (c->dev && !kfifo_peek(&c->fifo, &mbo)) {
246                 mutex_unlock(&c->io_mutex);
247                 if (filp->f_flags & O_NONBLOCK)
248                         return -EAGAIN;
249                 if (wait_event_interruptible(c->wq,
250                                              (!kfifo_is_empty(&c->fifo) ||
251                                               (!c->dev))))
252                         return -ERESTARTSYS;
253                 mutex_lock(&c->io_mutex);
254         }
255
256         /* make sure we don't submit to gone devices */
257         if (unlikely(!c->dev)) {
258                 mutex_unlock(&c->io_mutex);
259                 return -EIO;
260         }
261
262         to_copy = min_t(size_t,
263                         count,
264                         mbo->processed_length - c->mbo_offs);
265
266         not_copied = copy_to_user(buf,
267                                   mbo->virt_address + c->mbo_offs,
268                                   to_copy);
269
270         copied = to_copy - not_copied;
271
272         c->mbo_offs += copied;
273         if (c->mbo_offs >= mbo->processed_length) {
274                 kfifo_skip(&c->fifo);
275                 most_put_mbo(mbo);
276                 c->mbo_offs = 0;
277         }
278         mutex_unlock(&c->io_mutex);
279         return copied;
280 }
281
282 static unsigned int aim_poll(struct file *filp, poll_table *wait)
283 {
284         struct aim_channel *c = filp->private_data;
285         unsigned int mask = 0;
286
287         poll_wait(filp, &c->wq, wait);
288
289         if (c->cfg->direction == MOST_CH_RX) {
290                 if (!kfifo_is_empty(&c->fifo))
291                         mask |= POLLIN | POLLRDNORM;
292         } else {
293                 if (ch_has_mbo(c))
294                         mask |= POLLOUT | POLLWRNORM;
295         }
296         return mask;
297 }
298
299 /**
300  * Initialization of struct file_operations
301  */
302 static const struct file_operations channel_fops = {
303         .owner = THIS_MODULE,
304         .read = aim_read,
305         .write = aim_write,
306         .open = aim_open,
307         .release = aim_close,
308         .poll = aim_poll,
309 };
310
311 /**
312  * aim_disconnect_channel - disconnect a channel
313  * @iface: pointer to interface instance
314  * @channel_id: channel index
315  *
316  * This frees allocated memory and removes the cdev that represents this
317  * channel in user space.
318  */
319 static int aim_disconnect_channel(struct most_interface *iface, int channel_id)
320 {
321         struct aim_channel *c;
322
323         if (!iface) {
324                 pr_info("Bad interface pointer\n");
325                 return -EINVAL;
326         }
327
328         c = get_channel(iface, channel_id);
329         if (!c)
330                 return -ENXIO;
331
332         mutex_lock(&c->io_mutex);
333         spin_lock(&c->unlink);
334         c->dev = NULL;
335         spin_unlock(&c->unlink);
336         if (c->access_ref) {
337                 stop_channel(c);
338                 wake_up_interruptible(&c->wq);
339                 mutex_unlock(&c->io_mutex);
340         } else {
341                 destroy_cdev(c);
342                 mutex_unlock(&c->io_mutex);
343                 kfree(c);
344         }
345         return 0;
346 }
347
348 /**
349  * aim_rx_completion - completion handler for rx channels
350  * @mbo: pointer to buffer object that has completed
351  *
352  * This searches for the channel linked to this MBO and stores it in the local
353  * fifo buffer.
354  */
355 static int aim_rx_completion(struct mbo *mbo)
356 {
357         struct aim_channel *c;
358
359         if (!mbo)
360                 return -EINVAL;
361
362         c = get_channel(mbo->ifp, mbo->hdm_channel_id);
363         if (!c)
364                 return -ENXIO;
365
366         spin_lock(&c->unlink);
367         if (!c->access_ref || !c->dev) {
368                 spin_unlock(&c->unlink);
369                 return -EFAULT;
370         }
371         kfifo_in(&c->fifo, &mbo, 1);
372         spin_unlock(&c->unlink);
373 #ifdef DEBUG_MESG
374         if (kfifo_is_full(&c->fifo))
375                 pr_info("WARN: Fifo is full\n");
376 #endif
377         wake_up_interruptible(&c->wq);
378         return 0;
379 }
380
381 /**
382  * aim_tx_completion - completion handler for tx channels
383  * @iface: pointer to interface instance
384  * @channel_id: channel index/ID
385  *
386  * This wakes sleeping processes in the wait-queue.
387  */
388 static int aim_tx_completion(struct most_interface *iface, int channel_id)
389 {
390         struct aim_channel *c;
391
392         if (!iface) {
393                 pr_info("Bad interface pointer\n");
394                 return -EINVAL;
395         }
396         if ((channel_id < 0) || (channel_id >= iface->num_channels)) {
397                 pr_info("Channel ID out of range\n");
398                 return -EINVAL;
399         }
400
401         c = get_channel(iface, channel_id);
402         if (!c)
403                 return -ENXIO;
404         wake_up_interruptible(&c->wq);
405         return 0;
406 }
407
408 /**
409  * aim_probe - probe function of the driver module
410  * @iface: pointer to interface instance
411  * @channel_id: channel index/ID
412  * @cfg: pointer to actual channel configuration
413  * @parent: pointer to kobject (needed for sysfs hook-up)
414  * @name: name of the device to be created
415  *
416  * This allocates achannel object and creates the device node in /dev
417  *
418  * Returns 0 on success or error code otherwise.
419  */
420 static int aim_probe(struct most_interface *iface, int channel_id,
421                      struct most_channel_config *cfg,
422                      struct kobject *parent, char *name)
423 {
424         struct aim_channel *c;
425         unsigned long cl_flags;
426         int retval;
427         int current_minor;
428
429         if ((!iface) || (!cfg) || (!parent) || (!name)) {
430                 pr_info("Probing AIM with bad arguments");
431                 return -EINVAL;
432         }
433         c = get_channel(iface, channel_id);
434         if (c)
435                 return -EEXIST;
436
437         current_minor = ida_simple_get(&minor_id, 0, 0, GFP_KERNEL);
438         if (current_minor < 0)
439                 return current_minor;
440
441         c = kzalloc(sizeof(*c), GFP_KERNEL);
442         if (!c) {
443                 retval = -ENOMEM;
444                 goto error_alloc_channel;
445         }
446
447         c->devno = MKDEV(major, current_minor);
448         cdev_init(&c->cdev, &channel_fops);
449         c->cdev.owner = THIS_MODULE;
450         cdev_add(&c->cdev, c->devno, 1);
451         c->iface = iface;
452         c->cfg = cfg;
453         c->channel_id = channel_id;
454         c->access_ref = 0;
455         spin_lock_init(&c->unlink);
456         INIT_KFIFO(c->fifo);
457         retval = kfifo_alloc(&c->fifo, cfg->num_buffers, GFP_KERNEL);
458         if (retval) {
459                 pr_info("failed to alloc channel kfifo");
460                 goto error_alloc_kfifo;
461         }
462         init_waitqueue_head(&c->wq);
463         mutex_init(&c->io_mutex);
464         spin_lock_irqsave(&ch_list_lock, cl_flags);
465         list_add_tail(&c->list, &channel_list);
466         spin_unlock_irqrestore(&ch_list_lock, cl_flags);
467         c->dev = device_create(aim_class,
468                                      NULL,
469                                      c->devno,
470                                      NULL,
471                                      "%s", name);
472
473         retval = IS_ERR(c->dev);
474         if (retval) {
475                 pr_info("failed to create new device node %s\n", name);
476                 goto error_create_device;
477         }
478         kobject_uevent(&c->dev->kobj, KOBJ_ADD);
479         return 0;
480
481 error_create_device:
482         kfifo_free(&c->fifo);
483         list_del(&c->list);
484 error_alloc_kfifo:
485         cdev_del(&c->cdev);
486         kfree(c);
487 error_alloc_channel:
488         ida_simple_remove(&minor_id, current_minor);
489         return retval;
490 }
491
492 static struct most_aim cdev_aim = {
493         .name = "cdev",
494         .probe_channel = aim_probe,
495         .disconnect_channel = aim_disconnect_channel,
496         .rx_completion = aim_rx_completion,
497         .tx_completion = aim_tx_completion,
498 };
499
500 static int __init mod_init(void)
501 {
502         pr_info("init()\n");
503
504         INIT_LIST_HEAD(&channel_list);
505         spin_lock_init(&ch_list_lock);
506         ida_init(&minor_id);
507
508         if (alloc_chrdev_region(&aim_devno, 0, 50, "cdev") < 0)
509                 return -EIO;
510         major = MAJOR(aim_devno);
511
512         aim_class = class_create(THIS_MODULE, "most_cdev_aim");
513         if (IS_ERR(aim_class)) {
514                 pr_err("no udev support\n");
515                 goto free_cdev;
516         }
517
518         if (most_register_aim(&cdev_aim))
519                 goto dest_class;
520         return 0;
521
522 dest_class:
523         class_destroy(aim_class);
524 free_cdev:
525         unregister_chrdev_region(aim_devno, 1);
526         return -EIO;
527 }
528
529 static void __exit mod_exit(void)
530 {
531         struct aim_channel *c, *tmp;
532
533         pr_info("exit module\n");
534
535         most_deregister_aim(&cdev_aim);
536
537         list_for_each_entry_safe(c, tmp, &channel_list, list) {
538                 destroy_cdev(c);
539                 kfree(c);
540         }
541         class_destroy(aim_class);
542         unregister_chrdev_region(aim_devno, 1);
543         ida_destroy(&minor_id);
544 }
545
546 module_init(mod_init);
547 module_exit(mod_exit);
548 MODULE_AUTHOR("Christian Gromm <christian.gromm@microchip.com>");
549 MODULE_LICENSE("GPL");
550 MODULE_DESCRIPTION("character device AIM for mostcore");