/* The industrial I/O core
*
* Copyright (c) 2008 Jonathan Cameron
*
* 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.
*
* Handling of buffer allocation / resizing.
*
*
* Things to look at here.
* - Better memory allocation techniques?
* - Alternative access techniques?
*/
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/iio/iio.h>
#include "iio_core.h"
#include <linux/iio/sysfs.h>
#include <linux/iio/buffer.h>
static const char * const iio_endian_prefix[] = {
[IIO_BE] = "be",
[IIO_LE] = "le",
};
static bool iio_buffer_is_active(struct iio_buffer *buf)
{
return !list_empty(&buf->buffer_list);
}
static size_t iio_buffer_data_available(struct iio_buffer *buf)
{
return buf->access->data_available(buf);
}
static int iio_buffer_flush_hwfifo(struct iio_dev *indio_dev,
struct iio_buffer *buf, size_t required)
{
if (!indio_dev->info->hwfifo_flush_to_buffer)
return -ENODEV;
return indio_dev->info->hwfifo_flush_to_buffer(indio_dev, required);
}
static bool iio_buffer_ready(struct iio_dev *indio_dev, struct iio_buffer *buf,
size_t to_wait, int to_flush)
{
size_t avail;
int flushed = 0;
/* wakeup if the device was unregistered */
if (!indio_dev->info)
return true;
/* drain the buffer if it was disabled */
if (!iio_buffer_is_active(buf)) {
to_wait = min_t(size_t, to_wait, 1);
to_flush = 0;
}
avail = iio_buffer_data_available(buf);
if (avail >= to_wait) {
/* force a flush for non-blocking reads */
if (!to_wait && !avail && to_flush)
iio_buffer_flush_hwfifo(indio_dev, buf, to_flush);
return true;
}
if (to_flush)
flushed = iio_buffer_flush_hwfifo(indio_dev, buf,
to_wait - avail);
if (flushed <= 0)
return false;
if (avail + flushed >= to_wait)
return true;
return false;
}
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
*
* This function relies on all buffer implementations having an
* iio_buffer as their first element.
**/
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps)
{
struct iio_dev *indio_d