forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.9 KiB
156 lines
3.9 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* The industrial I/O callback buffer |
|
*/ |
|
|
|
#include <linux/kernel.h> |
|
#include <linux/module.h> |
|
#include <linux/slab.h> |
|
#include <linux/err.h> |
|
#include <linux/export.h> |
|
#include <linux/iio/iio.h> |
|
#include <linux/iio/buffer_impl.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; |
|
struct iio_dev *indio_dev; |
|
}; |
|
|
|
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); |
|
|
|
bitmap_free(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_channel *chan; |
|
|
|
if (!cb) { |
|
dev_err(dev, "Invalid arguments: A callback must be provided!\n"); |
|
return ERR_PTR(-EINVAL); |
|
} |
|
|
|
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; |
|
} |
|
|
|
cb_buff->indio_dev = cb_buff->channels[0].indio_dev; |
|
cb_buff->buffer.scan_mask = bitmap_zalloc(cb_buff->indio_dev->masklength, |
|
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 != cb_buff->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: |
|
bitmap_free(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_cb_set_buffer_watermark(struct iio_cb_buffer *cb_buff, |
|
size_t watermark) |
|
{ |
|
if (!watermark) |
|
return -EINVAL; |
|
cb_buff->buffer.watermark = watermark; |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL_GPL(iio_channel_cb_set_buffer_watermark); |
|
|
|
int iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff) |
|
{ |
|
return iio_update_buffers(cb_buff->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->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); |
|
|
|
struct iio_dev |
|
*iio_channel_cb_get_iio_dev(const struct iio_cb_buffer *cb_buffer) |
|
{ |
|
return cb_buffer->indio_dev; |
|
} |
|
EXPORT_SYMBOL_GPL(iio_channel_cb_get_iio_dev); |
|
|
|
MODULE_AUTHOR("Jonathan Cameron <[email protected]>"); |
|
MODULE_DESCRIPTION("Industrial I/O callback buffer"); |
|
MODULE_LICENSE("GPL");
|
|
|