aboutsummaryrefslogtreecommitdiff
path: root/drivers/iio/kfifo_buf.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/kfifo_buf.c')
-rw-r--r--drivers/iio/kfifo_buf.c66
1 files changed, 47 insertions, 19 deletions
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index a923c78d5cb..7134e8ada09 100644
--- a/drivers/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -7,10 +7,12 @@
#include <linux/mutex.h>
#include <linux/iio/kfifo_buf.h>
#include <linux/sched.h>
+#include <linux/poll.h>
struct iio_kfifo {
struct iio_buffer buffer;
struct kfifo kf;
+ struct mutex user_lock;
int update_needed;
};
@@ -31,13 +33,17 @@ static int iio_request_update_kfifo(struct iio_buffer *r)
int ret = 0;
struct iio_kfifo *buf = iio_to_kfifo(r);
- if (!buf->update_needed)
- goto error_ret;
- kfifo_free(&buf->kf);
- ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
+ mutex_lock(&buf->user_lock);
+ if (buf->update_needed) {
+ kfifo_free(&buf->kf);
+ ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
buf->buffer.length);
- r->stufftoread = false;
-error_ret:
+ buf->update_needed = false;
+ } else {
+ kfifo_reset_out(&buf->kf);
+ }
+ mutex_unlock(&buf->user_lock);
+
return ret;
}
@@ -94,15 +100,15 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length)
}
static int iio_store_to_kfifo(struct iio_buffer *r,
- u8 *data)
+ const void *data)
{
int ret;
struct iio_kfifo *kf = iio_to_kfifo(r);
ret = kfifo_in(&kf->kf, data, 1);
if (ret != 1)
return -EBUSY;
- r->stufftoread = true;
- wake_up_interruptible(&r->pollq);
+
+ wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
return 0;
}
@@ -113,30 +119,51 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
int ret, copied;
struct iio_kfifo *kf = iio_to_kfifo(r);
- if (n < r->bytes_per_datum || r->bytes_per_datum == 0)
- return -EINVAL;
+ if (mutex_lock_interruptible(&kf->user_lock))
+ return -ERESTARTSYS;
- ret = kfifo_to_user(&kf->kf, buf, n, &copied);
+ if (!kfifo_initialized(&kf->kf) || n < kfifo_esize(&kf->kf))
+ ret = -EINVAL;
+ else
+ ret = kfifo_to_user(&kf->kf, buf, n, &copied);
+ mutex_unlock(&kf->user_lock);
if (ret < 0)
return ret;
- if (kfifo_is_empty(&kf->kf))
- r->stufftoread = false;
- /* verify it is still empty to avoid race */
- if (!kfifo_is_empty(&kf->kf))
- r->stufftoread = true;
-
return copied;
}
+static bool iio_kfifo_buf_data_available(struct iio_buffer *r)
+{
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+ bool empty;
+
+ mutex_lock(&kf->user_lock);
+ empty = kfifo_is_empty(&kf->kf);
+ mutex_unlock(&kf->user_lock);
+
+ return !empty;
+}
+
+static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
+{
+ struct iio_kfifo *kf = iio_to_kfifo(buffer);
+
+ mutex_destroy(&kf->user_lock);
+ kfifo_free(&kf->kf);
+ kfree(kf);
+}
+
static const struct iio_buffer_access_funcs kfifo_access_funcs = {
.store_to = &iio_store_to_kfifo,
.read_first_n = &iio_read_first_n_kfifo,
+ .data_available = iio_kfifo_buf_data_available,
.request_update = &iio_request_update_kfifo,
.get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo,
.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
.get_length = &iio_get_length_kfifo,
.set_length = &iio_set_length_kfifo,
+ .release = &iio_kfifo_buffer_release,
};
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
@@ -151,13 +178,14 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
kf->buffer.attrs = &iio_kfifo_attribute_group;
kf->buffer.access = &kfifo_access_funcs;
kf->buffer.length = 2;
+ mutex_init(&kf->user_lock);
return &kf->buffer;
}
EXPORT_SYMBOL(iio_kfifo_allocate);
void iio_kfifo_free(struct iio_buffer *r)
{
- kfree(iio_to_kfifo(r));
+ iio_buffer_put(r);
}
EXPORT_SYMBOL(iio_kfifo_free);