#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>
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;
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;
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;
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;
}
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;
}
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;
}
}
return actual_len - retval;
error:
- if (mbo)
- most_put_mbo(mbo);
+ most_put_mbo(mbo);
return err;
}
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;
}
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 {
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
*/
.write = aim_write,
.open = aim_open,
.release = aim_close,
+ .poll = aim_poll,
};
/**
}
channel = get_channel(iface, channel_id);
- if (channel == NULL)
+ if (!channel)
return -ENXIO;
mutex_lock(&channel->io_mutex);
return -EINVAL;
channel = get_channel(mbo->ifp, mbo->hdm_channel_id);
- if (channel == NULL)
+ if (!channel)
return -ENXIO;
kfifo_in(&channel->fifo, &mbo, 1);
}
channel = get_channel(iface, channel_id);
- if (channel == NULL)
+ if (!channel)
return -ENXIO;
wake_up_interruptible(&channel->wq);
return 0;
channel = kzalloc(sizeof(*channel), GFP_KERNEL);
if (!channel) {
- pr_info("failed to alloc channel object\n");
retval = -ENOMEM;
goto error_alloc_channel;
}