From aac997dfdd58eec1add02dae09030caeddc1abe6 Mon Sep 17 00:00:00 2001 From: Christian Gromm Date: Mon, 28 Sep 2015 17:18:57 +0200 Subject: [PATCH] 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 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/most/aim-cdev/cdev.c | 26 ++++++++++++++++++++++++ drivers/staging/most/mostcore/core.c | 16 +++++++++++++++ drivers/staging/most/mostcore/mostcore.h | 1 + 3 files changed, 43 insertions(+) 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 #include #include +#include #include #include #include @@ -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, -- 2.30.2