diff options
Diffstat (limited to 'drivers/iio/kfifo_buf.c')
-rw-r--r-- | drivers/iio/kfifo_buf.c | 49 |
1 files changed, 36 insertions, 13 deletions
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index a923c78d5cb..95c6fc81c2c 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,18 @@ 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); + buf->update_needed = false; + } else { + kfifo_reset_out(&buf->kf); + } r->stufftoread = false; -error_ret: + mutex_unlock(&buf->user_lock); + return ret; } @@ -94,7 +101,7 @@ 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); @@ -102,7 +109,7 @@ static int iio_store_to_kfifo(struct iio_buffer *r, if (ret != 1) return -EBUSY; r->stufftoread = true; - wake_up_interruptible(&r->pollq); + wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM); return 0; } @@ -113,12 +120,13 @@ 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 (ret < 0) - return ret; + if (!kfifo_initialized(&kf->kf) || n < kfifo_esize(&kf->kf)) + ret = -EINVAL; + else + ret = kfifo_to_user(&kf->kf, buf, n, &copied); if (kfifo_is_empty(&kf->kf)) r->stufftoread = false; @@ -126,9 +134,22 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, if (!kfifo_is_empty(&kf->kf)) r->stufftoread = true; + mutex_unlock(&kf->user_lock); + if (ret < 0) + return ret; + return copied; } +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, @@ -137,6 +158,7 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = { .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 +173,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); |