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