staging: most: add poll syscall to AIM cdev
authorChristian Gromm <christian.gromm@microchip.com>
Mon, 28 Sep 2015 15:18:57 +0000 (17:18 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 29 Sep 2015 01:18:53 +0000 (03:18 +0200)
This patch adds the implementation of the poll syscall to the AIM cdev.
To have the full functionality, a helper function is needed in the
core module to retrieve the instantaneous availability of tx buffers.

Signed-off-by: Christian Gromm <christian.gromm@microchip.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/staging/most/aim-cdev/cdev.c
drivers/staging/most/mostcore/core.c
drivers/staging/most/mostcore/mostcore.h

index 23c3f6e..930ada0 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>
@@ -31,6 +32,7 @@ static struct most_aim cdev_aim;
 
 struct aim_channel {
        wait_queue_head_t wq;
+       wait_queue_head_t poll_wq;
        struct cdev cdev;
        struct device *dev;
        struct mutex io_mutex;
@@ -271,6 +273,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->poll_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
  */
@@ -280,6 +304,7 @@ static const struct file_operations channel_fops = {
        .write = aim_write,
        .open = aim_open,
        .release = aim_close,
+       .poll = aim_poll,
 };
 
 /**
@@ -434,6 +459,7 @@ static int aim_probe(struct most_interface *iface, int channel_id,
                goto error_alloc_kfifo;
        }
        init_waitqueue_head(&channel->wq);
+       init_waitqueue_head(&channel->poll_wq);
        mutex_init(&channel->io_mutex);
        spin_lock_irqsave(&ch_list_lock, cl_flags);
        list_add_tail(&channel->list, &channel_list);
index ee6deb8..0045c10 100644 (file)
@@ -1383,6 +1383,22 @@ most_c_obj *get_channel_by_iface(struct most_interface *iface, int id)
        return i->channel[id];
 }
 
+int channel_has_mbo(struct most_interface *iface, int id)
+{
+       struct most_c_obj *c = get_channel_by_iface(iface, id);
+       unsigned long flags;
+       int empty;
+
+       if (unlikely(!c))
+               return -EINVAL;
+
+       spin_lock_irqsave(&c->fifo_lock, flags);
+       empty = list_empty(&c->fifo);
+       spin_unlock_irqrestore(&c->fifo_lock, flags);
+       return !empty;
+}
+EXPORT_SYMBOL_GPL(channel_has_mbo);
+
 /**
  * most_get_mbo - get pointer to an MBO of pool
  * @iface: pointer to interface instance
index 3c6fb19..9bd4c77 100644 (file)
@@ -311,6 +311,7 @@ int most_deregister_aim(struct most_aim *aim);
 struct mbo *most_get_mbo(struct most_interface *iface, int channel_idx,
                         struct most_aim *);
 void most_put_mbo(struct mbo *mbo);
+int channel_has_mbo(struct most_interface *iface, int channel_idx);
 int most_start_channel(struct most_interface *iface, int channel_idx,
                       struct most_aim *);
 int most_stop_channel(struct most_interface *iface, int channel_idx,