work together.
</para>
<sect2 id="iiotrigbufsetup"> <title> IIO triggered buffer setup</title>
-!Edrivers/iio/industrialio-triggered-buffer.c
+!Edrivers/iio/buffer/industrialio-triggered-buffer.c
!Finclude/linux/iio/iio.h iio_buffer_setup_ops
acquisition methods.
if IIO_BUFFER
-
-config IIO_BUFFER_CB
- tristate "IIO callback buffer used for push in-kernel interfaces"
- help
- Should be selected by any drivers that do in-kernel push
- usage. That is, those where the data is pushed to the consumer.
-
-config IIO_KFIFO_BUF
- tristate "Industrial I/O buffering based on kfifo"
- help
- A simple fifo based on kfifo. Note that this currently provides
- no buffer events so it is up to userspace to work out how
- often to read from the buffer.
-
-config IIO_TRIGGERED_BUFFER
- tristate
- select IIO_TRIGGER
- select IIO_KFIFO_BUF
- help
- Provides helper functions for setting up triggered buffers.
-
+ source "drivers/iio/buffer/Kconfig"
endif # IIO_BUFFER
config IIO_TRIGGER
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
-obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
-obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
-obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
-
obj-y += accel/
obj-y += adc/
obj-y += amplifiers/
+obj-y += buffer/
obj-y += common/
obj-y += dac/
obj-y += gyro/
--- /dev/null
+#
+# Industrial I/O generic buffer implementations
+#
+# When adding new entries keep the list in alphabetical order
+
+config IIO_BUFFER_CB
+ tristate "IIO callback buffer used for push in-kernel interfaces"
+ help
+ Should be selected by any drivers that do in-kernel push
+ usage. That is, those where the data is pushed to the consumer.
+
+config IIO_KFIFO_BUF
+ tristate "Industrial I/O buffering based on kfifo"
+ help
+ A simple fifo based on kfifo. Note that this currently provides
+ no buffer events so it is up to userspace to work out how
+ often to read from the buffer.
+
+config IIO_TRIGGERED_BUFFER
+ tristate
+ select IIO_TRIGGER
+ select IIO_KFIFO_BUF
+ help
+ Provides helper functions for setting up triggered buffers.
--- /dev/null
+#
+# Makefile for the industrial I/O buffer implementations
+#
+
+# When adding new entries keep the list in alphabetical order
+obj-$(CONFIG_IIO_BUFFER_CB) += industrialio-buffer-cb.o
+obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o
+obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
--- /dev/null
+/* The industrial I/O callback buffer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/export.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/consumer.h>
+
+struct iio_cb_buffer {
+ struct iio_buffer buffer;
+ int (*cb)(const void *data, void *private);
+ void *private;
+ struct iio_channel *channels;
+};
+
+static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer)
+{
+ return container_of(buffer, struct iio_cb_buffer, buffer);
+}
+
+static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data)
+{
+ struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
+ return cb_buff->cb(data, cb_buff->private);
+}
+
+static void iio_buffer_cb_release(struct iio_buffer *buffer)
+{
+ struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
+ kfree(cb_buff->buffer.scan_mask);
+ kfree(cb_buff);
+}
+
+static const struct iio_buffer_access_funcs iio_cb_access = {
+ .store_to = &iio_buffer_cb_store_to,
+ .release = &iio_buffer_cb_release,
+
+ .modes = INDIO_BUFFER_SOFTWARE | INDIO_BUFFER_TRIGGERED,
+};
+
+struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
+ int (*cb)(const void *data,
+ void *private),
+ void *private)
+{
+ int ret;
+ struct iio_cb_buffer *cb_buff;
+ struct iio_dev *indio_dev;
+ struct iio_channel *chan;
+
+ cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
+ if (cb_buff == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ iio_buffer_init(&cb_buff->buffer);
+
+ cb_buff->private = private;
+ cb_buff->cb = cb;
+ cb_buff->buffer.access = &iio_cb_access;
+ INIT_LIST_HEAD(&cb_buff->buffer.demux_list);
+
+ cb_buff->channels = iio_channel_get_all(dev);
+ if (IS_ERR(cb_buff->channels)) {
+ ret = PTR_ERR(cb_buff->channels);
+ goto error_free_cb_buff;
+ }
+
+ indio_dev = cb_buff->channels[0].indio_dev;
+ cb_buff->buffer.scan_mask
+ = kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long),
+ GFP_KERNEL);
+ if (cb_buff->buffer.scan_mask == NULL) {
+ ret = -ENOMEM;
+ goto error_release_channels;
+ }
+ chan = &cb_buff->channels[0];
+ while (chan->indio_dev) {
+ if (chan->indio_dev != indio_dev) {
+ ret = -EINVAL;
+ goto error_free_scan_mask;
+ }
+ set_bit(chan->channel->scan_index,
+ cb_buff->buffer.scan_mask);
+ chan++;
+ }
+
+ return cb_buff;
+
+error_free_scan_mask:
+ kfree(cb_buff->buffer.scan_mask);
+error_release_channels:
+ iio_channel_release_all(cb_buff->channels);
+error_free_cb_buff:
+ kfree(cb_buff);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
+
+int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff)
+{
+ return iio_update_buffers(cb_buff->channels[0].indio_dev,
+ &cb_buff->buffer,
+ NULL);
+}
+EXPORT_SYMBOL_GPL(iio_channel_start_all_cb);
+
+void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff)
+{
+ iio_update_buffers(cb_buff->channels[0].indio_dev,
+ NULL,
+ &cb_buff->buffer);
+}
+EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
+
+void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff)
+{
+ iio_channel_release_all(cb_buff->channels);
+ iio_buffer_put(&cb_buff->buffer);
+}
+EXPORT_SYMBOL_GPL(iio_channel_release_all_cb);
+
+struct iio_channel
+*iio_channel_cb_get_channels(const struct iio_cb_buffer *cb_buffer)
+{
+ return cb_buffer->channels;
+}
+EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
+MODULE_DESCRIPTION("Industrial I/O callback buffer");
+MODULE_LICENSE("GPL");
--- /dev/null
+ /*
+ * Copyright (c) 2012 Analog Devices, Inc.
+ * Author: Lars-Peter Clausen <lars@metafoo.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/export.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
+ .postenable = &iio_triggered_buffer_postenable,
+ .predisable = &iio_triggered_buffer_predisable,
+};
+
+/**
+ * iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc
+ * @indio_dev: IIO device structure
+ * @h: Function which will be used as pollfunc top half
+ * @thread: Function which will be used as pollfunc bottom half
+ * @setup_ops: Buffer setup functions to use for this device.
+ * If NULL the default setup functions for triggered
+ * buffers will be used.
+ *
+ * This function combines some common tasks which will normally be performed
+ * when setting up a triggered buffer. It will allocate the buffer and the
+ * pollfunc.
+ *
+ * Before calling this function the indio_dev structure should already be
+ * completely initialized, but not yet registered. In practice this means that
+ * this function should be called right before iio_device_register().
+ *
+ * To free the resources allocated by this function call
+ * iio_triggered_buffer_cleanup().
+ */
+int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
+ irqreturn_t (*h)(int irq, void *p),
+ irqreturn_t (*thread)(int irq, void *p),
+ const struct iio_buffer_setup_ops *setup_ops)
+{
+ struct iio_buffer *buffer;
+ int ret;
+
+ buffer = iio_kfifo_allocate();
+ if (!buffer) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ iio_device_attach_buffer(indio_dev, buffer);
+
+ indio_dev->pollfunc = iio_alloc_pollfunc(h,
+ thread,
+ IRQF_ONESHOT,
+ indio_dev,
+ "%s_consumer%d",
+ indio_dev->name,
+ indio_dev->id);
+ if (indio_dev->pollfunc == NULL) {
+ ret = -ENOMEM;
+ goto error_kfifo_free;
+ }
+
+ /* Ring buffer functions - here trigger setup related */
+ if (setup_ops)
+ indio_dev->setup_ops = setup_ops;
+ else
+ indio_dev->setup_ops = &iio_triggered_buffer_setup_ops;
+
+ /* Flag that polled ring buffering is possible */
+ indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
+
+ return 0;
+
+error_kfifo_free:
+ iio_kfifo_free(indio_dev->buffer);
+error_ret:
+ return ret;
+}
+EXPORT_SYMBOL(iio_triggered_buffer_setup);
+
+/**
+ * iio_triggered_buffer_cleanup() - Free resources allocated by iio_triggered_buffer_setup()
+ * @indio_dev: IIO device structure
+ */
+void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
+{
+ iio_dealloc_pollfunc(indio_dev->pollfunc);
+ iio_kfifo_free(indio_dev->buffer);
+}
+EXPORT_SYMBOL(iio_triggered_buffer_cleanup);
+
+MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
+MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers");
+MODULE_LICENSE("GPL");
--- /dev/null
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/kfifo.h>
+#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;
+};
+
+#define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer)
+
+static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
+ int bytes_per_datum, int length)
+{
+ if ((length == 0) || (bytes_per_datum == 0))
+ return -EINVAL;
+
+ return __kfifo_alloc((struct __kfifo *)&buf->kf, length,
+ bytes_per_datum, GFP_KERNEL);
+}
+
+static int iio_request_update_kfifo(struct iio_buffer *r)
+{
+ int ret = 0;
+ struct iio_kfifo *buf = iio_to_kfifo(r);
+
+ 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);
+ if (ret >= 0)
+ buf->update_needed = false;
+ } else {
+ kfifo_reset_out(&buf->kf);
+ }
+ mutex_unlock(&buf->user_lock);
+
+ return ret;
+}
+
+static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
+{
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+ kf->update_needed = true;
+ return 0;
+}
+
+static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd)
+{
+ if (r->bytes_per_datum != bpd) {
+ r->bytes_per_datum = bpd;
+ iio_mark_update_needed_kfifo(r);
+ }
+ return 0;
+}
+
+static int iio_set_length_kfifo(struct iio_buffer *r, int length)
+{
+ /* Avoid an invalid state */
+ if (length < 2)
+ length = 2;
+ if (r->length != length) {
+ r->length = length;
+ iio_mark_update_needed_kfifo(r);
+ }
+ return 0;
+}
+
+static int iio_store_to_kfifo(struct iio_buffer *r,
+ 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;
+ return 0;
+}
+
+static int iio_read_first_n_kfifo(struct iio_buffer *r,
+ size_t n, char __user *buf)
+{
+ int ret, copied;
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+
+ if (mutex_lock_interruptible(&kf->user_lock))
+ return -ERESTARTSYS;
+
+ 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;
+
+ return copied;
+}
+
+static size_t iio_kfifo_buf_data_available(struct iio_buffer *r)
+{
+ struct iio_kfifo *kf = iio_to_kfifo(r);
+ size_t samples;
+
+ mutex_lock(&kf->user_lock);
+ samples = kfifo_len(&kf->kf);
+ mutex_unlock(&kf->user_lock);
+
+ return samples;
+}
+
+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,
+ .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
+ .set_length = &iio_set_length_kfifo,
+ .release = &iio_kfifo_buffer_release,
+
+ .modes = INDIO_BUFFER_SOFTWARE | INDIO_BUFFER_TRIGGERED,
+};
+
+struct iio_buffer *iio_kfifo_allocate(void)
+{
+ struct iio_kfifo *kf;
+
+ kf = kzalloc(sizeof(*kf), GFP_KERNEL);
+ if (!kf)
+ return NULL;
+
+ kf->update_needed = true;
+ iio_buffer_init(&kf->buffer);
+ 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)
+{
+ iio_buffer_put(r);
+}
+EXPORT_SYMBOL(iio_kfifo_free);
+
+static void devm_iio_kfifo_release(struct device *dev, void *res)
+{
+ iio_kfifo_free(*(struct iio_buffer **)res);
+}
+
+static int devm_iio_kfifo_match(struct device *dev, void *res, void *data)
+{
+ struct iio_buffer **r = res;
+
+ if (WARN_ON(!r || !*r))
+ return 0;
+
+ return *r == data;
+}
+
+/**
+ * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate()
+ * @dev: Device to allocate kfifo buffer for
+ *
+ * RETURNS:
+ * Pointer to allocated iio_buffer on success, NULL on failure.
+ */
+struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
+{
+ struct iio_buffer **ptr, *r;
+
+ ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ r = iio_kfifo_allocate();
+ if (r) {
+ *ptr = r;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(devm_iio_kfifo_allocate);
+
+/**
+ * devm_iio_fifo_free - Resource-managed iio_kfifo_free()
+ * @dev: Device the buffer belongs to
+ * @r: The buffer associated with the device
+ */
+void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r)
+{
+ WARN_ON(devres_release(dev, devm_iio_kfifo_release,
+ devm_iio_kfifo_match, r));
+}
+EXPORT_SYMBOL(devm_iio_kfifo_free);
+
+MODULE_LICENSE("GPL");
+++ /dev/null
-/* The industrial I/O callback buffer
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/iio/buffer.h>
-#include <linux/iio/consumer.h>
-
-struct iio_cb_buffer {
- struct iio_buffer buffer;
- int (*cb)(const void *data, void *private);
- void *private;
- struct iio_channel *channels;
-};
-
-static struct iio_cb_buffer *buffer_to_cb_buffer(struct iio_buffer *buffer)
-{
- return container_of(buffer, struct iio_cb_buffer, buffer);
-}
-
-static int iio_buffer_cb_store_to(struct iio_buffer *buffer, const void *data)
-{
- struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
- return cb_buff->cb(data, cb_buff->private);
-}
-
-static void iio_buffer_cb_release(struct iio_buffer *buffer)
-{
- struct iio_cb_buffer *cb_buff = buffer_to_cb_buffer(buffer);
- kfree(cb_buff->buffer.scan_mask);
- kfree(cb_buff);
-}
-
-static const struct iio_buffer_access_funcs iio_cb_access = {
- .store_to = &iio_buffer_cb_store_to,
- .release = &iio_buffer_cb_release,
-
- .modes = INDIO_BUFFER_SOFTWARE | INDIO_BUFFER_TRIGGERED,
-};
-
-struct iio_cb_buffer *iio_channel_get_all_cb(struct device *dev,
- int (*cb)(const void *data,
- void *private),
- void *private)
-{
- int ret;
- struct iio_cb_buffer *cb_buff;
- struct iio_dev *indio_dev;
- struct iio_channel *chan;
-
- cb_buff = kzalloc(sizeof(*cb_buff), GFP_KERNEL);
- if (cb_buff == NULL)
- return ERR_PTR(-ENOMEM);
-
- iio_buffer_init(&cb_buff->buffer);
-
- cb_buff->private = private;
- cb_buff->cb = cb;
- cb_buff->buffer.access = &iio_cb_access;
- INIT_LIST_HEAD(&cb_buff->buffer.demux_list);
-
- cb_buff->channels = iio_channel_get_all(dev);
- if (IS_ERR(cb_buff->channels)) {
- ret = PTR_ERR(cb_buff->channels);
- goto error_free_cb_buff;
- }
-
- indio_dev = cb_buff->channels[0].indio_dev;
- cb_buff->buffer.scan_mask
- = kcalloc(BITS_TO_LONGS(indio_dev->masklength), sizeof(long),
- GFP_KERNEL);
- if (cb_buff->buffer.scan_mask == NULL) {
- ret = -ENOMEM;
- goto error_release_channels;
- }
- chan = &cb_buff->channels[0];
- while (chan->indio_dev) {
- if (chan->indio_dev != indio_dev) {
- ret = -EINVAL;
- goto error_free_scan_mask;
- }
- set_bit(chan->channel->scan_index,
- cb_buff->buffer.scan_mask);
- chan++;
- }
-
- return cb_buff;
-
-error_free_scan_mask:
- kfree(cb_buff->buffer.scan_mask);
-error_release_channels:
- iio_channel_release_all(cb_buff->channels);
-error_free_cb_buff:
- kfree(cb_buff);
- return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
-
-int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff)
-{
- return iio_update_buffers(cb_buff->channels[0].indio_dev,
- &cb_buff->buffer,
- NULL);
-}
-EXPORT_SYMBOL_GPL(iio_channel_start_all_cb);
-
-void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff)
-{
- iio_update_buffers(cb_buff->channels[0].indio_dev,
- NULL,
- &cb_buff->buffer);
-}
-EXPORT_SYMBOL_GPL(iio_channel_stop_all_cb);
-
-void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buff)
-{
- iio_channel_release_all(cb_buff->channels);
- iio_buffer_put(&cb_buff->buffer);
-}
-EXPORT_SYMBOL_GPL(iio_channel_release_all_cb);
-
-struct iio_channel
-*iio_channel_cb_get_channels(const struct iio_cb_buffer *cb_buffer)
-{
- return cb_buffer->channels;
-}
-EXPORT_SYMBOL_GPL(iio_channel_cb_get_channels);
-
-MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
-MODULE_DESCRIPTION("Industrial I/O callback buffer");
-MODULE_LICENSE("GPL");
+++ /dev/null
- /*
- * Copyright (c) 2012 Analog Devices, Inc.
- * Author: Lars-Peter Clausen <lars@metafoo.de>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/module.h>
-#include <linux/iio/iio.h>
-#include <linux/iio/buffer.h>
-#include <linux/iio/kfifo_buf.h>
-#include <linux/iio/triggered_buffer.h>
-#include <linux/iio/trigger_consumer.h>
-
-static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
- .postenable = &iio_triggered_buffer_postenable,
- .predisable = &iio_triggered_buffer_predisable,
-};
-
-/**
- * iio_triggered_buffer_setup() - Setup triggered buffer and pollfunc
- * @indio_dev: IIO device structure
- * @h: Function which will be used as pollfunc top half
- * @thread: Function which will be used as pollfunc bottom half
- * @setup_ops: Buffer setup functions to use for this device.
- * If NULL the default setup functions for triggered
- * buffers will be used.
- *
- * This function combines some common tasks which will normally be performed
- * when setting up a triggered buffer. It will allocate the buffer and the
- * pollfunc.
- *
- * Before calling this function the indio_dev structure should already be
- * completely initialized, but not yet registered. In practice this means that
- * this function should be called right before iio_device_register().
- *
- * To free the resources allocated by this function call
- * iio_triggered_buffer_cleanup().
- */
-int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
- irqreturn_t (*h)(int irq, void *p),
- irqreturn_t (*thread)(int irq, void *p),
- const struct iio_buffer_setup_ops *setup_ops)
-{
- struct iio_buffer *buffer;
- int ret;
-
- buffer = iio_kfifo_allocate();
- if (!buffer) {
- ret = -ENOMEM;
- goto error_ret;
- }
-
- iio_device_attach_buffer(indio_dev, buffer);
-
- indio_dev->pollfunc = iio_alloc_pollfunc(h,
- thread,
- IRQF_ONESHOT,
- indio_dev,
- "%s_consumer%d",
- indio_dev->name,
- indio_dev->id);
- if (indio_dev->pollfunc == NULL) {
- ret = -ENOMEM;
- goto error_kfifo_free;
- }
-
- /* Ring buffer functions - here trigger setup related */
- if (setup_ops)
- indio_dev->setup_ops = setup_ops;
- else
- indio_dev->setup_ops = &iio_triggered_buffer_setup_ops;
-
- /* Flag that polled ring buffering is possible */
- indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
-
- return 0;
-
-error_kfifo_free:
- iio_kfifo_free(indio_dev->buffer);
-error_ret:
- return ret;
-}
-EXPORT_SYMBOL(iio_triggered_buffer_setup);
-
-/**
- * iio_triggered_buffer_cleanup() - Free resources allocated by iio_triggered_buffer_setup()
- * @indio_dev: IIO device structure
- */
-void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
-{
- iio_dealloc_pollfunc(indio_dev->pollfunc);
- iio_kfifo_free(indio_dev->buffer);
-}
-EXPORT_SYMBOL(iio_triggered_buffer_cleanup);
-
-MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
-MODULE_DESCRIPTION("IIO helper functions for setting up triggered buffers");
-MODULE_LICENSE("GPL");
+++ /dev/null
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/workqueue.h>
-#include <linux/kfifo.h>
-#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;
-};
-
-#define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer)
-
-static inline int __iio_allocate_kfifo(struct iio_kfifo *buf,
- int bytes_per_datum, int length)
-{
- if ((length == 0) || (bytes_per_datum == 0))
- return -EINVAL;
-
- return __kfifo_alloc((struct __kfifo *)&buf->kf, length,
- bytes_per_datum, GFP_KERNEL);
-}
-
-static int iio_request_update_kfifo(struct iio_buffer *r)
-{
- int ret = 0;
- struct iio_kfifo *buf = iio_to_kfifo(r);
-
- 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);
- if (ret >= 0)
- buf->update_needed = false;
- } else {
- kfifo_reset_out(&buf->kf);
- }
- mutex_unlock(&buf->user_lock);
-
- return ret;
-}
-
-static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
-{
- struct iio_kfifo *kf = iio_to_kfifo(r);
- kf->update_needed = true;
- return 0;
-}
-
-static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd)
-{
- if (r->bytes_per_datum != bpd) {
- r->bytes_per_datum = bpd;
- iio_mark_update_needed_kfifo(r);
- }
- return 0;
-}
-
-static int iio_set_length_kfifo(struct iio_buffer *r, int length)
-{
- /* Avoid an invalid state */
- if (length < 2)
- length = 2;
- if (r->length != length) {
- r->length = length;
- iio_mark_update_needed_kfifo(r);
- }
- return 0;
-}
-
-static int iio_store_to_kfifo(struct iio_buffer *r,
- 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;
- return 0;
-}
-
-static int iio_read_first_n_kfifo(struct iio_buffer *r,
- size_t n, char __user *buf)
-{
- int ret, copied;
- struct iio_kfifo *kf = iio_to_kfifo(r);
-
- if (mutex_lock_interruptible(&kf->user_lock))
- return -ERESTARTSYS;
-
- 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;
-
- return copied;
-}
-
-static size_t iio_kfifo_buf_data_available(struct iio_buffer *r)
-{
- struct iio_kfifo *kf = iio_to_kfifo(r);
- size_t samples;
-
- mutex_lock(&kf->user_lock);
- samples = kfifo_len(&kf->kf);
- mutex_unlock(&kf->user_lock);
-
- return samples;
-}
-
-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,
- .set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
- .set_length = &iio_set_length_kfifo,
- .release = &iio_kfifo_buffer_release,
-
- .modes = INDIO_BUFFER_SOFTWARE | INDIO_BUFFER_TRIGGERED,
-};
-
-struct iio_buffer *iio_kfifo_allocate(void)
-{
- struct iio_kfifo *kf;
-
- kf = kzalloc(sizeof(*kf), GFP_KERNEL);
- if (!kf)
- return NULL;
-
- kf->update_needed = true;
- iio_buffer_init(&kf->buffer);
- 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)
-{
- iio_buffer_put(r);
-}
-EXPORT_SYMBOL(iio_kfifo_free);
-
-static void devm_iio_kfifo_release(struct device *dev, void *res)
-{
- iio_kfifo_free(*(struct iio_buffer **)res);
-}
-
-static int devm_iio_kfifo_match(struct device *dev, void *res, void *data)
-{
- struct iio_buffer **r = res;
-
- if (WARN_ON(!r || !*r))
- return 0;
-
- return *r == data;
-}
-
-/**
- * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate()
- * @dev: Device to allocate kfifo buffer for
- *
- * RETURNS:
- * Pointer to allocated iio_buffer on success, NULL on failure.
- */
-struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
-{
- struct iio_buffer **ptr, *r;
-
- ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
- if (!ptr)
- return NULL;
-
- r = iio_kfifo_allocate();
- if (r) {
- *ptr = r;
- devres_add(dev, ptr);
- } else {
- devres_free(ptr);
- }
-
- return r;
-}
-EXPORT_SYMBOL(devm_iio_kfifo_allocate);
-
-/**
- * devm_iio_fifo_free - Resource-managed iio_kfifo_free()
- * @dev: Device the buffer belongs to
- * @r: The buffer associated with the device
- */
-void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r)
-{
- WARN_ON(devres_release(dev, devm_iio_kfifo_release,
- devm_iio_kfifo_match, r));
-}
-EXPORT_SYMBOL(devm_iio_kfifo_free);
-
-MODULE_LICENSE("GPL");