Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.13.7.
  1#include <linux/slab.h>
  2#include <linux/kernel.h>
  3#include <linux/module.h>
  4#include <linux/device.h>
  5#include <linux/workqueue.h>
  6#include <linux/kfifo.h>
  7#include <linux/mutex.h>
  8#include <linux/iio/kfifo_buf.h>
  9#include <linux/sched.h>
 10#include <linux/poll.h>
 11
 12struct iio_kfifo {
 13	struct iio_buffer buffer;
 14	struct kfifo kf;
 15	struct mutex user_lock;
 16	int update_needed;
 17};
 18
 19#define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer)
 20
 21static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
 22				int bytes_per_datum, int length)
 23{
 24	if ((length == 0) || (bytes_per_datum == 0))
 25		return -EINVAL;
 26
 27	return __kfifo_alloc((struct __kfifo *)&buf->kf, length,
 28			     bytes_per_datum, GFP_KERNEL);
 29}
 30
 31static int iio_request_update_kfifo(struct iio_buffer *r)
 32{
 33	int ret = 0;
 34	struct iio_kfifo *buf = iio_to_kfifo(r);
 35
 36	mutex_lock(&buf->user_lock);
 37	if (buf->update_needed) {
 38		kfifo_free(&buf->kf);
 39		ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum,
 40				   buf->buffer.length);
 41		buf->update_needed = false;
 42	} else {
 43		kfifo_reset_out(&buf->kf);
 44	}
 45	mutex_unlock(&buf->user_lock);
 46
 47	return ret;
 48}
 49
 50static int iio_get_length_kfifo(struct iio_buffer *r)
 51{
 52	return r->length;
 53}
 54
 55static IIO_BUFFER_ENABLE_ATTR;
 56static IIO_BUFFER_LENGTH_ATTR;
 57
 58static struct attribute *iio_kfifo_attributes[] = {
 59	&dev_attr_length.attr,
 60	&dev_attr_enable.attr,
 61	NULL,
 62};
 63
 64static struct attribute_group iio_kfifo_attribute_group = {
 65	.attrs = iio_kfifo_attributes,
 66	.name = "buffer",
 67};
 68
 69static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
 70{
 71	return r->bytes_per_datum;
 72}
 73
 74static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
 75{
 76	struct iio_kfifo *kf = iio_to_kfifo(r);
 77	kf->update_needed = true;
 78	return 0;
 79}
 80
 81static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd)
 82{
 83	if (r->bytes_per_datum != bpd) {
 84		r->bytes_per_datum = bpd;
 85		iio_mark_update_needed_kfifo(r);
 86	}
 87	return 0;
 88}
 89
 90static int iio_set_length_kfifo(struct iio_buffer *r, int length)
 91{
 92	/* Avoid an invalid state */
 93	if (length < 2)
 94		length = 2;
 95	if (r->length != length) {
 96		r->length = length;
 97		iio_mark_update_needed_kfifo(r);
 98	}
 99	return 0;
100}
101
102static int iio_store_to_kfifo(struct iio_buffer *r,
103			      const void *data)
104{
105	int ret;
106	struct iio_kfifo *kf = iio_to_kfifo(r);
107	ret = kfifo_in(&kf->kf, data, 1);
108	if (ret != 1)
109		return -EBUSY;
110
111	wake_up_interruptible_poll(&r->pollq, POLLIN | POLLRDNORM);
112
113	return 0;
114}
115
116static int iio_read_first_n_kfifo(struct iio_buffer *r,
117			   size_t n, char __user *buf)
118{
119	int ret, copied;
120	struct iio_kfifo *kf = iio_to_kfifo(r);
121
122	if (mutex_lock_interruptible(&kf->user_lock))
123		return -ERESTARTSYS;
124
125	if (!kfifo_initialized(&kf->kf) || n < kfifo_esize(&kf->kf))
126		ret = -EINVAL;
127	else
128		ret = kfifo_to_user(&kf->kf, buf, n, &copied);
129	mutex_unlock(&kf->user_lock);
130	if (ret < 0)
131		return ret;
132
133	return copied;
134}
135
136static bool iio_kfifo_buf_data_available(struct iio_buffer *r)
137{
138	struct iio_kfifo *kf = iio_to_kfifo(r);
139	bool empty;
140
141	mutex_lock(&kf->user_lock);
142	empty = kfifo_is_empty(&kf->kf);
143	mutex_unlock(&kf->user_lock);
144
145	return !empty;
146}
147
148static void iio_kfifo_buffer_release(struct iio_buffer *buffer)
149{
150	struct iio_kfifo *kf = iio_to_kfifo(buffer);
151
152	mutex_destroy(&kf->user_lock);
153	kfifo_free(&kf->kf);
154	kfree(kf);
155}
156
157static const struct iio_buffer_access_funcs kfifo_access_funcs = {
158	.store_to = &iio_store_to_kfifo,
159	.read_first_n = &iio_read_first_n_kfifo,
160	.data_available = iio_kfifo_buf_data_available,
161	.request_update = &iio_request_update_kfifo,
162	.get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo,
163	.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
164	.get_length = &iio_get_length_kfifo,
165	.set_length = &iio_set_length_kfifo,
166	.release = &iio_kfifo_buffer_release,
167};
168
169struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
170{
171	struct iio_kfifo *kf;
172
173	kf = kzalloc(sizeof *kf, GFP_KERNEL);
174	if (!kf)
175		return NULL;
176	kf->update_needed = true;
177	iio_buffer_init(&kf->buffer);
178	kf->buffer.attrs = &iio_kfifo_attribute_group;
179	kf->buffer.access = &kfifo_access_funcs;
180	kf->buffer.length = 2;
181	mutex_init(&kf->user_lock);
182	return &kf->buffer;
183}
184EXPORT_SYMBOL(iio_kfifo_allocate);
185
186void iio_kfifo_free(struct iio_buffer *r)
187{
188	iio_buffer_put(r);
189}
190EXPORT_SYMBOL(iio_kfifo_free);
191
192MODULE_LICENSE("GPL");