]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/staging/most/aim-cdev/cdev.c
Merge remote-tracking branch 'staging/staging-next'
[karo-tx-linux.git] / drivers / staging / most / aim-cdev / cdev.c
index 0a13d8d0fa392c4842048df1976fd42570456c2e..dc3fb25b52aab246ba9c2d14cf7ca940be3e9e54 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/cdev.h>
+#include <linux/poll.h>
 #include <linux/kfifo.h>
 #include <linux/uaccess.h>
 #include <linux/idr.h>
@@ -27,6 +28,7 @@ static dev_t aim_devno;
 static struct class *aim_class;
 static struct ida minor_id;
 static unsigned int major;
+static struct most_aim cdev_aim;
 
 struct aim_channel {
        wait_queue_head_t wq;
@@ -44,11 +46,11 @@ struct aim_channel {
        atomic_t access_ref;
        struct list_head list;
 };
+
 #define to_channel(d) container_of(d, struct aim_channel, cdev)
 static struct list_head channel_list;
 static spinlock_t ch_list_lock;
 
-
 static struct aim_channel *get_channel(struct most_interface *iface, int id)
 {
        struct aim_channel *channel, *tmp;
@@ -85,8 +87,8 @@ static int aim_open(struct inode *inode, struct file *filp)
        filp->private_data = channel;
 
        if (((channel->cfg->direction == MOST_CH_RX) &&
-            ((filp->f_flags & O_ACCMODE) != O_RDONLY))
-           || ((channel->cfg->direction == MOST_CH_TX) &&
+            ((filp->f_flags & O_ACCMODE) != O_RDONLY)) ||
+            ((channel->cfg->direction == MOST_CH_TX) &&
                ((filp->f_flags & O_ACCMODE) != O_WRONLY))) {
                pr_info("WARN: Access flags mismatch\n");
                return -EACCES;
@@ -97,7 +99,8 @@ static int aim_open(struct inode *inode, struct file *filp)
                return -EBUSY;
        }
 
-       ret = most_start_channel(channel->iface, channel->channel_id);
+       ret = most_start_channel(channel->iface, channel->channel_id,
+                                &cdev_aim);
        if (ret)
                atomic_dec(&channel->access_ref);
        return ret;
@@ -131,11 +134,11 @@ static int aim_close(struct inode *inode, struct file *filp)
        }
        mutex_unlock(&channel->io_mutex);
 
-       while (0 != kfifo_out((struct kfifo *)&channel->fifo, &mbo, 1))
+       while (kfifo_out((struct kfifo *)&channel->fifo, &mbo, 1))
                most_put_mbo(mbo);
-       if (channel->keep_mbo == true)
+       if (channel->keep_mbo)
                most_put_mbo(channel->stacked_mbo);
-       ret = most_stop_channel(channel->iface, channel->channel_id);
+       ret = most_stop_channel(channel->iface, channel->channel_id, &cdev_aim);
        atomic_dec(&channel->access_ref);
        wake_up_interruptible(&channel->wq);
        return ret;
@@ -165,16 +168,17 @@ static ssize_t aim_write(struct file *filp, const char __user *buf,
        }
        mutex_unlock(&channel->io_mutex);
 
-       mbo = most_get_mbo(channel->iface, channel->channel_id);
+       mbo = most_get_mbo(channel->iface, channel->channel_id, &cdev_aim);
 
-       if (!mbo && channel->dev) {
+       if (!mbo) {
                if ((filp->f_flags & O_NONBLOCK))
                        return -EAGAIN;
                if (wait_event_interruptible(
                            channel->wq,
                            (mbo = most_get_mbo(channel->iface,
-                                               channel->channel_id)) ||
-                           (channel->dev == NULL)))
+                                               channel->channel_id,
+                                               &cdev_aim)) ||
+                           (!channel->dev)))
                        return -ERESTARTSYS;
        }
 
@@ -204,8 +208,7 @@ static ssize_t aim_write(struct file *filp, const char __user *buf,
        }
        return actual_len - retval;
 error:
-       if (mbo)
-               most_put_mbo(mbo);
+       most_put_mbo(mbo);
        return err;
 }
 
@@ -224,18 +227,17 @@ aim_read(struct file *filp, char __user *buf, size_t count, loff_t *offset)
        struct mbo *mbo;
        struct aim_channel *channel = filp->private_data;
 
-       if (channel->keep_mbo == true) {
+       if (channel->keep_mbo) {
                mbo = channel->stacked_mbo;
                channel->keep_mbo = false;
                goto start_copy;
        }
-       while ((0 == kfifo_out(&channel->fifo, &mbo, 1))
-              && (channel->dev != NULL)) {
+       while ((!kfifo_out(&channel->fifo, &mbo, 1)) && (channel->dev)) {
                if (filp->f_flags & O_NONBLOCK)
                        return -EAGAIN;
                if (wait_event_interruptible(channel->wq,
                                             (!kfifo_is_empty(&channel->fifo) ||
-                                             (channel->dev == NULL))))
+                                             (!channel->dev))))
                        return -ERESTARTSYS;
        }
 
@@ -259,7 +261,7 @@ start_copy:
 
        retval = not_copied ? proc_len - not_copied : proc_len;
 
-       if (channel->keep_mbo == true) {
+       if (channel->keep_mbo) {
                channel->mbo_offs = retval;
                channel->stacked_mbo = mbo;
        } else {
@@ -270,6 +272,28 @@ start_copy:
        return retval;
 }
 
+static inline bool __must_check IS_ERR_OR_FALSE(int x)
+{
+       return x <= 0;
+}
+
+static unsigned int aim_poll(struct file *filp, poll_table *wait)
+{
+       struct aim_channel *c = filp->private_data;
+       unsigned int mask = 0;
+
+       poll_wait(filp, &c->wq, wait);
+
+       if (c->cfg->direction == MOST_CH_RX) {
+               if (!kfifo_is_empty(&c->fifo))
+                       mask |= POLLIN | POLLRDNORM;
+       } else {
+               if (!IS_ERR_OR_FALSE(channel_has_mbo(c->iface, c->channel_id)))
+                       mask |= POLLOUT | POLLWRNORM;
+       }
+       return mask;
+}
+
 /**
  * Initialization of struct file_operations
  */
@@ -279,6 +303,7 @@ static const struct file_operations channel_fops = {
        .write = aim_write,
        .open = aim_open,
        .release = aim_close,
+       .poll = aim_poll,
 };
 
 /**
@@ -300,7 +325,7 @@ static int aim_disconnect_channel(struct most_interface *iface, int channel_id)
        }
 
        channel = get_channel(iface, channel_id);
-       if (channel == NULL)
+       if (!channel)
                return -ENXIO;
 
        mutex_lock(&channel->io_mutex);
@@ -337,7 +362,7 @@ static int aim_rx_completion(struct mbo *mbo)
                return -EINVAL;
 
        channel = get_channel(mbo->ifp, mbo->hdm_channel_id);
-       if (channel == NULL)
+       if (!channel)
                return -ENXIO;
 
        kfifo_in(&channel->fifo, &mbo, 1);
@@ -370,7 +395,7 @@ static int aim_tx_completion(struct most_interface *iface, int channel_id)
        }
 
        channel = get_channel(iface, channel_id);
-       if (channel == NULL)
+       if (!channel)
                return -ENXIO;
        wake_up_interruptible(&channel->wq);
        return 0;
@@ -413,7 +438,6 @@ static int aim_probe(struct most_interface *iface, int channel_id,
 
        channel = kzalloc(sizeof(*channel), GFP_KERNEL);
        if (!channel) {
-               pr_info("failed to alloc channel object\n");
                retval = -ENOMEM;
                goto error_alloc_channel;
        }