aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/most
diff options
context:
space:
mode:
authorChristian Gromm <christian.gromm@microchip.com>2015-09-28 17:18:57 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-09-29 03:18:53 +0200
commitaac997dfdd58eec1add02dae09030caeddc1abe6 (patch)
tree16d2ce84c89c921396744775d76ad0a4b24f70d8 /drivers/staging/most
parentstaging: most: remove audio resolution format check (diff)
downloadlinux-dev-aac997dfdd58eec1add02dae09030caeddc1abe6.tar.xz
linux-dev-aac997dfdd58eec1add02dae09030caeddc1abe6.zip
staging: most: add poll syscall to AIM cdev
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>
Diffstat (limited to 'drivers/staging/most')
-rw-r--r--drivers/staging/most/aim-cdev/cdev.c26
-rw-r--r--drivers/staging/most/mostcore/core.c16
-rw-r--r--drivers/staging/most/mostcore/mostcore.h1
3 files changed, 43 insertions, 0 deletions
diff --git a/drivers/staging/most/aim-cdev/cdev.c b/drivers/staging/most/aim-cdev/cdev.c
index 23c3f6e7340c..930ada0922f3 100644
--- a/drivers/staging/most/aim-cdev/cdev.c
+++ b/drivers/staging/most/aim-cdev/cdev.c
@@ -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);
diff --git a/drivers/staging/most/mostcore/core.c b/drivers/staging/most/mostcore/core.c
index ee6deb884aad..0045c10413eb 100644
--- a/drivers/staging/most/mostcore/core.c
+++ b/drivers/staging/most/mostcore/core.c
@@ -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
diff --git a/drivers/staging/most/mostcore/mostcore.h b/drivers/staging/most/mostcore/mostcore.h
index 3c6fb19aaa3b..9bd4c779f1b6 100644
--- a/drivers/staging/most/mostcore/mostcore.h
+++ b/drivers/staging/most/mostcore/mostcore.h
@@ -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,