* [PATCH 0/4 V2] staging:iio: Add support for multiple buffers
@ 2012-05-30 19:36 Jonathan Cameron
2012-05-30 19:36 ` [PATCH 1/4] " Jonathan Cameron
` (3 more replies)
0 siblings, 4 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-05-30 19:36 UTC (permalink / raw)
To: linux-iio; +Cc: Jonathan Cameron
This is basically a rebase of the series from a few months back.
I held this one off as it's 'interesting and invasive'.
Basically this adds a level of indirection to the path between
the hardware and the software buffers. This allows us to have
multiple buffers each with their own demuxer. Clearly the
hardware has to be configured to provide all the channels
anyone is interested in, but then the flow looks something like.
Data ---> Demux1 ---> subset of data --> buffer1
|
-------> Demux2 ---> subset of data --> buffer2.
Note the demuxers should be very nearly transparent
if all the data is going on to the relevant buffer.
So you may ask ' Why?' In short - it allows us to
do clean data flow to multiple consumers such as an
IIO buffer, input, hwmon etc for devices running in
an trigger driven mode.
I also have a few thoughts on basic in kernel filtering
dependent on new buffer implementations.
Anyhow. Whilst the patch is relatively large it mostly
boils down to code for tearing down all current buffers,
reconfiguring the device and then building them all back
up again.
The input driver shoes the sort of client we might have.
(It probably needs more work) I'd like to get the
first three patches in the linux-next asap so they
get lots of testing prior to the next merge window.
Hence if anyone has time to take a look that would be
great!
Jonathan
Jonathan Cameron (4):
staging:iio: Add support for multiple buffers
staging:iio:in kernel users: Add a data field for channel specific
info.
staging:iio: add a callback buffer for in kernel push interface
staging:iio: Proof of concept input driver.
drivers/iio/Kconfig | 6 +
drivers/iio/Makefile | 1 +
drivers/iio/buffer_cb.c | 115 ++++++++
drivers/iio/industrialio-buffer.c | 335 +++++++++++++++--------
drivers/iio/industrialio-core.c | 1 +
drivers/iio/inkern.c | 1 +
drivers/staging/iio/Kconfig | 11 +
drivers/staging/iio/Makefile | 1 +
drivers/staging/iio/accel/adis16201_ring.c | 4 +-
drivers/staging/iio/accel/adis16203_ring.c | 6 +-
drivers/staging/iio/accel/adis16204_ring.c | 3 +-
drivers/staging/iio/accel/adis16209_ring.c | 3 +-
drivers/staging/iio/accel/adis16240_ring.c | 4 +-
drivers/staging/iio/accel/lis3l02dq_ring.c | 3 +-
drivers/staging/iio/adc/ad7192.c | 3 +-
drivers/staging/iio/adc/ad7298_ring.c | 5 +-
drivers/staging/iio/adc/ad7476_ring.c | 2 +-
drivers/staging/iio/adc/ad7606_ring.c | 3 +-
drivers/staging/iio/adc/ad7793.c | 3 +-
drivers/staging/iio/adc/ad7887_ring.c | 2 +-
drivers/staging/iio/adc/ad799x_ring.c | 3 +-
drivers/staging/iio/adc/max1363_ring.c | 2 +-
drivers/staging/iio/gyro/adis16260_ring.c | 3 +-
drivers/staging/iio/iio_input.c | 176 ++++++++++++
drivers/staging/iio/iio_input.h | 23 ++
drivers/staging/iio/iio_simple_dummy_buffer.c | 5 +-
drivers/staging/iio/impedance-analyzer/ad5933.c | 3 +-
drivers/staging/iio/imu/adis16400_ring.c | 2 +-
drivers/staging/iio/meter/ade7758_ring.c | 3 +-
include/linux/iio/buffer.h | 24 +-
include/linux/iio/consumer.h | 48 ++++
include/linux/iio/iio.h | 2 +
include/linux/iio/machine.h | 2 +
33 files changed, 651 insertions(+), 157 deletions(-)
create mode 100644 drivers/iio/buffer_cb.c
create mode 100644 drivers/staging/iio/iio_input.c
create mode 100644 drivers/staging/iio/iio_input.h
--
1.7.10.2
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-05-30 19:36 [PATCH 0/4 V2] staging:iio: Add support for multiple buffers Jonathan Cameron
@ 2012-05-30 19:36 ` Jonathan Cameron
2012-06-08 15:13 ` Lars-Peter Clausen
2012-05-30 19:36 ` [PATCH 2/4] staging:iio:in kernel users: Add a data field for channel specific info Jonathan Cameron
` (2 subsequent siblings)
3 siblings, 1 reply; 16+ messages in thread
From: Jonathan Cameron @ 2012-05-30 19:36 UTC (permalink / raw)
To: linux-iio; +Cc: Jonathan Cameron
Route all buffer writes through the demux.
Addition or removal of a buffer results in tear down and
setup of all the buffers for a given device.
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/iio/industrialio-buffer.c | 335 +++++++++++++++--------
drivers/iio/industrialio-core.c | 1 +
drivers/staging/iio/accel/adis16201_ring.c | 4 +-
drivers/staging/iio/accel/adis16203_ring.c | 6 +-
drivers/staging/iio/accel/adis16204_ring.c | 3 +-
drivers/staging/iio/accel/adis16209_ring.c | 3 +-
drivers/staging/iio/accel/adis16240_ring.c | 4 +-
drivers/staging/iio/accel/lis3l02dq_ring.c | 3 +-
drivers/staging/iio/adc/ad7192.c | 3 +-
drivers/staging/iio/adc/ad7298_ring.c | 5 +-
drivers/staging/iio/adc/ad7476_ring.c | 2 +-
drivers/staging/iio/adc/ad7606_ring.c | 3 +-
drivers/staging/iio/adc/ad7793.c | 3 +-
drivers/staging/iio/adc/ad7887_ring.c | 2 +-
drivers/staging/iio/adc/ad799x_ring.c | 3 +-
drivers/staging/iio/adc/max1363_ring.c | 2 +-
drivers/staging/iio/gyro/adis16260_ring.c | 3 +-
drivers/staging/iio/iio_simple_dummy_buffer.c | 5 +-
drivers/staging/iio/impedance-analyzer/ad5933.c | 3 +-
drivers/staging/iio/imu/adis16400_ring.c | 2 +-
drivers/staging/iio/meter/ade7758_ring.c | 3 +-
include/linux/iio/buffer.h | 24 +-
include/linux/iio/iio.h | 2 +
23 files changed, 267 insertions(+), 157 deletions(-)
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index ac185b8..b04b543 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -31,6 +31,16 @@ static const char * const iio_endian_prefix[] = {
[IIO_LE] = "le",
};
+static bool iio_buffer_is_primary_active(struct iio_dev *indio_dev)
+{
+ struct list_head *p;
+
+ list_for_each(p, &indio_dev->buffer_list)
+ if (p == &indio_dev->buffer->buffer_list)
+ return true;
+ return false;
+}
+
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
*
@@ -134,7 +144,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
if (ret < 0)
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_primary_active(indio_dev)) {
ret = -EBUSY;
goto error_ret;
}
@@ -180,12 +190,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_primary_active(indio_dev)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
- indio_dev->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@@ -395,96 +404,6 @@ ssize_t iio_buffer_write_length(struct device *dev,
}
EXPORT_SYMBOL(iio_buffer_write_length);
-ssize_t iio_buffer_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- bool requested_state, current_state;
- int previous_mode;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
-
- mutex_lock(&indio_dev->mlock);
- previous_mode = indio_dev->currentmode;
- requested_state = !(buf[0] == '0');
- current_state = iio_buffer_enabled(indio_dev);
- if (current_state == requested_state) {
- printk(KERN_INFO "iio-buffer, current state requested again\n");
- goto done;
- }
- if (requested_state) {
- if (indio_dev->setup_ops->preenable) {
- ret = indio_dev->setup_ops->preenable(indio_dev);
- if (ret) {
- printk(KERN_ERR
- "Buffer not started:"
- "buffer preenable failed\n");
- goto error_ret;
- }
- }
- if (buffer->access->request_update) {
- ret = buffer->access->request_update(buffer);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started:"
- "buffer parameter update failed\n");
- goto error_ret;
- }
- }
- /* Definitely possible for devices to support both of these.*/
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
- if (!indio_dev->trig) {
- printk(KERN_INFO
- "Buffer not started: no trigger\n");
- ret = -EINVAL;
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
- } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
- indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
- else { /* should never be reached */
- ret = -EINVAL;
- goto error_ret;
- }
-
- if (indio_dev->setup_ops->postenable) {
- ret = indio_dev->setup_ops->postenable(indio_dev);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started:"
- "postenable failed\n");
- indio_dev->currentmode = previous_mode;
- if (indio_dev->setup_ops->postdisable)
- indio_dev->setup_ops->
- postdisable(indio_dev);
- goto error_ret;
- }
- }
- } else {
- if (indio_dev->setup_ops->predisable) {
- ret = indio_dev->setup_ops->predisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_DIRECT_MODE;
- if (indio_dev->setup_ops->postdisable) {
- ret = indio_dev->setup_ops->postdisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- }
-done:
- mutex_unlock(&indio_dev->mlock);
- return len;
-
-error_ret:
- mutex_unlock(&indio_dev->mlock);
- return ret;
-}
-EXPORT_SYMBOL(iio_buffer_store_enable);
-
ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -534,31 +453,186 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
return bytes;
}
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
+ int ret;
+ struct iio_buffer *buffer;
+ unsigned long *compound_mask;
- /* How much space will the demuxed element take? */
- indio_dev->scan_bytes =
- iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
- buffer->scan_timestamp);
- buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
+ /* Wind down existing buffers - iff there are any */
+ if (!list_empty(&indio_dev->buffer_list)) {
+ if (indio_dev->setup_ops->predisable) {
+ ret = indio_dev->setup_ops->predisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable) {
+ ret = indio_dev->setup_ops->postdisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ }
+ if (!indio_dev->available_scan_masks)
+ kfree(indio_dev->active_scan_mask);
+
+ if (insert_buffer)
+ list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
+ if (remove_buffer)
+ list_del(&remove_buffer->buffer_list);
+
+ /* If no buffers in list, we are done */
+ if (list_empty(&indio_dev->buffer_list))
+ return 0;
/* What scan mask do we actually have ?*/
+ compound_mask = kzalloc(BITS_TO_LONGS(indio_dev->masklength)
+ *sizeof(long), GFP_KERNEL);
+ if (compound_mask == NULL)
+ return -ENOMEM;
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
+ indio_dev->masklength);
+ indio_dev->scan_timestamp |= buffer->scan_timestamp;
+ }
if (indio_dev->available_scan_masks)
indio_dev->active_scan_mask =
iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
- buffer->scan_mask);
+ compound_mask);
else
- indio_dev->active_scan_mask = buffer->scan_mask;
+ indio_dev->active_scan_mask = compound_mask;
+
iio_update_demux(indio_dev);
- if (indio_dev->info->update_scan_mode)
- return indio_dev->info
+ /* Wind up again */
+ if (indio_dev->setup_ops->preenable) {
+ ret = indio_dev->setup_ops->preenable(indio_dev);
+ if (ret) {
+ printk(KERN_ERR
+ "Buffer not started:"
+ "buffer preenable failed\n");
+ goto error_free_compound_mask;
+ }
+ }
+ indio_dev->scan_bytes =
+ iio_compute_scan_bytes(indio_dev,
+ indio_dev->active_scan_mask,
+ indio_dev->scan_timestamp);
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->request_update) {
+ ret = buffer->access->request_update(buffer);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started:"
+ "buffer parameter update failed\n");
+ goto error_ret;
+ }
+ }
+ if (indio_dev->info->update_scan_mode) {
+ ret = indio_dev->info
->update_scan_mode(indio_dev,
indio_dev->active_scan_mask);
+ if (ret < 0)
+ goto error_free_compound_mask;
+ }
+ /* Definitely possible for devices to support both of these.*/
+ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
+ if (!indio_dev->trig) {
+ printk(KERN_INFO "Buffer not started: no trigger\n");
+ ret = -EINVAL;
+ goto error_free_compound_mask;
+ }
+ indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
+ } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
+ indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+ } else { /* should never be reached */
+ ret = -EINVAL;
+ goto error_free_compound_mask;
+ }
+
+ if (indio_dev->setup_ops->postenable) {
+ ret = indio_dev->setup_ops->postenable(indio_dev);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started: postenable failed\n");
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+ goto error_free_compound_mask;
+ }
+ }
+error_free_compound_mask:
+ indio_dev->active_scan_mask = NULL;
+ kfree(compound_mask);
+error_ret:
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_update_buffers);
+
+ssize_t iio_buffer_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ bool requested_state;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_buffer *pbuf = indio_dev->buffer;
+ struct list_head *p;
+ bool inlist = false;
+
+ ret = strtobool(buf, &requested_state);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ /* Find out if it is in the list */
+ list_for_each(p, &indio_dev->buffer_list)
+ if (p == &pbuf->buffer_list) {
+ inlist = true;
+ break;
+ }
+ /* Already enabled */
+ if (inlist && requested_state)
+ goto done;
+ /* Already disabled */
+ if (!inlist && !requested_state)
+ goto done;
+
+ if (requested_state)
+ ret = iio_update_buffers(indio_dev,
+ indio_dev->buffer, NULL);
+ else
+ ret = iio_update_buffers(indio_dev,
+ NULL, indio_dev->buffer);
+
+ if (ret < 0)
+ goto done;
+done:
+ mutex_unlock(&indio_dev->mlock);
+ return (ret < 0) ? ret : len;
+}
+EXPORT_SYMBOL(iio_buffer_store_enable);
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ unsigned bytes;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->set_bytes_per_datum) {
+ bytes = iio_compute_scan_bytes(indio_dev,
+ buffer->scan_mask,
+ buffer->scan_timestamp);
+
+ buffer->access->set_bytes_per_datum(buffer, bytes);
+ }
return 0;
}
EXPORT_SYMBOL(iio_sw_buffer_preenable);
@@ -567,7 +641,11 @@ EXPORT_SYMBOL(iio_sw_buffer_preenable);
* iio_scan_mask_set() - set particular bit in the scan mask
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
- **/
+ *
+ * Note that at this point we have no way of knowing what other
+ * buffers might request, hence this code only verifies that the
+ * individual buffers request is plausible.
+ */
int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
@@ -597,7 +675,7 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
return -EINVAL;
}
}
- bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
+ set_bit(bit, buffer->scan_mask);
kfree(trialmask);
@@ -646,14 +724,13 @@ static unsigned char *iio_demux(struct iio_buffer *buffer,
return buffer->demux_bounce;
}
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
+static int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
s64 timestamp)
{
unsigned char *dataout = iio_demux(buffer, data);
return buffer->access->store_to(buffer, dataout, timestamp);
}
-EXPORT_SYMBOL_GPL(iio_push_to_buffer);
static void iio_buffer_demux_free(struct iio_buffer *buffer)
{
@@ -664,10 +741,27 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer)
}
}
-int iio_update_demux(struct iio_dev *indio_dev)
+
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data,
+ s64 timestamp)
+{
+ int ret;
+ struct iio_buffer *buf;
+
+ list_for_each_entry(buf, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_push_to_buffer(buf, data, timestamp);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_push_to_buffers);
+
+static int iio_buffer_update_demux(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
{
const struct iio_chan_spec *ch;
- struct iio_buffer *buffer = indio_dev->buffer;
int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0;
struct iio_demux_table *p;
@@ -752,4 +846,23 @@ error_clear_mux_table:
return ret;
}
+
+int iio_update_demux(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ int ret;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_buffer_update_demux(indio_dev, buffer);
+ if (ret < 0)
+ goto error_clear_mux_table;
+ }
+ return 0;
+
+error_clear_mux_table:
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ iio_buffer_demux_free(buffer);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 07b053b..aa2edf4 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -834,6 +834,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
+ INIT_LIST_HEAD(&dev->buffer_list);
}
return dev;
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 247602a..64ba02a 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -62,8 +62,6 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16201_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
@@ -83,7 +81,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 7bbd2c2..57480f4 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -61,8 +61,6 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16203_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
@@ -82,9 +80,7 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring,
- (u8 *)data,
- pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index f73518b..3a5d459 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -59,7 +59,6 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16204_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
@@ -79,7 +78,7 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 0906075..155fc79 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -59,7 +59,6 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16209_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
@@ -79,7 +78,7 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index 86a2a47..dec6646 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -56,8 +56,6 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16240_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
@@ -77,7 +75,7 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 51b00df..7129e22 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -135,7 +135,6 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
char *data;
@@ -154,7 +153,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
*(s64 *)(((phys_addr_t)data + len
+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
= pf->timestamp;
- buffer->access->store_to(buffer, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 5eaeaf1..b6b32f6 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -510,7 +510,6 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *ring = indio_dev->buffer;
struct ad7192_state *st = iio_priv(indio_dev);
s64 dat64[2];
s32 *dat32 = (s32 *)dat64;
@@ -524,7 +523,7 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
st->irq_dis = false;
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index 908a3e5..146afd8 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -83,7 +83,6 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7298_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u16 buf[16];
int b_sent, i;
@@ -99,10 +98,10 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
}
for (i = 0; i < bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength); i++)
+ indio_dev->masklength); i++)
buf[i] = be16_to_cpu(st->rx_buf[i]);
- indio_dev->buffer->access->store_to(ring, (u8 *)buf, time_ns);
+ iio_push_to_buffers(indio_dev, (u8 *)buf, time_ns);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index 383611b..950a11e 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -44,7 +44,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns);
+ iio_push_to_buffers(indio_dev, rxbuf, time_ns);
done:
iio_trigger_notify_done(indio_dev->trig);
kfree(rxbuf);
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index 24ce8fc..497c1fc 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -46,7 +46,6 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
struct ad7606_state *st = container_of(work_s, struct ad7606_state,
poll_work);
struct iio_dev *indio_dev = iio_priv_to_dev(st);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u8 *buf;
int ret;
@@ -84,7 +83,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
if (indio_dev->scan_timestamp)
*((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
- ring->access->store_to(indio_dev->buffer, buf, time_ns);
+ iio_push_to_buffers(indio_dev, buf, time_ns);
done:
gpio_set_value(st->pdata->gpio_convst, 0);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index b36556f..22875a5 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -375,7 +375,6 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *ring = indio_dev->buffer;
struct ad7793_state *st = iio_priv(indio_dev);
s64 dat64[2];
s32 *dat32 = (s32 *)dat64;
@@ -389,7 +388,7 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
st->irq_dis = false;
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index fd91384..9e11052 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -95,7 +95,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns);
+ iio_push_to_buffers(indio_dev, buf, time_ns);
done:
kfree(buf);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 1c7ff44..5d567fe 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -56,7 +56,6 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad799x_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u8 *rxbuf;
int b_sent;
@@ -99,7 +98,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- ring->access->store_to(indio_dev->buffer, rxbuf, time_ns);
+ iio_push_to_buffers(indio_dev, rxbuf, time_ns);
done:
kfree(rxbuf);
if (b_sent < 0)
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index b302013..73273c0 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -80,7 +80,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns);
+ iio_push_to_buffers(indio_dev, rxbuf, time_ns);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index 0fe2d9d..4922a6d 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -62,7 +62,6 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16260_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
@@ -82,7 +81,7 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index fdfc873..5931cbb 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -46,7 +46,6 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
u16 *data;
@@ -76,7 +75,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
i++) {
- j = find_next_bit(buffer->scan_mask,
+ j = find_next_bit(indio_dev->buffer->scan_mask,
indio_dev->masklength, j + 1);
/* random access read form the 'device' */
data[i] = fakedata[j];
@@ -88,7 +87,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
*(s64 *)(((phys_addr_t)data + len
+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
= iio_get_time_ns();
- buffer->access->store_to(buffer, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
kfree(data);
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index a8e51bc..3599ec1 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -647,7 +647,6 @@ static void ad5933_work(struct work_struct *work)
struct ad5933_state *st = container_of(work,
struct ad5933_state, work.work);
struct iio_dev *indio_dev = i2c_get_clientdata(st->client);
- struct iio_buffer *ring = indio_dev->buffer;
signed short buf[2];
unsigned char status;
@@ -678,7 +677,7 @@ static void ad5933_work(struct work_struct *work)
buf[0] = be16_to_cpu(buf[0]);
}
/* save datum to the ring */
- ring->access->store_to(ring, (u8 *)buf, iio_get_time_ns());
+ iio_push_to_buffers(indio_dev, (u8 *)buf, iio_get_time_ns());
} else {
/* no data available - try again later */
schedule_delayed_work(&st->work, st->poll_time_jiffies);
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 809e2c4..4c0dac8 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -150,7 +150,7 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
/* Guaranteed to be aligned with 8 byte boundary */
if (ring->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(indio_dev->buffer, (u8 *) data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *) data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 92159f2..0b0edd2 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -61,7 +61,6 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *ring = indio_dev->buffer;
struct ade7758_state *st = iio_priv(indio_dev);
s64 dat64[2];
u32 *dat32 = (u32 *)dat64;
@@ -74,7 +73,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index fb0fe46..22f7bfd 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -66,7 +66,8 @@ struct iio_buffer_access_funcs {
* @stufftoread: [INTERN] flag to indicate new data.
* @demux_list: [INTERN] list of operations required to demux the scan.
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
- **/
+ * @buffer_list: [INTERN] entry in the devices list of current buffers.
+ */
struct iio_buffer {
int length;
int bytes_per_datum;
@@ -81,9 +82,22 @@ struct iio_buffer {
const struct attribute_group *attrs;
struct list_head demux_list;
unsigned char *demux_bounce;
+ struct list_head buffer_list;
};
/**
+ * iio_update_buffers() - add or remove buffer from active list
+ * @indio_dev: device to add buffer to
+ * @insert_buffer: buffer to insert
+ * @remove_buffer: buffer_to_remove
+ *
+ * Note this will tear down the all buffering and build it up again
+ */
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer);
+
+/**
* iio_buffer_init() - Initialize the buffer structure
* @buffer: buffer to be initialized
**/
@@ -114,12 +128,12 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit);
/**
- * iio_push_to_buffer() - push to a registered buffer.
- * @buffer: IIO buffer structure for device
- * @scan: Full scan.
+ * iio_push_to_buffers() - push to a registered buffer.
+ * @indio_dev: iio_dev structure for device.
+ * @data: Full scan.
* @timestamp:
*/
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data,
s64 timestamp);
int iio_update_demux(struct iio_dev *indio_dev);
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 7378bbd..e486216 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -381,6 +381,7 @@ struct iio_buffer_setup_ops {
* and owner
* @event_interface: [INTERN] event chrdevs associated with interrupt lines
* @buffer: [DRIVER] any buffer present
+ * @buffer_list: [INTERN] list of all buffers currently attached
* @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
* @mlock: [INTERN] lock used to prevent simultaneous device state
* changes
@@ -419,6 +420,7 @@ struct iio_dev {
struct iio_event_interface *event_interface;
struct iio_buffer *buffer;
+ struct list_head buffer_list;
int scan_bytes;
struct mutex mlock;
--
1.7.10.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 2/4] staging:iio:in kernel users: Add a data field for channel specific info.
2012-05-30 19:36 [PATCH 0/4 V2] staging:iio: Add support for multiple buffers Jonathan Cameron
2012-05-30 19:36 ` [PATCH 1/4] " Jonathan Cameron
@ 2012-05-30 19:36 ` Jonathan Cameron
2012-05-30 19:36 ` [PATCH 3/4] staging:iio: add a callback buffer for in kernel push interface Jonathan Cameron
2012-05-30 19:36 ` [PATCH 4/4] staging:iio: Proof of concept input driver Jonathan Cameron
3 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-05-30 19:36 UTC (permalink / raw)
To: linux-iio; +Cc: Jonathan Cameron
Used to allow information about a given channel mapping to be passed
through from board files to the consumer drivers.
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/iio/inkern.c | 1 +
include/linux/iio/consumer.h | 2 ++
include/linux/iio/machine.h | 2 ++
3 files changed, 5 insertions(+)
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 6c03cf5..c1ea198 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -188,6 +188,7 @@ struct iio_channel *iio_channel_get_all(const char *name)
if (name && strcmp(name, c->map->consumer_dev_name) != 0)
continue;
chans[mapind].indio_dev = c->indio_dev;
+ chans[mapind].data = c->map->consumer_data;
chans[mapind].channel =
iio_chan_spec_from_name(chans[mapind].indio_dev,
c->map->adc_channel_label);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index e2657e6..26040c2 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -18,10 +18,12 @@ struct iio_chan_spec;
* struct iio_channel - everything needed for a consumer to use a channel
* @indio_dev: Device on which the channel exists.
* @channel: Full description of the channel.
+ * @data: Data about the channel used by consumer.
*/
struct iio_channel {
struct iio_dev *indio_dev;
const struct iio_chan_spec *channel;
+ void *data;
};
/**
diff --git a/include/linux/iio/machine.h b/include/linux/iio/machine.h
index 0b1f19b..7409100 100644
--- a/include/linux/iio/machine.h
+++ b/include/linux/iio/machine.h
@@ -16,9 +16,11 @@
* @consumer_dev_name: Name to uniquely identify the consumer device.
* @consumer_channel: Unique name used to idenitify the channel on the
* consumer side.
+ * @consumer_data: Data about the channel for use by the consumer driver.
*/
struct iio_map {
const char *adc_channel_label;
const char *consumer_dev_name;
const char *consumer_channel;
+ void *consumer_data;
};
--
1.7.10.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 3/4] staging:iio: add a callback buffer for in kernel push interface
2012-05-30 19:36 [PATCH 0/4 V2] staging:iio: Add support for multiple buffers Jonathan Cameron
2012-05-30 19:36 ` [PATCH 1/4] " Jonathan Cameron
2012-05-30 19:36 ` [PATCH 2/4] staging:iio:in kernel users: Add a data field for channel specific info Jonathan Cameron
@ 2012-05-30 19:36 ` Jonathan Cameron
2012-05-30 19:36 ` [PATCH 4/4] staging:iio: Proof of concept input driver Jonathan Cameron
3 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-05-30 19:36 UTC (permalink / raw)
To: linux-iio; +Cc: Jonathan Cameron
This callback buffer is meant to be opaque to users, but basically
adds a very simple pass through buffer to which data may be
pushed when it is inserted into the buffer list.
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/iio/Kconfig | 6 +++
drivers/iio/Makefile | 1 +
drivers/iio/buffer_cb.c | 115 ++++++++++++++++++++++++++++++++++++++++++
include/linux/iio/consumer.h | 46 +++++++++++++++++
4 files changed, 168 insertions(+)
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 62fda86..c9e9483 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -21,6 +21,12 @@ config IIO_BUFFER
if IIO_BUFFER
+config IIO_BUFFER_CB
+ boolean "IIO callback buffer used for push in kernel interfaces"
+ help
+ Should be selected by any drivers that do inkernel push
+ usage. That is, those where the data is pushed to the consumer.
+
config IIO_KFIFO_BUF
select IIO_TRIGGER
tristate "Industrial I/O buffering based on kfifo"
diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
index 30a9144..2df439c 100644
--- a/drivers/iio/Makefile
+++ b/drivers/iio/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
+industrialio-$(CONFIG_IIO_BUFFER_CB) += buffer_cb.o
obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o
diff --git a/drivers/iio/buffer_cb.c b/drivers/iio/buffer_cb.c
new file mode 100644
index 0000000..d686bdf
--- /dev/null
+++ b/drivers/iio/buffer_cb.c
@@ -0,0 +1,115 @@
+#include <linux/kernel.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)(u8 *data, void *private);
+ void *private;
+ struct iio_channel *channels;
+};
+
+static int iio_buffer_cb_store_to(struct iio_buffer *buffer,
+ u8 *data,
+ s64 timestamp)
+{
+ struct iio_cb_buffer *cb_buff = container_of(buffer,
+ struct iio_cb_buffer,
+ buffer);
+
+ return cb_buff->cb(data, cb_buff->private);
+}
+
+static struct iio_buffer_access_funcs iio_cb_access = {
+ .store_to = &iio_buffer_cb_store_to,
+};
+
+struct iio_cb_buffer *iio_channel_get_all_cb(const char *name,
+ int (*cb)(u8 *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) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+
+ 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(name);
+ 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
+ = kzalloc(sizeof(long)*BITS_TO_LONGS(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 != indio_dev) {
+ ret = -EINVAL;
+ goto error_release_channels;
+ }
+ set_bit(chan->channel->scan_index,
+ cb_buff->buffer.scan_mask);
+ chan++;
+ }
+
+ return cb_buff;
+
+error_release_channels:
+ iio_channel_release_all(cb_buff->channels);
+error_free_cb_buff:
+ kfree(cb_buff);
+error_ret:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(iio_channel_get_all_cb);
+
+void iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff)
+{
+ 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);
+ kfree(cb_buff);
+}
+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);
diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h
index 26040c2..efd377e 100644
--- a/include/linux/iio/consumer.h
+++ b/include/linux/iio/consumer.h
@@ -61,6 +61,52 @@ struct iio_channel *iio_channel_get_all(const char *name);
*/
void iio_channel_release_all(struct iio_channel *chan);
+struct iio_cb_buffer;
+/**
+ * iio_channel_get_all_cb() - register callback for triggered capture
+ * @name: Name of client device.
+ * @cb: Callback function.
+ * @private: Private data passed to callback.
+ *
+ * NB right now we have no ability to mux data from multiple devices.
+ * So if the channels requested come from different devices this will
+ * fail.
+ */
+struct iio_cb_buffer *iio_channel_get_all_cb(const char *name,
+ int (*cb)(u8 *data,
+ void *private),
+ void *private);
+/**
+ * iio_channel_release_all_cb() - release and unregister the callback.
+ * @cb_buffer: The callback buffer that was allocated.
+ */
+void iio_channel_release_all_cb(struct iio_cb_buffer *cb_buffer);
+
+/**
+ * iio_channel_start_all_cb() - start the flow of data through callback.
+ * @cb_buff: The callback buffer we are starting.
+ */
+void iio_channel_start_all_cb(struct iio_cb_buffer *cb_buff);
+
+/**
+ * iio_channel_stop_all_cb() - stop the flow of data through the callback.
+ * @cb_buff: The callback buffer we are stopping.
+ */
+void iio_channel_stop_all_cb(struct iio_cb_buffer *cb_buff);
+
+/**
+ * iio_channel_cb_get_channels() - get access to the underlying channels.
+ * @cb_buff: The callback buffers from whom we want the channel
+ * information.
+ *
+ * This function allows one to obtain information about the channels.
+ * Whilst this may allow direct reading if all buffers are disabled, the
+ * primary aim is to allow drivers that are consuming a channel to query
+ * things like scaling of the channel.
+ */
+struct iio_channel
+*iio_channel_cb_get_channels(const struct iio_cb_buffer *cb_buffer);
+
/**
* iio_read_channel_raw() - read from a given channel
* @channel: The channel being queried.
--
1.7.10.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 4/4] staging:iio: Proof of concept input driver.
2012-05-30 19:36 [PATCH 0/4 V2] staging:iio: Add support for multiple buffers Jonathan Cameron
` (2 preceding siblings ...)
2012-05-30 19:36 ` [PATCH 3/4] staging:iio: add a callback buffer for in kernel push interface Jonathan Cameron
@ 2012-05-30 19:36 ` Jonathan Cameron
2012-06-08 15:27 ` Lars-Peter Clausen
3 siblings, 1 reply; 16+ messages in thread
From: Jonathan Cameron @ 2012-05-30 19:36 UTC (permalink / raw)
To: linux-iio; +Cc: Jonathan Cameron, Jonathan Cameron
From: Jonathan Cameron <jic23@cam.ac.uk>
This is no where near ready to merge. Lots of stuff missing.
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/staging/iio/Kconfig | 11 +++
drivers/staging/iio/Makefile | 1 +
drivers/staging/iio/iio_input.c | 176 +++++++++++++++++++++++++++++++++++++++
drivers/staging/iio/iio_input.h | 23 +++++
4 files changed, 211 insertions(+)
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index 04cd6ec..022463e 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -4,6 +4,17 @@
menu "IIO staging drivers"
depends on IIO
+config IIO_ST_INPUT
+ tristate "Input driver that uses channels specified via iio maps"
+ depends on INPUT
+ depends on IIO_BUFFER
+ select IIO_BUFFER_CB
+ help
+ Client driver for IIO via the push interfaces. Used to provide
+ and input interface for IIO devices that can feed a buffer on
+ a trigger interrupt. Note that all channels must come from a
+ single IIO supported device.
+
config IIO_ST_HWMON
tristate "Hwmon driver that uses channels specified via iio maps"
depends on HWMON
diff --git a/drivers/staging/iio/Makefile b/drivers/staging/iio/Makefile
index fa6937d..9e71498 100644
--- a/drivers/staging/iio/Makefile
+++ b/drivers/staging/iio/Makefile
@@ -12,6 +12,7 @@ iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
obj-$(CONFIG_IIO_ST_HWMON) += iio_hwmon.o
+obj-$(CONFIG_IIO_ST_INPUT) += iio_input.o
obj-y += accel/
obj-y += adc/
diff --git a/drivers/staging/iio/iio_input.c b/drivers/staging/iio/iio_input.c
new file mode 100644
index 0000000..42f4cfb
--- /dev/null
+++ b/drivers/staging/iio/iio_input.c
@@ -0,0 +1,176 @@
+/*
+ * The industrial I/O input client driver
+ *
+ * Copyright (c) 2011 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/consumer.h>
+#include "iio_input.h"
+
+struct iio_input_state {
+ struct iio_cb_buffer *buff;
+ struct input_dev *idev;
+};
+
+static int iio_channel_value(u8 *data,
+ const struct iio_chan_spec *chan,
+ int *val)
+{
+ int value;
+
+ if (chan->scan_type.sign == 's') {
+ switch (chan->scan_type.storagebits) {
+ case 8:
+ value = *(s8 *)(data);
+ break;
+ case 16:
+ value = *(s16 *)(data);
+ break;
+ case 32:
+ value = *(s32 *)(data);
+ break;
+ default:
+ return -EINVAL;
+ }
+ value >>= chan->scan_type.shift;
+ value &= (1 << chan->scan_type.realbits) - 1;
+ value = (value << (sizeof(value)*8 - chan->scan_type.realbits))
+ >> (sizeof(value)*8 - chan->scan_type.realbits);
+ } else {
+ switch (chan->scan_type.storagebits) {
+ case 8:
+ value = *(u8 *)(data);
+ break;
+ case 16:
+ value = *(u16 *)(data);
+ break;
+ case 32:
+ value = *(u32 *)(data);
+ break;
+ default:
+ return -EINVAL;
+ }
+ value >>= chan->scan_type.shift;
+ value &= (1 << chan->scan_type.realbits) - 1;
+ }
+ *val = value;
+
+ return 0;
+}
+
+static int iio_input_store_to(u8 *data, void *private)
+{
+ struct iio_input_state *st = private;
+ struct iio_channel *channel;
+ struct iio_input_channel_data *input_data;
+ int offset = 0;
+ int value, ret;
+
+ channel = iio_channel_cb_get_channels(st->buff);
+ while (channel->indio_dev) {
+ input_data = channel->data;
+ offset = ALIGN(offset,
+ channel->channel->scan_type.storagebits/8);
+ offset += channel->channel->scan_type.storagebits/8;
+ ret = iio_channel_value(&data[offset],
+ channel->channel,
+ &value);
+ if (ret < 0)
+ return ret;
+ input_report_abs(st->idev, input_data->code, value);
+ }
+ input_sync(st->idev);
+
+ return 0;
+}
+
+static int __devinit iio_input_probe(struct platform_device *pdev)
+{
+ struct iio_input_state *st;
+ int ret;
+ struct iio_channel *channel;
+ struct iio_input_channel_data *input_data;
+
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
+ if (st == NULL)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, st);
+ st->buff = iio_channel_get_all_cb(dev_name(&pdev->dev),
+ &iio_input_store_to,
+ st);
+ if (IS_ERR(st->buff)) {
+ ret = PTR_ERR(st->buff);
+ goto error_free_state;
+ }
+
+ st->idev = input_allocate_device();
+ if (!st->idev) {
+ ret = -ENOMEM;
+ goto error_channels_release_all;
+ }
+
+ __set_bit(EV_ABS, st->idev->evbit);
+ channel = iio_channel_cb_get_channels(st->buff);
+ while (channel->indio_dev) {
+ input_data = channel->data;
+ input_set_abs_params(st->idev, input_data->code,
+ input_data->min,
+ input_data->max,
+ input_data->fuzz,
+ input_data->flat);
+ }
+
+ ret = input_register_device(st->idev);
+ if (ret < 0)
+ goto error_free_idev;
+
+ /* NORMALLY IN THE OPEN */
+ iio_channel_start_all_cb(st->buff);
+
+ return 0;
+error_free_idev:
+ input_free_device(st->idev);
+error_channels_release_all:
+ iio_channel_release_all_cb(st->buff);
+error_free_state:
+ kfree(st);
+ return ret;
+}
+
+static int __devexit iio_input_remove(struct platform_device *pdev)
+{
+ struct iio_input_state *st = platform_get_drvdata(pdev);
+ /* NORMALLY IN THE CLOSE */
+ iio_channel_stop_all_cb(st->buff);
+ input_unregister_device(st->idev);
+ iio_channel_release_all_cb(st->buff);
+
+ kfree(st);
+ return 0;
+}
+
+static struct platform_driver iio_input_driver = {
+ .driver = {
+ .name = "iio_snoop",
+ .owner = THIS_MODULE,
+ },
+ .probe = iio_input_probe,
+ .remove = __devexit_p(iio_input_remove),
+};
+
+module_platform_driver(iio_input_driver);
+
+MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
+MODULE_DESCRIPTION("IIO input buffer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/iio/iio_input.h b/drivers/staging/iio/iio_input.h
new file mode 100644
index 0000000..cfd1d34
--- /dev/null
+++ b/drivers/staging/iio/iio_input.h
@@ -0,0 +1,23 @@
+/*
+ * The industrial I/O input client driver
+ *
+ * Copyright (c) 2011 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.
+ */
+
+/**
+ * iio_input_channel_data - description of the channel for input subsystem
+ * @code: Absolute axis.
+ * @min: Minimum value.
+ * @max: Maximum value.
+ * @fuzz: Used to filter noise from the event stream.
+ * @flat: Values within this value will be discarded by joydev
+ * and reported as 0 instead.
+ */
+struct iio_input_channel_data {
+ unsigned int code;
+ int min, max, fuzz, flat;
+};
--
1.7.10.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-05-30 19:36 ` [PATCH 1/4] " Jonathan Cameron
@ 2012-06-08 15:13 ` Lars-Peter Clausen
2012-06-09 12:17 ` Jonathan Cameron
0 siblings, 1 reply; 16+ messages in thread
From: Lars-Peter Clausen @ 2012-06-08 15:13 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio
On 05/30/2012 09:36 PM, Jonathan Cameron wrote:
> Route all buffer writes through the demux.
> Addition or removal of a buffer results in tear down and
> setup of all the buffers for a given device.
>
My test platform is currently broken in staging-next, so just some comments
based on code review for now.
> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
> ---
> drivers/iio/industrialio-buffer.c | 335 +++++++++++++++--------
> drivers/iio/industrialio-core.c | 1 +
> drivers/staging/iio/accel/adis16201_ring.c | 4 +-
> drivers/staging/iio/accel/adis16203_ring.c | 6 +-
> drivers/staging/iio/accel/adis16204_ring.c | 3 +-
> drivers/staging/iio/accel/adis16209_ring.c | 3 +-
> drivers/staging/iio/accel/adis16240_ring.c | 4 +-
> drivers/staging/iio/accel/lis3l02dq_ring.c | 3 +-
> drivers/staging/iio/adc/ad7192.c | 3 +-
> drivers/staging/iio/adc/ad7298_ring.c | 5 +-
> drivers/staging/iio/adc/ad7476_ring.c | 2 +-
> drivers/staging/iio/adc/ad7606_ring.c | 3 +-
> drivers/staging/iio/adc/ad7793.c | 3 +-
> drivers/staging/iio/adc/ad7887_ring.c | 2 +-
> drivers/staging/iio/adc/ad799x_ring.c | 3 +-
> drivers/staging/iio/adc/max1363_ring.c | 2 +-
> drivers/staging/iio/gyro/adis16260_ring.c | 3 +-
> drivers/staging/iio/iio_simple_dummy_buffer.c | 5 +-
> drivers/staging/iio/impedance-analyzer/ad5933.c | 3 +-
> drivers/staging/iio/imu/adis16400_ring.c | 2 +-
> drivers/staging/iio/meter/ade7758_ring.c | 3 +-
> include/linux/iio/buffer.h | 24 +-
> include/linux/iio/iio.h | 2 +
The at91_adc driver is not handled by this patch
> 23 files changed, 267 insertions(+), 157 deletions(-)
>
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index ac185b8..b04b543 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -31,6 +31,16 @@ static const char * const iio_endian_prefix[] = {
> [IIO_LE] = "le",
> };
>
> +static bool iio_buffer_is_primary_active(struct iio_dev *indio_dev)
> +{
> + struct list_head *p;
> +
> + list_for_each(p, &indio_dev->buffer_list)
> + if (p == &indio_dev->buffer->buffer_list)
> + return true;
More or less the same code is used below. I think it makes sense to have a
generic iio_buffer_is_active(indio_dev, buffer)
> + return false;
> +}
> [...]
> @@ -534,31 +453,186 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
> return bytes;
> }
>
> -int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
> +int iio_update_buffers(struct iio_dev *indio_dev,
> + struct iio_buffer *insert_buffer,
> + struct iio_buffer *remove_buffer)
> {
> - struct iio_buffer *buffer = indio_dev->buffer;
> - dev_dbg(&indio_dev->dev, "%s\n", __func__);
> + int ret;
drivers/iio/industrialio-buffer.c: In function ‘iio_update_buffers’:
drivers/iio/industrialio-buffer.c:460: warning: ‘ret’ may be used
uninitialized in this function
I think there a missing 'return 0', before the error handling. Right now the
code always sets active_scan_mask to NULL.
> + struct iio_buffer *buffer;
> + unsigned long *compound_mask;
>
> - /* How much space will the demuxed element take? */
> - indio_dev->scan_bytes =
> - iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
> - buffer->scan_timestamp);
> - buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
> + /* Wind down existing buffers - iff there are any */
> + if (!list_empty(&indio_dev->buffer_list)) {
> + if (indio_dev->setup_ops->predisable) {
> + ret = indio_dev->setup_ops->predisable(indio_dev);
> + if (ret)
> + goto error_ret;
> + }
> + indio_dev->currentmode = INDIO_DIRECT_MODE;
> + if (indio_dev->setup_ops->postdisable) {
> + ret = indio_dev->setup_ops->postdisable(indio_dev);
> + if (ret)
> + goto error_ret;
> + }
> + }
> + if (!indio_dev->available_scan_masks)
> + kfree(indio_dev->active_scan_mask);
If the code errors out before reassigning active_scan_mask we'll leave a
dangling pointer to the old scan mask, which will cause access after free or
a double free.
> +
> + if (insert_buffer)
> + list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
> + if (remove_buffer)
> + list_del(&remove_buffer->buffer_list);
I'd do the remove before the insert, makes this more robust, if the function
is ever going to be called with both set to the same buffer.
> +
> + /* If no buffers in list, we are done */
> + if (list_empty(&indio_dev->buffer_list))
> + return 0;
>
> /* What scan mask do we actually have ?*/
> + compound_mask = kzalloc(BITS_TO_LONGS(indio_dev->masklength)
> + *sizeof(long), GFP_KERNEL);
> + if (compound_mask == NULL)
> + return -ENOMEM;
> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
> + bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
> + indio_dev->masklength);
> + indio_dev->scan_timestamp |= buffer->scan_timestamp;
> + }
> if (indio_dev->available_scan_masks)
> indio_dev->active_scan_mask =
> iio_scan_mask_match(indio_dev->available_scan_masks,
> indio_dev->masklength,
> - buffer->scan_mask);
> + compound_mask);
active_scan_mask may be NULL if the device isn't able to handle the compound
mask.
Btw. if it is not possible to add the new buffer to the list, e.g. because
the compound scan mask is not supported, do we to do a rollback to the
previous working configuration? I think this might be a better option,
rather than leaving things broken.
> else
> - indio_dev->active_scan_mask = buffer->scan_mask;
> + indio_dev->active_scan_mask = compound_mask;
> +
> iio_update_demux(indio_dev);
>
> - if (indio_dev->info->update_scan_mode)
> - return indio_dev->info
> + /* Wind up again */
> + if (indio_dev->setup_ops->preenable) {
> + ret = indio_dev->setup_ops->preenable(indio_dev);
> + if (ret) {
> + printk(KERN_ERR
> + "Buffer not started:"
> + "buffer preenable failed\n");
> + goto error_free_compound_mask;
> + }
> + }
> + indio_dev->scan_bytes =
> + iio_compute_scan_bytes(indio_dev,
> + indio_dev->active_scan_mask,
> + indio_dev->scan_timestamp);
> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
> + if (buffer->access->request_update) {
> + ret = buffer->access->request_update(buffer);
> + if (ret) {
> + printk(KERN_INFO
> + "Buffer not started:"
> + "buffer parameter update failed\n");
> + goto error_ret;
> + }
> + }
> + if (indio_dev->info->update_scan_mode) {
> + ret = indio_dev->info
> ->update_scan_mode(indio_dev,
> indio_dev->active_scan_mask);
> + if (ret < 0)
> + goto error_free_compound_mask;
> + }
> + /* Definitely possible for devices to support both of these.*/
> + if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
> + if (!indio_dev->trig) {
> + printk(KERN_INFO "Buffer not started: no trigger\n");
> + ret = -EINVAL;
> + goto error_free_compound_mask;
> + }
> + indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
> + } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
> + indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
> + } else { /* should never be reached */
> + ret = -EINVAL;
> + goto error_free_compound_mask;
> + }
> +
> + if (indio_dev->setup_ops->postenable) {
> + ret = indio_dev->setup_ops->postenable(indio_dev);
> + if (ret) {
> + printk(KERN_INFO
> + "Buffer not started: postenable failed\n");
> + indio_dev->currentmode = INDIO_DIRECT_MODE;
> + if (indio_dev->setup_ops->postdisable)
> + indio_dev->setup_ops->postdisable(indio_dev);
> + goto error_free_compound_mask;
> + }
> + }
> +error_free_compound_mask:
> + indio_dev->active_scan_mask = NULL;
> + kfree(compound_mask);
> +error_ret:
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(iio_update_buffers);
> +
> +ssize_t iio_buffer_store_enable(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf,
> + size_t len)
> +{
> + int ret;
> + bool requested_state;
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
> + struct iio_buffer *pbuf = indio_dev->buffer;
> + struct list_head *p;
> + bool inlist = false;
> +
> + ret = strtobool(buf, &requested_state);
> + if (ret < 0)
> + return ret;
> +
> + mutex_lock(&indio_dev->mlock);
> +
> + /* Find out if it is in the list */
> + list_for_each(p, &indio_dev->buffer_list)
> + if (p == &pbuf->buffer_list) {
> + inlist = true;
> + break;
> + }
> + /* Already enabled */
> + if (inlist && requested_state)
> + goto done;
> + /* Already disabled */
> + if (!inlist && !requested_state)
> + goto done;
if (inlist == requested_state)
goto done;
> +
> + if (requested_state)
> + ret = iio_update_buffers(indio_dev,
> + indio_dev->buffer, NULL);
> + else
> + ret = iio_update_buffers(indio_dev,
> + NULL, indio_dev->buffer);
> +
> + if (ret < 0)
> + goto done;
> +done:
> + mutex_unlock(&indio_dev->mlock);
> + return (ret < 0) ? ret : len;
> +}
> +EXPORT_SYMBOL(iio_buffer_store_enable);
> +
[...]
> @@ -567,7 +641,11 @@ EXPORT_SYMBOL(iio_sw_buffer_preenable);
> * iio_scan_mask_set() - set particular bit in the scan mask
> * @buffer: the buffer whose scan mask we are interested in
> * @bit: the bit to be set.
> - **/
> + *
> + * Note that at this point we have no way of knowing what other
> + * buffers might request, hence this code only verifies that the
> + * individual buffers request is plausible.
> + */
> int iio_scan_mask_set(struct iio_dev *indio_dev,
> struct iio_buffer *buffer, int bit)
> {
> @@ -597,7 +675,7 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
> return -EINVAL;
> }
> }
> - bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
> + set_bit(bit, buffer->scan_mask);
Is this a unrelated fix?
>
> kfree(trialmask);
>
[...]
> diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
> index fdfc873..5931cbb 100644
> --- a/drivers/staging/iio/iio_simple_dummy_buffer.c
> +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
> @@ -46,7 +46,6 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
> {
> struct iio_poll_func *pf = p;
> struct iio_dev *indio_dev = pf->indio_dev;
> - struct iio_buffer *buffer = indio_dev->buffer;
> int len = 0;
> u16 *data;
>
> @@ -76,7 +75,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
> i < bitmap_weight(indio_dev->active_scan_mask,
> indio_dev->masklength);
> i++) {
> - j = find_next_bit(buffer->scan_mask,
> + j = find_next_bit(indio_dev->buffer->scan_mask,
should this be indio_dev->active_scan_mask?
> indio_dev->masklength, j + 1);
> /* random access read form the 'device' */
> data[i] = fakedata[j];
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 4/4] staging:iio: Proof of concept input driver.
2012-05-30 19:36 ` [PATCH 4/4] staging:iio: Proof of concept input driver Jonathan Cameron
@ 2012-06-08 15:27 ` Lars-Peter Clausen
2012-06-09 17:56 ` Jonathan Cameron
0 siblings, 1 reply; 16+ messages in thread
From: Lars-Peter Clausen @ 2012-06-08 15:27 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio, Jonathan Cameron
On 05/30/2012 09:36 PM, Jonathan Cameron wrote:
> From: Jonathan Cameron <jic23@cam.ac.uk>
>
> This is no where near ready to merge. Lots of stuff missing.
>
> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
> ---
> drivers/staging/iio/Kconfig | 11 +++
> drivers/staging/iio/Makefile | 1 +
> drivers/staging/iio/iio_input.c | 176 +++++++++++++++++++++++++++++++++++++++
> drivers/staging/iio/iio_input.h | 23 +++++
> 4 files changed, 211 insertions(+)
>
> diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
> index 04cd6ec..022463e 100644
> --- a/drivers/staging/iio/Kconfig
> +++ b/drivers/staging/iio/Kconfig
> @@ -4,6 +4,17 @@
[...]
> +};
> +
> +static int iio_channel_value(u8 *data,
> + const struct iio_chan_spec *chan,
> + int *val)
> +{
> + int value;
> +
> + if (chan->scan_type.sign == 's') {
> + switch (chan->scan_type.storagebits) {
> + case 8:
> + value = *(s8 *)(data);
> + break;
> + case 16:
> + value = *(s16 *)(data);
> + break;
> + case 32:
> + value = *(s32 *)(data);
> + break;
> + default:
> + return -EINVAL;
> + }
> + value >>= chan->scan_type.shift;
> + value &= (1 << chan->scan_type.realbits) - 1;
> + value = (value << (sizeof(value)*8 - chan->scan_type.realbits))
> + >> (sizeof(value)*8 - chan->scan_type.realbits);
This looks scarey. There is a sign_extend32 function. It probably makes
sense to add one which works on ints. Btw. I think until the sign extension
the type should still be unsigned. This will also get rid of the duplicated
code.
> + } else {
> + switch (chan->scan_type.storagebits) {
> + case 8:
> + value = *(u8 *)(data);
> + break;
> + case 16:
> + value = *(u16 *)(data);
> + break;
> + case 32:
> + value = *(u32 *)(data);
> + break;
> + default:
> + return -EINVAL;
> + }
> + value >>= chan->scan_type.shift;
> + value &= (1 << chan->scan_type.realbits) - 1;
> + }
> + *val = value;
This function probably needs to be extended to deal with the endianness
field of the scan type at some point.
> +
> + return 0;
> +}
> +
> +static int iio_input_store_to(u8 *data, void *private)
> +{
> + struct iio_input_state *st = private;
> + struct iio_channel *channel;
> + struct iio_input_channel_data *input_data;
> + int offset = 0;
> + int value, ret;
> +
> + channel = iio_channel_cb_get_channels(st->buff);
> + while (channel->indio_dev) {
> + input_data = channel->data;
> + offset = ALIGN(offset,
> + channel->channel->scan_type.storagebits/8);
> + offset += channel->channel->scan_type.storagebits/8;
Maybe I'm missing something, but shouldn't offset be increased after reading
the data?
> + ret = iio_channel_value(&data[offset],
> + channel->channel,
> + &value);
> + if (ret < 0)
> + return ret;
> + input_report_abs(st->idev, input_data->code, value);
> + }
> + input_sync(st->idev);
> +
> + return 0;
> +}
> +
[...]
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-06-09 12:17 ` Jonathan Cameron
@ 2012-06-09 11:50 ` Lars-Peter Clausen
2012-06-09 17:56 ` Jonathan Cameron
0 siblings, 1 reply; 16+ messages in thread
From: Lars-Peter Clausen @ 2012-06-09 11:50 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio
On 06/09/2012 02:17 PM, Jonathan Cameron wrote:
>>> [...]
>>> @@ -534,31 +453,186 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
>>> return bytes;
>>> }
>>>
>>> -int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>>> +int iio_update_buffers(struct iio_dev *indio_dev,
>>> + struct iio_buffer *insert_buffer,
>>> + struct iio_buffer *remove_buffer)
>>> {
>>> - struct iio_buffer *buffer = indio_dev->buffer;
>>> - dev_dbg(&indio_dev->dev, "%s\n", __func__);
>>> + int ret;
>>
>> drivers/iio/industrialio-buffer.c: In function ‘iio_update_buffers’:
>> drivers/iio/industrialio-buffer.c:460: warning: ‘ret’ may be used
>> uninitialized in this function
>>
>> I think there a missing 'return 0', before the error handling. Right now the
>> code always sets active_scan_mask to NULL.
> The setting to NULL definitely isn't right, but we do still need to
> free the compoundmask. I'll fix that up.
Only if compoundmask != active_scan_mask
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-06-08 15:13 ` Lars-Peter Clausen
@ 2012-06-09 12:17 ` Jonathan Cameron
2012-06-09 11:50 ` Lars-Peter Clausen
0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-09 12:17 UTC (permalink / raw)
To: Lars-Peter Clausen; +Cc: linux-iio
On 06/08/2012 04:13 PM, Lars-Peter Clausen wrote:
> On 05/30/2012 09:36 PM, Jonathan Cameron wrote:
>> Route all buffer writes through the demux.
>> Addition or removal of a buffer results in tear down and
>> setup of all the buffers for a given device.
>>
>=20
> My test platform is currently broken in staging-next, so just some co=
mments
> based on code review for now.
Annoying when that happens!
Thanks for taking a look. This codes now been sitting around
long enough that I'm not entirely sure what some of it does myself...
>=20
>> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
>> ---
>> drivers/iio/industrialio-buffer.c | 335 ++++++++++++=
+++--------
>> drivers/iio/industrialio-core.c | 1 +
>> drivers/staging/iio/accel/adis16201_ring.c | 4 +-
>> drivers/staging/iio/accel/adis16203_ring.c | 6 +-
>> drivers/staging/iio/accel/adis16204_ring.c | 3 +-
>> drivers/staging/iio/accel/adis16209_ring.c | 3 +-
>> drivers/staging/iio/accel/adis16240_ring.c | 4 +-
>> drivers/staging/iio/accel/lis3l02dq_ring.c | 3 +-
>> drivers/staging/iio/adc/ad7192.c | 3 +-
>> drivers/staging/iio/adc/ad7298_ring.c | 5 +-
>> drivers/staging/iio/adc/ad7476_ring.c | 2 +-
>> drivers/staging/iio/adc/ad7606_ring.c | 3 +-
>> drivers/staging/iio/adc/ad7793.c | 3 +-
>> drivers/staging/iio/adc/ad7887_ring.c | 2 +-
>> drivers/staging/iio/adc/ad799x_ring.c | 3 +-
>> drivers/staging/iio/adc/max1363_ring.c | 2 +-
>> drivers/staging/iio/gyro/adis16260_ring.c | 3 +-
>> drivers/staging/iio/iio_simple_dummy_buffer.c | 5 +-
>> drivers/staging/iio/impedance-analyzer/ad5933.c | 3 +-
>> drivers/staging/iio/imu/adis16400_ring.c | 2 +-
>> drivers/staging/iio/meter/ade7758_ring.c | 3 +-
>> include/linux/iio/buffer.h | 24 +-
>> include/linux/iio/iio.h | 2 +
>=20
> The at91_adc driver is not handled by this patch
good point. oops. Darn these new drivers ;)
>=20
>> 23 files changed, 267 insertions(+), 157 deletions(-)
>>
>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industr=
ialio-buffer.c
>> index ac185b8..b04b543 100644
>> --- a/drivers/iio/industrialio-buffer.c
>> +++ b/drivers/iio/industrialio-buffer.c
>> @@ -31,6 +31,16 @@ static const char * const iio_endian_prefix[] =3D=
{
>> [IIO_LE] =3D "le",
>> };
>> =20
>> +static bool iio_buffer_is_primary_active(struct iio_dev *indio_dev)
>> +{
>> + struct list_head *p;
>> +
>> + list_for_each(p, &indio_dev->buffer_list)
>> + if (p =3D=3D &indio_dev->buffer->buffer_list)
>> + return true;
>=20
> More or less the same code is used below. I think it makes sense to h=
ave a
> generic iio_buffer_is_active(indio_dev, buffer)
Good point.
>=20
>> + return false;
>> +}
>=20
>> [...]
>> @@ -534,31 +453,186 @@ static int iio_compute_scan_bytes(struct iio_=
dev *indio_dev, const long *mask,
>> return bytes;
>> }
>> =20
>> -int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>> +int iio_update_buffers(struct iio_dev *indio_dev,
>> + struct iio_buffer *insert_buffer,
>> + struct iio_buffer *remove_buffer)
>> {
>> - struct iio_buffer *buffer =3D indio_dev->buffer;
>> - dev_dbg(&indio_dev->dev, "%s\n", __func__);
>> + int ret;
>=20
> drivers/iio/industrialio-buffer.c: In function =91iio_update_buffers=92=
:
> drivers/iio/industrialio-buffer.c:460: warning: =91ret=92 may be used
> uninitialized in this function
>=20
> I think there a missing 'return 0', before the error handling. Right =
now the
> code always sets active_scan_mask to NULL.
The setting to NULL definitely isn't right, but we do still need to
free the compoundmask. I'll fix that up.
>=20
>=20
>> + struct iio_buffer *buffer;
>> + unsigned long *compound_mask;
>> =20
>> - /* How much space will the demuxed element take? */
>> - indio_dev->scan_bytes =3D
>> - iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
>> - buffer->scan_timestamp);
>> - buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes)=
;
>> + /* Wind down existing buffers - iff there are any */
>> + if (!list_empty(&indio_dev->buffer_list)) {
>> + if (indio_dev->setup_ops->predisable) {
>> + ret =3D indio_dev->setup_ops->predisable(indio_dev);
>> + if (ret)
>> + goto error_ret;
>> + }
>> + indio_dev->currentmode =3D INDIO_DIRECT_MODE;
>> + if (indio_dev->setup_ops->postdisable) {
>> + ret =3D indio_dev->setup_ops->postdisable(indio_dev);
>> + if (ret)
>> + goto error_ret;
>> + }
>> + }
>> + if (!indio_dev->available_scan_masks)
>> + kfree(indio_dev->active_scan_mask);
>=20
> If the code errors out before reassigning active_scan_mask we'll leav=
e a
> dangling pointer to the old scan mask, which will cause access after =
free or
> a double free.
good point this needs to be set to NULL.
>=20
>> +
>> + if (insert_buffer)
>> + list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
>> + if (remove_buffer)
>> + list_del(&remove_buffer->buffer_list);
>=20
> I'd do the remove before the insert, makes this more robust, if the f=
unction
> is ever going to be called with both set to the same buffer.
Tempting as it is to take the view we should crash hard if anyone does
that you are right of course ;)
>=20
>> +
>> + /* If no buffers in list, we are done */
>> + if (list_empty(&indio_dev->buffer_list))
>> + return 0;
>> =20
>> /* What scan mask do we actually have ?*/
>> + compound_mask =3D kzalloc(BITS_TO_LONGS(indio_dev->masklength)
>> + *sizeof(long), GFP_KERNEL);
>> + if (compound_mask =3D=3D NULL)
>> + return -ENOMEM;
>> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) =
{
>> + bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
>> + indio_dev->masklength);
>> + indio_dev->scan_timestamp |=3D buffer->scan_timestamp;
>> + }
>> if (indio_dev->available_scan_masks)
>> indio_dev->active_scan_mask =3D
>> iio_scan_mask_match(indio_dev->available_scan_masks,
>> indio_dev->masklength,
>> - buffer->scan_mask);
>> + compound_mask);
>=20
> active_scan_mask may be NULL if the device isn't able to handle the c=
ompound
> mask.
>=20
> Btw. if it is not possible to add the new buffer to the list, e.g. be=
cause
> the compound scan mask is not supported, do we to do a rollback to th=
e
> previous working configuration? I think this might be a better option=
,
> rather than leaving things broken.
hmm.. Indeed, that is a good idea... Adds a bit of complexity, but not
too bad.
>=20
>> else
>> - indio_dev->active_scan_mask =3D buffer->scan_mask;
>> + indio_dev->active_scan_mask =3D compound_mask;
>> +
>> iio_update_demux(indio_dev);
>> =20
>> - if (indio_dev->info->update_scan_mode)
>> - return indio_dev->info
>> + /* Wind up again */
>> + if (indio_dev->setup_ops->preenable) {
>> + ret =3D indio_dev->setup_ops->preenable(indio_dev);
>> + if (ret) {
>> + printk(KERN_ERR
>> + "Buffer not started:"
>> + "buffer preenable failed\n");
>> + goto error_free_compound_mask;
>> + }
>> + }
>> + indio_dev->scan_bytes =3D
>> + iio_compute_scan_bytes(indio_dev,
>> + indio_dev->active_scan_mask,
>> + indio_dev->scan_timestamp);
>> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
>> + if (buffer->access->request_update) {
>> + ret =3D buffer->access->request_update(buffer);
>> + if (ret) {
>> + printk(KERN_INFO
>> + "Buffer not started:"
>> + "buffer parameter update failed\n");
>> + goto error_ret;
>> + }
>> + }
>> + if (indio_dev->info->update_scan_mode) {
>> + ret =3D indio_dev->info
>> ->update_scan_mode(indio_dev,
>> indio_dev->active_scan_mask);
>> + if (ret < 0)
>> + goto error_free_compound_mask;
>> + }
>> + /* Definitely possible for devices to support both of these.*/
>> + if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
>> + if (!indio_dev->trig) {
>> + printk(KERN_INFO "Buffer not started: no trigger\n");
>> + ret =3D -EINVAL;
>> + goto error_free_compound_mask;
>> + }
>> + indio_dev->currentmode =3D INDIO_BUFFER_TRIGGERED;
>> + } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
>> + indio_dev->currentmode =3D INDIO_BUFFER_HARDWARE;
>> + } else { /* should never be reached */
>> + ret =3D -EINVAL;
>> + goto error_free_compound_mask;
>> + }
>> +
>> + if (indio_dev->setup_ops->postenable) {
>> + ret =3D indio_dev->setup_ops->postenable(indio_dev);
>> + if (ret) {
>> + printk(KERN_INFO
>> + "Buffer not started: postenable failed\n");
>> + indio_dev->currentmode =3D INDIO_DIRECT_MODE;
>> + if (indio_dev->setup_ops->postdisable)
>> + indio_dev->setup_ops->postdisable(indio_dev);
>> + goto error_free_compound_mask;
>> + }
>> + }
>> +error_free_compound_mask:
>> + indio_dev->active_scan_mask =3D NULL;
>> + kfree(compound_mask);
>> +error_ret:
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_update_buffers);
>> +
>> +ssize_t iio_buffer_store_enable(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf,
>> + size_t len)
>> +{
>> + int ret;
>> + bool requested_state;
>> + struct iio_dev *indio_dev =3D dev_get_drvdata(dev);
>> + struct iio_buffer *pbuf =3D indio_dev->buffer;
>> + struct list_head *p;
>> + bool inlist =3D false;
>> +
>> + ret =3D strtobool(buf, &requested_state);
>> + if (ret < 0)
>> + return ret;
>> +
>> + mutex_lock(&indio_dev->mlock);
>> +
>> + /* Find out if it is in the list */
>> + list_for_each(p, &indio_dev->buffer_list)
>> + if (p =3D=3D &pbuf->buffer_list) {
>> + inlist =3D true;
>> + break;
>> + }
>> + /* Already enabled */
>> + if (inlist && requested_state)
>> + goto done;
>> + /* Already disabled */
>> + if (!inlist && !requested_state)
>> + goto done;
>=20
> if (inlist =3D=3D requested_state)
> goto done;
>=20
>> +
>> + if (requested_state)
>> + ret =3D iio_update_buffers(indio_dev,
>> + indio_dev->buffer, NULL);
>> + else
>> + ret =3D iio_update_buffers(indio_dev,
>> + NULL, indio_dev->buffer);
>> +
>> + if (ret < 0)
>> + goto done;
>> +done:
>> + mutex_unlock(&indio_dev->mlock);
>> + return (ret < 0) ? ret : len;
>> +}
>> +EXPORT_SYMBOL(iio_buffer_store_enable);
>> +
> [...]
>> @@ -567,7 +641,11 @@ EXPORT_SYMBOL(iio_sw_buffer_preenable);
>> * iio_scan_mask_set() - set particular bit in the scan mask
>> * @buffer: the buffer whose scan mask we are interested in
>> * @bit: the bit to be set.
>> - **/
>> + *
>> + * Note that at this point we have no way of knowing what other
>> + * buffers might request, hence this code only verifies that the
>> + * individual buffers request is plausible.
>> + */
>> int iio_scan_mask_set(struct iio_dev *indio_dev,
>> struct iio_buffer *buffer, int bit)
>> {
>> @@ -597,7 +675,7 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
>> return -EINVAL;
>> }
>> }
>> - bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
>> + set_bit(bit, buffer->scan_mask);
>=20
> Is this a unrelated fix?
Slight simplification. Doesn't belong in this patch (and probably not
worth having at all really...
>=20
>> =20
>> kfree(trialmask);
>> =20
> [...]
>> diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers=
/staging/iio/iio_simple_dummy_buffer.c
>> index fdfc873..5931cbb 100644
>> --- a/drivers/staging/iio/iio_simple_dummy_buffer.c
>> +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
>> @@ -46,7 +46,6 @@ static irqreturn_t iio_simple_dummy_trigger_h(int =
irq, void *p)
>> {
>> struct iio_poll_func *pf =3D p;
>> struct iio_dev *indio_dev =3D pf->indio_dev;
>> - struct iio_buffer *buffer =3D indio_dev->buffer;
>> int len =3D 0;
>> u16 *data;
>> =20
>> @@ -76,7 +75,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int =
irq, void *p)
>> i < bitmap_weight(indio_dev->active_scan_mask,
>> indio_dev->masklength);
>> i++) {
>> - j =3D find_next_bit(buffer->scan_mask,
>> + j =3D find_next_bit(indio_dev->buffer->scan_mask,
>=20
> should this be indio_dev->active_scan_mask?
This bit always give me a headache. You are right of course. It's in
the trigger handler so should not care at all about the specific buffer
mask.
>=20
>> indio_dev->masklength, j + 1);
>> /* random access read form the 'device' */
>> data[i] =3D fakedata[j];
>=20
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" =
in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 4/4] staging:iio: Proof of concept input driver.
2012-06-08 15:27 ` Lars-Peter Clausen
@ 2012-06-09 17:56 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-09 17:56 UTC (permalink / raw)
To: Lars-Peter Clausen; +Cc: linux-iio, Jonathan Cameron
On 06/08/2012 04:27 PM, Lars-Peter Clausen wrote:
> On 05/30/2012 09:36 PM, Jonathan Cameron wrote:
>> From: Jonathan Cameron <jic23@cam.ac.uk>
>>
>> This is no where near ready to merge. Lots of stuff missing.
>>
>> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
>> ---
>> drivers/staging/iio/Kconfig | 11 +++
>> drivers/staging/iio/Makefile | 1 +
>> drivers/staging/iio/iio_input.c | 176 +++++++++++++++++++++++++++++++++++++++
>> drivers/staging/iio/iio_input.h | 23 +++++
>> 4 files changed, 211 insertions(+)
>>
>> diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
>> index 04cd6ec..022463e 100644
>> --- a/drivers/staging/iio/Kconfig
>> +++ b/drivers/staging/iio/Kconfig
>> @@ -4,6 +4,17 @@
> [...]
>> +};
>> +
>> +static int iio_channel_value(u8 *data,
>> + const struct iio_chan_spec *chan,
>> + int *val)
>> +{
>> + int value;
>> +
>> + if (chan->scan_type.sign == 's') {
>> + switch (chan->scan_type.storagebits) {
>> + case 8:
>> + value = *(s8 *)(data);
>> + break;
>> + case 16:
>> + value = *(s16 *)(data);
>> + break;
>> + case 32:
>> + value = *(s32 *)(data);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + value >>= chan->scan_type.shift;
>> + value &= (1 << chan->scan_type.realbits) - 1;
>> + value = (value << (sizeof(value)*8 - chan->scan_type.realbits))
>> + >> (sizeof(value)*8 - chan->scan_type.realbits);
>
> This looks scarey. There is a sign_extend32 function. It probably makes
> sense to add one which works on ints. Btw. I think until the sign extension
> the type should still be unsigned. This will also get rid of the duplicated
> code.
Not sure there is any real reason not to use sign_extend32 as is. Can
just convert much later at the input_report_abs call.
>
>> + } else {
>> + switch (chan->scan_type.storagebits) {
>> + case 8:
>> + value = *(u8 *)(data);
>> + break;
>> + case 16:
>> + value = *(u16 *)(data);
>> + break;
>> + case 32:
>> + value = *(u32 *)(data);
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> + value >>= chan->scan_type.shift;
>> + value &= (1 << chan->scan_type.realbits) - 1;
>> + }
>> + *val = value;
>
> This function probably needs to be extended to deal with the endianness
> field of the scan type at some point.
Yup. Lots of extensions needed to this driver....
>> +
>> + return 0;
>> +}
>> +
>> +static int iio_input_store_to(u8 *data, void *private)
>> +{
>> + struct iio_input_state *st = private;
>> + struct iio_channel *channel;
>> + struct iio_input_channel_data *input_data;
>> + int offset = 0;
>> + int value, ret;
>> +
>> + channel = iio_channel_cb_get_channels(st->buff);
>> + while (channel->indio_dev) {
>> + input_data = channel->data;
>> + offset = ALIGN(offset,
>> + channel->channel->scan_type.storagebits/8);
>> + offset += channel->channel->scan_type.storagebits/8;
>
> Maybe I'm missing something, but shouldn't offset be increased after reading
> the data?
Indeed. I'm clearly going mad ;)
>
>> + ret = iio_channel_value(&data[offset],
>> + channel->channel,
>> + &value);
>> + if (ret < 0)
>> + return ret;
>> + input_report_abs(st->idev, input_data->code, value);
>> + }
>> + input_sync(st->idev);
>> +
>> + return 0;
>> +}
>> +
> [...]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-06-09 11:50 ` Lars-Peter Clausen
@ 2012-06-09 17:56 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-09 17:56 UTC (permalink / raw)
To: Lars-Peter Clausen; +Cc: linux-iio
On 06/09/2012 12:50 PM, Lars-Peter Clausen wrote:
> On 06/09/2012 02:17 PM, Jonathan Cameron wrote:
>>>> [...]
>>>> @@ -534,31 +453,186 @@ static int iio_compute_scan_bytes(struct ii=
o_dev *indio_dev, const long *mask,
>>>> return bytes;
>>>> }
>>>> =20
>>>> -int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>>>> +int iio_update_buffers(struct iio_dev *indio_dev,
>>>> + struct iio_buffer *insert_buffer,
>>>> + struct iio_buffer *remove_buffer)
>>>> {
>>>> - struct iio_buffer *buffer =3D indio_dev->buffer;
>>>> - dev_dbg(&indio_dev->dev, "%s\n", __func__);
>>>> + int ret;
>>>
>>> drivers/iio/industrialio-buffer.c: In function =91iio_update_buffer=
s=92:
>>> drivers/iio/industrialio-buffer.c:460: warning: =91ret=92 may be us=
ed
>>> uninitialized in this function
>>>
>>> I think there a missing 'return 0', before the error handling. Righ=
t now the
>>> code always sets active_scan_mask to NULL.
>> The setting to NULL definitely isn't right, but we do still need to
>> free the compoundmask. I'll fix that up.
>=20
> Only if compoundmask !=3D active_scan_mask
indeed.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" =
in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-06-30 19:06 [PATCH 0/4 V3] staging:iio: Add support for multiple buffers Jonathan Cameron
@ 2012-06-30 19:06 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-06-30 19:06 UTC (permalink / raw)
To: linux-iio; +Cc: Jonathan Cameron
Route all buffer writes through the demux.
Addition or removal of a buffer results in tear down and
setup of all the buffers for a given device.
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/iio/adc/at91_adc.c | 4 +-
drivers/iio/industrialio-buffer.c | 378 ++++++++++++++++--------
drivers/iio/industrialio-core.c | 1 +
drivers/staging/iio/accel/adis16201_ring.c | 4 +-
drivers/staging/iio/accel/adis16203_ring.c | 6 +-
drivers/staging/iio/accel/adis16204_ring.c | 3 +-
drivers/staging/iio/accel/adis16209_ring.c | 3 +-
drivers/staging/iio/accel/adis16240_ring.c | 4 +-
drivers/staging/iio/accel/lis3l02dq_ring.c | 3 +-
drivers/staging/iio/adc/ad7192.c | 3 +-
drivers/staging/iio/adc/ad7298_ring.c | 5 +-
drivers/staging/iio/adc/ad7476_ring.c | 2 +-
drivers/staging/iio/adc/ad7606_ring.c | 3 +-
drivers/staging/iio/adc/ad7793.c | 3 +-
drivers/staging/iio/adc/ad7887_ring.c | 2 +-
drivers/staging/iio/adc/ad799x_ring.c | 3 +-
drivers/staging/iio/adc/max1363_ring.c | 2 +-
drivers/staging/iio/gyro/adis16260_ring.c | 3 +-
drivers/staging/iio/iio_simple_dummy_buffer.c | 5 +-
drivers/staging/iio/impedance-analyzer/ad5933.c | 3 +-
drivers/staging/iio/imu/adis16400_ring.c | 2 +-
drivers/staging/iio/meter/ade7758_ring.c | 3 +-
include/linux/iio/buffer.h | 24 +-
include/linux/iio/iio.h | 2 +
24 files changed, 305 insertions(+), 166 deletions(-)
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index f61780a..10525d3 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -66,7 +66,6 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *idev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(idev);
- struct iio_buffer *buffer = idev->buffer;
int i, j = 0;
for (i = 0; i < idev->masklength; i++) {
@@ -81,8 +80,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
ALIGN(j, sizeof(s64)));
*timestamp = pf->timestamp;
}
-
- buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)st->buffer, pf->timestamp);
iio_trigger_notify_done(idev->trig);
st->irq_enabled = true;
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 3d8d187..3ffda2c 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -31,6 +31,18 @@ static const char * const iio_endian_prefix[] = {
[IIO_LE] = "le",
};
+static bool iio_buffer_is_active(struct iio_dev *indio_dev,
+ struct iio_buffer *buf)
+{
+ struct list_head *p;
+
+ list_for_each(p, &indio_dev->buffer_list)
+ if (p == &buf->buffer_list)
+ return true;
+
+ return false;
+}
+
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
*
@@ -134,7 +146,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
if (ret < 0)
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
@@ -180,12 +192,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
- indio_dev->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@@ -385,7 +396,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
return len;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
} else {
if (buffer->access->set_length)
@@ -398,102 +409,14 @@ ssize_t iio_buffer_write_length(struct device *dev,
}
EXPORT_SYMBOL(iio_buffer_write_length);
-ssize_t iio_buffer_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- bool requested_state, current_state;
- int previous_mode;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
-
- mutex_lock(&indio_dev->mlock);
- previous_mode = indio_dev->currentmode;
- requested_state = !(buf[0] == '0');
- current_state = iio_buffer_enabled(indio_dev);
- if (current_state == requested_state) {
- printk(KERN_INFO "iio-buffer, current state requested again\n");
- goto done;
- }
- if (requested_state) {
- if (indio_dev->setup_ops->preenable) {
- ret = indio_dev->setup_ops->preenable(indio_dev);
- if (ret) {
- printk(KERN_ERR
- "Buffer not started:"
- "buffer preenable failed\n");
- goto error_ret;
- }
- }
- if (buffer->access->request_update) {
- ret = buffer->access->request_update(buffer);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started:"
- "buffer parameter update failed\n");
- goto error_ret;
- }
- }
- /* Definitely possible for devices to support both of these.*/
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
- if (!indio_dev->trig) {
- printk(KERN_INFO
- "Buffer not started: no trigger\n");
- ret = -EINVAL;
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
- } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
- indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
- else { /* should never be reached */
- ret = -EINVAL;
- goto error_ret;
- }
-
- if (indio_dev->setup_ops->postenable) {
- ret = indio_dev->setup_ops->postenable(indio_dev);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started:"
- "postenable failed\n");
- indio_dev->currentmode = previous_mode;
- if (indio_dev->setup_ops->postdisable)
- indio_dev->setup_ops->
- postdisable(indio_dev);
- goto error_ret;
- }
- }
- } else {
- if (indio_dev->setup_ops->predisable) {
- ret = indio_dev->setup_ops->predisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_DIRECT_MODE;
- if (indio_dev->setup_ops->postdisable) {
- ret = indio_dev->setup_ops->postdisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- }
-done:
- mutex_unlock(&indio_dev->mlock);
- return len;
-
-error_ret:
- mutex_unlock(&indio_dev->mlock);
- return ret;
-}
-EXPORT_SYMBOL(iio_buffer_store_enable);
-
ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
+ return sprintf(buf, "%d\n",
+ iio_buffer_is_active(indio_dev,
+ indio_dev->buffer));
}
EXPORT_SYMBOL(iio_buffer_show_enable);
@@ -537,35 +460,217 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
return bytes;
}
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
+ int ret;
+ int success = 0;
+ struct iio_buffer *buffer;
+ unsigned long *compound_mask;
+ const unsigned long *old_mask;
- /* How much space will the demuxed element take? */
- indio_dev->scan_bytes =
- iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
- buffer->scan_timestamp);
- buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
+ /* Wind down existing buffers - iff there are any */
+ if (!list_empty(&indio_dev->buffer_list)) {
+ if (indio_dev->setup_ops->predisable) {
+ ret = indio_dev->setup_ops->predisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable) {
+ ret = indio_dev->setup_ops->postdisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ }
+ /* Keep a copy of current setup to allow roll back */
+ old_mask = indio_dev->active_scan_mask;
+ if (!indio_dev->available_scan_masks)
+ indio_dev->active_scan_mask = NULL;
+
+ if (remove_buffer)
+ list_del(&remove_buffer->buffer_list);
+ if (insert_buffer)
+ list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
+
+ /* If no buffers in list, we are done */
+ if (list_empty(&indio_dev->buffer_list)) {
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ return 0;
+ }
/* What scan mask do we actually have ?*/
- if (indio_dev->available_scan_masks)
+ compound_mask = kzalloc(BITS_TO_LONGS(indio_dev->masklength)
+ *sizeof(long), GFP_KERNEL);
+ if (compound_mask == NULL)
+ return -ENOMEM;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
+ indio_dev->masklength);
+ indio_dev->scan_timestamp |= buffer->scan_timestamp;
+ }
+ if (indio_dev->available_scan_masks) {
indio_dev->active_scan_mask =
iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
- buffer->scan_mask);
- else
- indio_dev->active_scan_mask = buffer->scan_mask;
-
- if (indio_dev->active_scan_mask == NULL)
- return -EINVAL;
+ compound_mask);
+ if (indio_dev->active_scan_mask == NULL) {
+ /*
+ * Roll back.
+ * Note can only occur when adding a buffer.
+ */
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ success = -EINVAL;
+ }
+ } else {
+ indio_dev->active_scan_mask = compound_mask;
+ }
iio_update_demux(indio_dev);
- if (indio_dev->info->update_scan_mode)
- return indio_dev->info
+ /* Wind up again */
+ if (indio_dev->setup_ops->preenable) {
+ ret = indio_dev->setup_ops->preenable(indio_dev);
+ if (ret) {
+ printk(KERN_ERR
+ "Buffer not started:"
+ "buffer preenable failed\n");
+ goto error_remove_inserted;
+ }
+ }
+ indio_dev->scan_bytes =
+ iio_compute_scan_bytes(indio_dev,
+ indio_dev->active_scan_mask,
+ indio_dev->scan_timestamp);
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->request_update) {
+ ret = buffer->access->request_update(buffer);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started:"
+ "buffer parameter update failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ if (indio_dev->info->update_scan_mode) {
+ ret = indio_dev->info
->update_scan_mode(indio_dev,
indio_dev->active_scan_mask);
+ if (ret < 0) {
+ printk(KERN_INFO "update scan mode failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ /* Definitely possible for devices to support both of these.*/
+ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
+ if (!indio_dev->trig) {
+ printk(KERN_INFO "Buffer not started: no trigger\n");
+ ret = -EINVAL;
+ /* Can only occur on first buffer */
+ goto error_run_postdisable;
+ }
+ indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
+ } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
+ indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+ } else { /* should never be reached */
+ ret = -EINVAL;
+ goto error_run_postdisable;
+ }
+
+ if (indio_dev->setup_ops->postenable) {
+ ret = indio_dev->setup_ops->postenable(indio_dev);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started: postenable failed\n");
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+ goto error_disable_all_buffers;
+ }
+ }
+
+ if (indio_dev->available_scan_masks)
+ kfree(compound_mask);
+ else
+ kfree(old_mask);
+
+ return success;
+
+error_disable_all_buffers:
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+error_run_postdisable:
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+error_remove_inserted:
+
+ if (insert_buffer)
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ kfree(compound_mask);
+error_ret:
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_update_buffers);
+
+ssize_t iio_buffer_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ bool requested_state;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_buffer *pbuf = indio_dev->buffer;
+ bool inlist;
+
+ ret = strtobool(buf, &requested_state);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ /* Find out if it is in the list */
+ inlist = iio_buffer_is_active(indio_dev, pbuf);
+ /* Already enabled */
+ if (inlist && requested_state)
+ goto done;
+ /* Already disabled */
+ if (!inlist && !requested_state)
+ goto done;
+
+ if (requested_state)
+ ret = iio_update_buffers(indio_dev,
+ indio_dev->buffer, NULL);
+ else
+ ret = iio_update_buffers(indio_dev,
+ NULL, indio_dev->buffer);
+
+ if (ret < 0)
+ goto done;
+done:
+ mutex_unlock(&indio_dev->mlock);
+ return (ret < 0) ? ret : len;
+}
+EXPORT_SYMBOL(iio_buffer_store_enable);
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ unsigned bytes;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->set_bytes_per_datum) {
+ bytes = iio_compute_scan_bytes(indio_dev,
+ buffer->scan_mask,
+ buffer->scan_timestamp);
+
+ buffer->access->set_bytes_per_datum(buffer, bytes);
+ }
return 0;
}
EXPORT_SYMBOL(iio_sw_buffer_preenable);
@@ -574,7 +679,11 @@ EXPORT_SYMBOL(iio_sw_buffer_preenable);
* iio_scan_mask_set() - set particular bit in the scan mask
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
- **/
+ *
+ * Note that at this point we have no way of knowing what other
+ * buffers might request, hence this code only verifies that the
+ * individual buffers request is plausible.
+ */
int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
@@ -653,14 +762,13 @@ static unsigned char *iio_demux(struct iio_buffer *buffer,
return buffer->demux_bounce;
}
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
+static int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
s64 timestamp)
{
unsigned char *dataout = iio_demux(buffer, data);
return buffer->access->store_to(buffer, dataout, timestamp);
}
-EXPORT_SYMBOL_GPL(iio_push_to_buffer);
static void iio_buffer_demux_free(struct iio_buffer *buffer)
{
@@ -671,10 +779,27 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer)
}
}
-int iio_update_demux(struct iio_dev *indio_dev)
+
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data,
+ s64 timestamp)
+{
+ int ret;
+ struct iio_buffer *buf;
+
+ list_for_each_entry(buf, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_push_to_buffer(buf, data, timestamp);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_push_to_buffers);
+
+static int iio_buffer_update_demux(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
{
const struct iio_chan_spec *ch;
- struct iio_buffer *buffer = indio_dev->buffer;
int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0;
struct iio_demux_table *p;
@@ -759,4 +884,23 @@ error_clear_mux_table:
return ret;
}
+
+int iio_update_demux(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ int ret;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_buffer_update_demux(indio_dev, buffer);
+ if (ret < 0)
+ goto error_clear_mux_table;
+ }
+ return 0;
+
+error_clear_mux_table:
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ iio_buffer_demux_free(buffer);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index bb3c692..4d4ce3a 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -839,6 +839,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
+ INIT_LIST_HEAD(&dev->buffer_list);
}
return dev;
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 247602a..64ba02a 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -62,8 +62,6 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16201_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
@@ -83,7 +81,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 7bbd2c2..57480f4 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -61,8 +61,6 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16203_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
@@ -82,9 +80,7 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring,
- (u8 *)data,
- pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index f73518b..3a5d459 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -59,7 +59,6 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16204_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
@@ -79,7 +78,7 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index 0906075..155fc79 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -59,7 +59,6 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16209_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
@@ -79,7 +78,7 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index 86a2a47..dec6646 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -56,8 +56,6 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16240_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
-
int i = 0;
s16 *data;
@@ -77,7 +75,7 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 51b00df..7129e22 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -135,7 +135,6 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
char *data;
@@ -154,7 +153,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
*(s64 *)(((phys_addr_t)data + len
+ sizeof(s64) - 1) & ~(sizeof(s64) - 1))
= pf->timestamp;
- buffer->access->store_to(buffer, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index 839f17c..3d8f27e 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -510,7 +510,6 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *ring = indio_dev->buffer;
struct ad7192_state *st = iio_priv(indio_dev);
s64 dat64[2];
s32 *dat32 = (s32 *)dat64;
@@ -524,7 +523,7 @@ static irqreturn_t ad7192_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
st->irq_dis = false;
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index cd3e9cb..f71919f 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -75,7 +75,6 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad7298_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u16 buf[16];
int b_sent, i;
@@ -91,10 +90,10 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
}
for (i = 0; i < bitmap_weight(indio_dev->active_scan_mask,
- indio_dev->masklength); i++)
+ indio_dev->masklength); i++)
buf[i] = be16_to_cpu(st->rx_buf[i]);
- indio_dev->buffer->access->store_to(ring, (u8 *)buf, time_ns);
+ iio_push_to_buffers(indio_dev, (u8 *)buf, time_ns);
iio_trigger_notify_done(indio_dev->trig);
return IRQ_HANDLED;
diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c
index 10f8b8d..add4d09 100644
--- a/drivers/staging/iio/adc/ad7476_ring.c
+++ b/drivers/staging/iio/adc/ad7476_ring.c
@@ -44,7 +44,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns);
+ iio_push_to_buffers(indio_dev, rxbuf, time_ns);
done:
iio_trigger_notify_done(indio_dev->trig);
kfree(rxbuf);
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index f15afe4..59ec62e 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -46,7 +46,6 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
struct ad7606_state *st = container_of(work_s, struct ad7606_state,
poll_work);
struct iio_dev *indio_dev = iio_priv_to_dev(st);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u8 *buf;
int ret;
@@ -84,7 +83,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
if (indio_dev->scan_timestamp)
*((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
- ring->access->store_to(indio_dev->buffer, buf, time_ns);
+ iio_push_to_buffers(indio_dev, buf, time_ns);
done:
gpio_set_value(st->pdata->gpio_convst, 0);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c
index eaa0cc9..d00cced 100644
--- a/drivers/staging/iio/adc/ad7793.c
+++ b/drivers/staging/iio/adc/ad7793.c
@@ -375,7 +375,6 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *ring = indio_dev->buffer;
struct ad7793_state *st = iio_priv(indio_dev);
s64 dat64[2];
s32 *dat32 = (s32 *)dat64;
@@ -389,7 +388,7 @@ static irqreturn_t ad7793_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
st->irq_dis = false;
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index 1c406da..6c20b80 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -95,7 +95,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns);
+ iio_push_to_buffers(indio_dev, buf, time_ns);
done:
kfree(buf);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 0882c9e..8a175de 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -35,7 +35,6 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct ad799x_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
s64 time_ns;
__u8 *rxbuf;
int b_sent;
@@ -78,7 +77,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- ring->access->store_to(indio_dev->buffer, rxbuf, time_ns);
+ iio_push_to_buffers(indio_dev, rxbuf, time_ns);
done:
kfree(rxbuf);
if (b_sent < 0)
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index b302013..73273c0 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -80,7 +80,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns);
+ iio_push_to_buffers(indio_dev, rxbuf, time_ns);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index 0fe2d9d..4922a6d 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -62,7 +62,6 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16260_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0;
s16 *data;
@@ -82,7 +81,7 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(ring, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
kfree(data);
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index b9e6093..f717ed4 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -46,7 +46,6 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
u16 *data;
@@ -76,7 +75,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
i++, j++) {
- j = find_next_bit(buffer->scan_mask,
+ j = find_next_bit(indio_dev->active_scan_mask,
indio_dev->masklength, j);
/* random access read from the 'device' */
data[i] = fakedata[j];
@@ -87,7 +86,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((phys_addr_t)data + ALIGN(len, sizeof(s64)))
= iio_get_time_ns();
- buffer->access->store_to(buffer, (u8 *)data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)data, pf->timestamp);
kfree(data);
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index a8e51bc..3599ec1 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -647,7 +647,6 @@ static void ad5933_work(struct work_struct *work)
struct ad5933_state *st = container_of(work,
struct ad5933_state, work.work);
struct iio_dev *indio_dev = i2c_get_clientdata(st->client);
- struct iio_buffer *ring = indio_dev->buffer;
signed short buf[2];
unsigned char status;
@@ -678,7 +677,7 @@ static void ad5933_work(struct work_struct *work)
buf[0] = be16_to_cpu(buf[0]);
}
/* save datum to the ring */
- ring->access->store_to(ring, (u8 *)buf, iio_get_time_ns());
+ iio_push_to_buffers(indio_dev, (u8 *)buf, iio_get_time_ns());
} else {
/* no data available - try again later */
schedule_delayed_work(&st->work, st->poll_time_jiffies);
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 809e2c4..4c0dac8 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -150,7 +150,7 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
/* Guaranteed to be aligned with 8 byte boundary */
if (ring->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- ring->access->store_to(indio_dev->buffer, (u8 *) data, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *) data, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 92159f2..0b0edd2 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -61,7 +61,6 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *ring = indio_dev->buffer;
struct ade7758_state *st = iio_priv(indio_dev);
s64 dat64[2];
u32 *dat32 = (u32 *)dat64;
@@ -74,7 +73,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- ring->access->store_to(ring, (u8 *)dat64, pf->timestamp);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64, pf->timestamp);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index ad4fb1a..53e72b9 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -66,7 +66,8 @@ struct iio_buffer_access_funcs {
* @stufftoread: [INTERN] flag to indicate new data.
* @demux_list: [INTERN] list of operations required to demux the scan.
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
- **/
+ * @buffer_list: [INTERN] entry in the devices list of current buffers.
+ */
struct iio_buffer {
int length;
int bytes_per_datum;
@@ -81,9 +82,22 @@ struct iio_buffer {
const struct attribute_group *attrs;
struct list_head demux_list;
unsigned char *demux_bounce;
+ struct list_head buffer_list;
};
/**
+ * iio_update_buffers() - add or remove buffer from active list
+ * @indio_dev: device to add buffer to
+ * @insert_buffer: buffer to insert
+ * @remove_buffer: buffer_to_remove
+ *
+ * Note this will tear down the all buffering and build it up again
+ */
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer);
+
+/**
* iio_buffer_init() - Initialize the buffer structure
* @buffer: buffer to be initialized
**/
@@ -114,12 +128,12 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit);
/**
- * iio_push_to_buffer() - push to a registered buffer.
- * @buffer: IIO buffer structure for device
- * @scan: Full scan.
+ * iio_push_to_buffers() - push to a registered buffer.
+ * @indio_dev: iio_dev structure for device.
+ * @data: Full scan.
* @timestamp:
*/
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data,
s64 timestamp);
int iio_update_demux(struct iio_dev *indio_dev);
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 2afbb6f..b9c8ff0 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -380,6 +380,7 @@ struct iio_buffer_setup_ops {
* and owner
* @event_interface: [INTERN] event chrdevs associated with interrupt lines
* @buffer: [DRIVER] any buffer present
+ * @buffer_list: [INTERN] list of all buffers currently attached
* @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
* @mlock: [INTERN] lock used to prevent simultaneous device state
* changes
@@ -418,6 +419,7 @@ struct iio_dev {
struct iio_event_interface *event_interface;
struct iio_buffer *buffer;
+ struct list_head buffer_list;
int scan_bytes;
struct mutex mlock;
--
1.7.11.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-10-13 9:24 [PATCH 0/4 V5] staging:iio: Add support for multiple buffers (testing required!) Jonathan Cameron
@ 2012-10-13 9:24 ` Jonathan Cameron
2012-10-17 8:37 ` Lars-Peter Clausen
0 siblings, 1 reply; 16+ messages in thread
From: Jonathan Cameron @ 2012-10-13 9:24 UTC (permalink / raw)
To: linux-iio; +Cc: Michael.Hennerich, lars, srinivas.pandruvada, Jonathan Cameron
Route all buffer writes through the demux.
Addition or removal of a buffer results in tear down and
setup of all the buffers for a given device.
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
drivers/iio/accel/hid-sensor-accel-3d.c | 15 +-
drivers/iio/adc/ad7266.c | 3 +-
drivers/iio/adc/ad7476.c | 2 +-
drivers/iio/adc/ad_sigma_delta.c | 2 +-
drivers/iio/adc/at91_adc.c | 3 +-
drivers/iio/gyro/hid-sensor-gyro-3d.c | 15 +-
drivers/iio/industrialio-buffer.c | 377 ++++++++++++++++--------
drivers/iio/industrialio-core.c | 1 +
drivers/iio/light/adjd_s311.c | 3 +-
drivers/iio/light/hid-sensor-als.c | 15 +-
drivers/iio/magnetometer/hid-sensor-magn-3d.c | 15 +-
drivers/staging/iio/accel/adis16201_ring.c | 2 +-
drivers/staging/iio/accel/adis16203_ring.c | 2 +-
drivers/staging/iio/accel/adis16204_ring.c | 2 +-
drivers/staging/iio/accel/adis16209_ring.c | 2 +-
drivers/staging/iio/accel/adis16240_ring.c | 2 +-
drivers/staging/iio/accel/lis3l02dq_ring.c | 2 +-
drivers/staging/iio/adc/ad7298_ring.c | 2 +-
drivers/staging/iio/adc/ad7606_ring.c | 2 +-
drivers/staging/iio/adc/ad7887_ring.c | 2 +-
drivers/staging/iio/adc/ad799x_ring.c | 2 +-
drivers/staging/iio/adc/max1363_ring.c | 2 +-
drivers/staging/iio/gyro/adis16260_ring.c | 2 +-
drivers/staging/iio/iio_simple_dummy_buffer.c | 5 +-
drivers/staging/iio/impedance-analyzer/ad5933.c | 4 +-
drivers/staging/iio/imu/adis16400_ring.c | 5 +-
drivers/staging/iio/meter/ade7758_ring.c | 2 +-
include/linux/iio/buffer.h | 24 +-
include/linux/iio/iio.h | 2 +
29 files changed, 309 insertions(+), 208 deletions(-)
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 314a405..a95cda0 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -197,21 +197,8 @@ static const struct iio_info accel_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index b11f214..a6f4fc5 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -91,7 +91,6 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
struct ad7266_state *st = iio_priv(indio_dev);
int ret;
@@ -99,7 +98,7 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
if (ret == 0) {
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = pf->timestamp;
- iio_push_to_buffer(buffer, (u8 *)st->data);
+ iio_push_to_buffers(indio_dev, (u8 *)st->data);
}
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 7f2f45a..330248b 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -76,7 +76,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = time_ns;
- iio_push_to_buffer(indio_dev->buffer, st->data);
+ iio_push_to_buffers(indio_dev, st->data);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 67baa13..afe6d78 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -391,7 +391,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
break;
}
- iio_push_to_buffer(indio_dev->buffer, (uint8_t *)data);
+ iio_push_to_buffers(indio_dev, (uint8_t *)data);
iio_trigger_notify_done(indio_dev->trig);
sigma_delta->irq_dis = false;
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index 3ed94bf..1f9e70e 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -66,7 +66,6 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *idev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(idev);
- struct iio_buffer *buffer = idev->buffer;
int i, j = 0;
for (i = 0; i < idev->masklength; i++) {
@@ -82,7 +81,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
*timestamp = pf->timestamp;
}
- buffer->access->store_to(buffer, (u8 *)st->buffer);
+ iio_push_to_buffers(indio_dev, (u8 *)st->buffer);
iio_trigger_notify_done(idev->trig);
st->irq_enabled = true;
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 4c56ada..02ef989 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -197,21 +197,8 @@ static const struct iio_info gyro_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index d4ad374..8caa0d7 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -31,6 +31,18 @@ static const char * const iio_endian_prefix[] = {
[IIO_LE] = "le",
};
+static bool iio_buffer_is_active(struct iio_dev *indio_dev,
+ struct iio_buffer *buf)
+{
+ struct list_head *p;
+
+ list_for_each(p, &indio_dev->buffer_list)
+ if (p == &buf->buffer_list)
+ return true;
+
+ return false;
+}
+
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
*
@@ -134,7 +146,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
if (ret < 0)
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
@@ -180,12 +192,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
- indio_dev->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@@ -385,7 +396,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
return len;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
} else {
if (buffer->access->set_length)
@@ -398,102 +409,14 @@ ssize_t iio_buffer_write_length(struct device *dev,
}
EXPORT_SYMBOL(iio_buffer_write_length);
-ssize_t iio_buffer_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- bool requested_state, current_state;
- int previous_mode;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
-
- mutex_lock(&indio_dev->mlock);
- previous_mode = indio_dev->currentmode;
- requested_state = !(buf[0] == '0');
- current_state = iio_buffer_enabled(indio_dev);
- if (current_state == requested_state) {
- printk(KERN_INFO "iio-buffer, current state requested again\n");
- goto done;
- }
- if (requested_state) {
- if (indio_dev->setup_ops->preenable) {
- ret = indio_dev->setup_ops->preenable(indio_dev);
- if (ret) {
- printk(KERN_ERR
- "Buffer not started: "
- "buffer preenable failed\n");
- goto error_ret;
- }
- }
- if (buffer->access->request_update) {
- ret = buffer->access->request_update(buffer);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started: "
- "buffer parameter update failed\n");
- goto error_ret;
- }
- }
- /* Definitely possible for devices to support both of these. */
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
- if (!indio_dev->trig) {
- printk(KERN_INFO
- "Buffer not started: no trigger\n");
- ret = -EINVAL;
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
- } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
- indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
- else { /* should never be reached */
- ret = -EINVAL;
- goto error_ret;
- }
-
- if (indio_dev->setup_ops->postenable) {
- ret = indio_dev->setup_ops->postenable(indio_dev);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started: "
- "postenable failed\n");
- indio_dev->currentmode = previous_mode;
- if (indio_dev->setup_ops->postdisable)
- indio_dev->setup_ops->
- postdisable(indio_dev);
- goto error_ret;
- }
- }
- } else {
- if (indio_dev->setup_ops->predisable) {
- ret = indio_dev->setup_ops->predisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_DIRECT_MODE;
- if (indio_dev->setup_ops->postdisable) {
- ret = indio_dev->setup_ops->postdisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- }
-done:
- mutex_unlock(&indio_dev->mlock);
- return len;
-
-error_ret:
- mutex_unlock(&indio_dev->mlock);
- return ret;
-}
-EXPORT_SYMBOL(iio_buffer_store_enable);
-
ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
+ return sprintf(buf, "%d\n",
+ iio_buffer_is_active(indio_dev,
+ indio_dev->buffer));
}
EXPORT_SYMBOL(iio_buffer_show_enable);
@@ -537,35 +460,217 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
return bytes;
}
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
+ int ret;
+ int success = 0;
+ struct iio_buffer *buffer;
+ unsigned long *compound_mask;
+ const unsigned long *old_mask;
- /* How much space will the demuxed element take? */
- indio_dev->scan_bytes =
- iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
- buffer->scan_timestamp);
- buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
+ /* Wind down existing buffers - iff there are any */
+ if (!list_empty(&indio_dev->buffer_list)) {
+ if (indio_dev->setup_ops->predisable) {
+ ret = indio_dev->setup_ops->predisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable) {
+ ret = indio_dev->setup_ops->postdisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ }
+ /* Keep a copy of current setup to allow roll back */
+ old_mask = indio_dev->active_scan_mask;
+ if (!indio_dev->available_scan_masks)
+ indio_dev->active_scan_mask = NULL;
+
+ if (remove_buffer)
+ list_del(&remove_buffer->buffer_list);
+ if (insert_buffer)
+ list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
+
+ /* If no buffers in list, we are done */
+ if (list_empty(&indio_dev->buffer_list)) {
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ return 0;
+ }
/* What scan mask do we actually have ?*/
- if (indio_dev->available_scan_masks)
+ compound_mask = kzalloc(BITS_TO_LONGS(indio_dev->masklength)
+ *sizeof(long), GFP_KERNEL);
+ if (compound_mask == NULL)
+ return -ENOMEM;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
+ indio_dev->masklength);
+ indio_dev->scan_timestamp |= buffer->scan_timestamp;
+ }
+ if (indio_dev->available_scan_masks) {
indio_dev->active_scan_mask =
iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
- buffer->scan_mask);
- else
- indio_dev->active_scan_mask = buffer->scan_mask;
-
- if (indio_dev->active_scan_mask == NULL)
- return -EINVAL;
+ compound_mask);
+ if (indio_dev->active_scan_mask == NULL) {
+ /*
+ * Roll back.
+ * Note can only occur when adding a buffer.
+ */
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ success = -EINVAL;
+ }
+ } else {
+ indio_dev->active_scan_mask = compound_mask;
+ }
iio_update_demux(indio_dev);
- if (indio_dev->info->update_scan_mode)
- return indio_dev->info
+ /* Wind up again */
+ if (indio_dev->setup_ops->preenable) {
+ ret = indio_dev->setup_ops->preenable(indio_dev);
+ if (ret) {
+ printk(KERN_ERR
+ "Buffer not started:"
+ "buffer preenable failed\n");
+ goto error_remove_inserted;
+ }
+ }
+ indio_dev->scan_bytes =
+ iio_compute_scan_bytes(indio_dev,
+ indio_dev->active_scan_mask,
+ indio_dev->scan_timestamp);
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->request_update) {
+ ret = buffer->access->request_update(buffer);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started:"
+ "buffer parameter update failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ if (indio_dev->info->update_scan_mode) {
+ ret = indio_dev->info
->update_scan_mode(indio_dev,
indio_dev->active_scan_mask);
+ if (ret < 0) {
+ printk(KERN_INFO "update scan mode failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ /* Definitely possible for devices to support both of these.*/
+ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
+ if (!indio_dev->trig) {
+ printk(KERN_INFO "Buffer not started: no trigger\n");
+ ret = -EINVAL;
+ /* Can only occur on first buffer */
+ goto error_run_postdisable;
+ }
+ indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
+ } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
+ indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+ } else { /* should never be reached */
+ ret = -EINVAL;
+ goto error_run_postdisable;
+ }
+
+ if (indio_dev->setup_ops->postenable) {
+ ret = indio_dev->setup_ops->postenable(indio_dev);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started: postenable failed\n");
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+ goto error_disable_all_buffers;
+ }
+ }
+
+ if (indio_dev->available_scan_masks)
+ kfree(compound_mask);
+ else
+ kfree(old_mask);
+
+ return success;
+
+error_disable_all_buffers:
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+error_run_postdisable:
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+error_remove_inserted:
+
+ if (insert_buffer)
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ kfree(compound_mask);
+error_ret:
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_update_buffers);
+
+ssize_t iio_buffer_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ bool requested_state;
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
+ struct iio_buffer *pbuf = indio_dev->buffer;
+ bool inlist;
+
+ ret = strtobool(buf, &requested_state);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ /* Find out if it is in the list */
+ inlist = iio_buffer_is_active(indio_dev, pbuf);
+ /* Already enabled */
+ if (inlist && requested_state)
+ goto done;
+ /* Already disabled */
+ if (!inlist && !requested_state)
+ goto done;
+
+ if (requested_state)
+ ret = iio_update_buffers(indio_dev,
+ indio_dev->buffer, NULL);
+ else
+ ret = iio_update_buffers(indio_dev,
+ NULL, indio_dev->buffer);
+
+ if (ret < 0)
+ goto done;
+done:
+ mutex_unlock(&indio_dev->mlock);
+ return (ret < 0) ? ret : len;
+}
+EXPORT_SYMBOL(iio_buffer_store_enable);
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ unsigned bytes;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->set_bytes_per_datum) {
+ bytes = iio_compute_scan_bytes(indio_dev,
+ buffer->scan_mask,
+ buffer->scan_timestamp);
+
+ buffer->access->set_bytes_per_datum(buffer, bytes);
+ }
return 0;
}
EXPORT_SYMBOL(iio_sw_buffer_preenable);
@@ -599,7 +704,11 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
* iio_scan_mask_set() - set particular bit in the scan mask
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
- **/
+ *
+ * Note that at this point we have no way of knowing what other
+ * buffers might request, hence this code only verifies that the
+ * individual buffers request is plausible.
+ */
int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
@@ -682,13 +791,12 @@ static unsigned char *iio_demux(struct iio_buffer *buffer,
return buffer->demux_bounce;
}
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
+static int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
{
unsigned char *dataout = iio_demux(buffer, data);
return buffer->access->store_to(buffer, dataout);
}
-EXPORT_SYMBOL_GPL(iio_push_to_buffer);
static void iio_buffer_demux_free(struct iio_buffer *buffer)
{
@@ -699,10 +807,26 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer)
}
}
-int iio_update_demux(struct iio_dev *indio_dev)
+
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data)
+{
+ int ret;
+ struct iio_buffer *buf;
+
+ list_for_each_entry(buf, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_push_to_buffer(buf, data);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_push_to_buffers);
+
+static int iio_buffer_update_demux(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
{
const struct iio_chan_spec *ch;
- struct iio_buffer *buffer = indio_dev->buffer;
int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0;
struct iio_demux_table *p;
@@ -787,4 +911,23 @@ error_clear_mux_table:
return ret;
}
+
+int iio_update_demux(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ int ret;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_buffer_update_demux(indio_dev, buffer);
+ if (ret < 0)
+ goto error_clear_mux_table;
+ }
+ return 0;
+
+error_clear_mux_table:
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ iio_buffer_demux_free(buffer);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 6eb24db..1bcaabf 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -851,6 +851,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
+ INIT_LIST_HEAD(&dev->buffer_list);
}
return dev;
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 164b62b..36d210a 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -164,7 +164,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adjd_s311_data *data = iio_priv(indio_dev);
- struct iio_buffer *buffer = indio_dev->buffer;
s64 time_ns = iio_get_time_ns();
int len = 0;
int i, j = 0;
@@ -187,7 +186,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64)))
= time_ns;
- iio_push_to_buffer(buffer, (u8 *)data->buffer);
+ iio_push_to_buffers(indio_dev, (u8 *)data->buffer);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 96e3691..8e1f698 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -176,21 +176,8 @@ static const struct iio_info als_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index c4f0d27..d1b5fb7 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -198,21 +198,8 @@ static const struct iio_info magn_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 97c09f0..e14ca60 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -82,7 +82,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 7507e1a..eba2e28 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -81,7 +81,7 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index 4c976be..3611a13 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -78,7 +78,7 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index f939e29..6af9a5d 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -78,7 +78,7 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index caff8e2..e2ac8a8 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -76,7 +76,7 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index fa4190d..d59abd3 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -154,7 +154,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)data + ALIGN(len, sizeof(s64)))
= pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index c2906a8..b3dd514 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -93,7 +93,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
indio_dev->masklength); i++)
buf[i] = be16_to_cpu(st->rx_buf[i]);
- iio_push_to_buffer(indio_dev->buffer, (u8 *)buf);
+ iio_push_to_buffers(indio_dev, (u8 *)buf);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index ba04d0f..2b25cb0 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -83,7 +83,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
if (indio_dev->scan_timestamp)
*((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
- iio_push_to_buffer(indio_dev->buffer, buf);
+ iio_push_to_buffers(indio_dev, buf);
done:
gpio_set_value(st->pdata->gpio_convst, 0);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index b39923b..ccb8d4d 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -95,7 +95,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, buf);
+ iio_push_to_buffers(indio_dev, buf);
done:
kfree(buf);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 86026d9..2c5f384 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -77,7 +77,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, rxbuf);
+ iio_push_to_buffers(indio_dev, rxbuf);
done:
kfree(rxbuf);
out:
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index 5f74f3b..688304b 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -80,7 +80,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, rxbuf);
+ iio_push_to_buffers(indio_dev, rxbuf);
done_free:
kfree(rxbuf);
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index e294cb4..d6c48f8 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -81,7 +81,7 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index 697d970..dee16f0 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -46,7 +46,6 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
u16 *data;
@@ -76,7 +75,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
i++, j++) {
- j = find_next_bit(buffer->scan_mask,
+ j = find_next_bit(indio_dev->active_scan_mask,
indio_dev->masklength, j);
/* random access read from the 'device' */
data[i] = fakedata[j];
@@ -87,7 +86,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)data + ALIGN(len, sizeof(s64)))
= iio_get_time_ns();
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index de21d47..b1fef14 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -647,7 +647,6 @@ static void ad5933_work(struct work_struct *work)
struct ad5933_state *st = container_of(work,
struct ad5933_state, work.work);
struct iio_dev *indio_dev = i2c_get_clientdata(st->client);
- struct iio_buffer *ring = indio_dev->buffer;
signed short buf[2];
unsigned char status;
@@ -677,8 +676,7 @@ static void ad5933_work(struct work_struct *work)
} else {
buf[0] = be16_to_cpu(buf[0]);
}
- /* save datum to the ring */
- iio_push_to_buffer(ring, (u8 *)buf);
+ iio_push_to_buffers(indio_dev, (u8 *)buf);
} else {
/* no data available - try again later */
schedule_delayed_work(&st->work, st->poll_time_jiffies);
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 260bdd1..d46c1e3 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -114,7 +114,6 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16400_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0, j, ret = 0;
s16 *data;
@@ -148,9 +147,9 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
}
}
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(ring, (u8 *) data);
+ iio_push_to_buffers(indio_dev, (u8 *) data);
done:
kfree(data);
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 9e49bac..4552a4c 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -73,7 +73,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)dat64);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index c629b3a..0270405 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -66,7 +66,8 @@ struct iio_buffer_access_funcs {
* @stufftoread: [INTERN] flag to indicate new data.
* @demux_list: [INTERN] list of operations required to demux the scan.
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
- **/
+ * @buffer_list: [INTERN] entry in the devices list of current buffers.
+ */
struct iio_buffer {
int length;
int bytes_per_datum;
@@ -81,9 +82,22 @@ struct iio_buffer {
const struct attribute_group *attrs;
struct list_head demux_list;
unsigned char *demux_bounce;
+ struct list_head buffer_list;
};
/**
+ * iio_update_buffers() - add or remove buffer from active list
+ * @indio_dev: device to add buffer to
+ * @insert_buffer: buffer to insert
+ * @remove_buffer: buffer_to_remove
+ *
+ * Note this will tear down the all buffering and build it up again
+ */
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer);
+
+/**
* iio_buffer_init() - Initialize the buffer structure
* @buffer: buffer to be initialized
**/
@@ -115,11 +129,11 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit);
/**
- * iio_push_to_buffer() - push to a registered buffer.
- * @buffer: IIO buffer structure for device
- * @data: the data to push to the buffer
+ * iio_push_to_buffers() - push to a registered buffer.
+ * @indio_dev: iio_dev structure for device.
+ * @data: Full scan.
*/
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data);
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data);
int iio_update_demux(struct iio_dev *indio_dev);
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index c0ae76a..0ff0e66 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -410,6 +410,7 @@ struct iio_buffer_setup_ops {
* and owner
* @event_interface: [INTERN] event chrdevs associated with interrupt lines
* @buffer: [DRIVER] any buffer present
+ * @buffer_list: [INTERN] list of all buffers currently attached
* @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
* @mlock: [INTERN] lock used to prevent simultaneous device state
* changes
@@ -448,6 +449,7 @@ struct iio_dev {
struct iio_event_interface *event_interface;
struct iio_buffer *buffer;
+ struct list_head buffer_list;
int scan_bytes;
struct mutex mlock;
--
1.7.12.2
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-10-13 9:24 ` [PATCH 1/4] staging:iio: Add support for multiple buffers Jonathan Cameron
@ 2012-10-17 8:37 ` Lars-Peter Clausen
2012-10-19 15:03 ` Jonathan Cameron
0 siblings, 1 reply; 16+ messages in thread
From: Lars-Peter Clausen @ 2012-10-17 8:37 UTC (permalink / raw)
To: Jonathan Cameron; +Cc: linux-iio, Michael.Hennerich, srinivas.pandruvada
On 10/13/2012 11:24 AM, Jonathan Cameron wrote:
> Route all buffer writes through the demux.
> Addition or removal of a buffer results in tear down and
> setup of all the buffers for a given device.
>
> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
> ---
> [...]
> /* Callback handler to send event after all samples are received and captured */
> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
> index d4ad374..8caa0d7 100644
> --- a/drivers/iio/industrialio-buffer.c
> +++ b/drivers/iio/industrialio-buffer.c
> @@ -31,6 +31,18 @@ static const char * const iio_endian_prefix[] = {
> [IIO_LE] = "le",
> };
>
> +static bool iio_buffer_is_active(struct iio_dev *indio_dev,
> + struct iio_buffer *buf)
> +{
> + struct list_head *p;
> +
> + list_for_each(p, &indio_dev->buffer_list)
> + if (p == &buf->buffer_list)
> + return true;
> +
> + return false;
> +}
> +
> /**
> * iio_buffer_read_first_n_outer() - chrdev read for buffer access
> *
> @@ -134,7 +146,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
> if (ret < 0)
> return ret;
> mutex_lock(&indio_dev->mlock);
> - if (iio_buffer_enabled(indio_dev)) {
> + if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
> ret = -EBUSY;
> goto error_ret;
> }
> @@ -180,12 +192,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
> return ret;
>
> mutex_lock(&indio_dev->mlock);
> - if (iio_buffer_enabled(indio_dev)) {
> + if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
> ret = -EBUSY;
> goto error_ret;
> }
> indio_dev->buffer->scan_timestamp = state;
> - indio_dev->scan_timestamp = state;
> error_ret:
> mutex_unlock(&indio_dev->mlock);
>
> @@ -385,7 +396,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
> return len;
>
> mutex_lock(&indio_dev->mlock);
> - if (iio_buffer_enabled(indio_dev)) {
> + if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
> ret = -EBUSY;
> } else {
> if (buffer->access->set_length)
> @@ -398,102 +409,14 @@ ssize_t iio_buffer_write_length(struct device *dev,
> }
> EXPORT_SYMBOL(iio_buffer_write_length);
>
> -ssize_t iio_buffer_store_enable(struct device *dev,
> - struct device_attribute *attr,
> - const char *buf,
> - size_t len)
> -{
> - int ret;
> - bool requested_state, current_state;
> - int previous_mode;
> - struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> - struct iio_buffer *buffer = indio_dev->buffer;
> -
> - mutex_lock(&indio_dev->mlock);
> - previous_mode = indio_dev->currentmode;
> - requested_state = !(buf[0] == '0');
> - current_state = iio_buffer_enabled(indio_dev);
> - if (current_state == requested_state) {
> - printk(KERN_INFO "iio-buffer, current state requested again\n");
> - goto done;
> - }
> - if (requested_state) {
> - if (indio_dev->setup_ops->preenable) {
> - ret = indio_dev->setup_ops->preenable(indio_dev);
> - if (ret) {
> - printk(KERN_ERR
> - "Buffer not started: "
> - "buffer preenable failed\n");
> - goto error_ret;
> - }
> - }
> - if (buffer->access->request_update) {
> - ret = buffer->access->request_update(buffer);
> - if (ret) {
> - printk(KERN_INFO
> - "Buffer not started: "
> - "buffer parameter update failed\n");
> - goto error_ret;
> - }
> - }
> - /* Definitely possible for devices to support both of these. */
> - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
> - if (!indio_dev->trig) {
> - printk(KERN_INFO
> - "Buffer not started: no trigger\n");
> - ret = -EINVAL;
> - goto error_ret;
> - }
> - indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
> - } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
> - indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
> - else { /* should never be reached */
> - ret = -EINVAL;
> - goto error_ret;
> - }
> -
> - if (indio_dev->setup_ops->postenable) {
> - ret = indio_dev->setup_ops->postenable(indio_dev);
> - if (ret) {
> - printk(KERN_INFO
> - "Buffer not started: "
> - "postenable failed\n");
> - indio_dev->currentmode = previous_mode;
> - if (indio_dev->setup_ops->postdisable)
> - indio_dev->setup_ops->
> - postdisable(indio_dev);
> - goto error_ret;
> - }
> - }
> - } else {
> - if (indio_dev->setup_ops->predisable) {
> - ret = indio_dev->setup_ops->predisable(indio_dev);
> - if (ret)
> - goto error_ret;
> - }
> - indio_dev->currentmode = INDIO_DIRECT_MODE;
> - if (indio_dev->setup_ops->postdisable) {
> - ret = indio_dev->setup_ops->postdisable(indio_dev);
> - if (ret)
> - goto error_ret;
> - }
> - }
> -done:
> - mutex_unlock(&indio_dev->mlock);
> - return len;
> -
> -error_ret:
> - mutex_unlock(&indio_dev->mlock);
> - return ret;
> -}
> -EXPORT_SYMBOL(iio_buffer_store_enable);
> -
> ssize_t iio_buffer_show_enable(struct device *dev,
> struct device_attribute *attr,
> char *buf)
> {
> struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> - return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
> + return sprintf(buf, "%d\n",
> + iio_buffer_is_active(indio_dev,
> + indio_dev->buffer));
> }
> EXPORT_SYMBOL(iio_buffer_show_enable);
>
> @@ -537,35 +460,217 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
> return bytes;
> }
>
> -int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
> +int iio_update_buffers(struct iio_dev *indio_dev,
> + struct iio_buffer *insert_buffer,
> + struct iio_buffer *remove_buffer)
> {
> - struct iio_buffer *buffer = indio_dev->buffer;
> - dev_dbg(&indio_dev->dev, "%s\n", __func__);
> + int ret;
> + int success = 0;
> + struct iio_buffer *buffer;
> + unsigned long *compound_mask;
> + const unsigned long *old_mask;
>
> - /* How much space will the demuxed element take? */
> - indio_dev->scan_bytes =
> - iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
> - buffer->scan_timestamp);
> - buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
> + /* Wind down existing buffers - iff there are any */
> + if (!list_empty(&indio_dev->buffer_list)) {
> + if (indio_dev->setup_ops->predisable) {
> + ret = indio_dev->setup_ops->predisable(indio_dev);
> + if (ret)
> + goto error_ret;
> + }
> + indio_dev->currentmode = INDIO_DIRECT_MODE;
> + if (indio_dev->setup_ops->postdisable) {
> + ret = indio_dev->setup_ops->postdisable(indio_dev);
> + if (ret)
> + goto error_ret;
> + }
> + }
> + /* Keep a copy of current setup to allow roll back */
> + old_mask = indio_dev->active_scan_mask;
> + if (!indio_dev->available_scan_masks)
> + indio_dev->active_scan_mask = NULL;
> +
> + if (remove_buffer)
> + list_del(&remove_buffer->buffer_list);
> + if (insert_buffer)
> + list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
> +
> + /* If no buffers in list, we are done */
> + if (list_empty(&indio_dev->buffer_list)) {
> + indio_dev->currentmode = INDIO_DIRECT_MODE;
> + return 0;
You leak old mask here, if indio_dev->available_scan_masks == NULL
> + }
>
> /* What scan mask do we actually have ?*/
> - if (indio_dev->available_scan_masks)
> + compound_mask = kzalloc(BITS_TO_LONGS(indio_dev->masklength)
> + *sizeof(long), GFP_KERNEL);
kcalloc
> + if (compound_mask == NULL)
> + return -ENOMEM;
Also leaks oldmask
> +
> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
> + bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
> + indio_dev->masklength);
> + indio_dev->scan_timestamp |= buffer->scan_timestamp;
As far as I can see indio_dev->scan_timestamp is never set to 0, so once
enabled it stays enabled.
> + }
> + if (indio_dev->available_scan_masks) {
> indio_dev->active_scan_mask =
> iio_scan_mask_match(indio_dev->available_scan_masks,
> indio_dev->masklength,
> - buffer->scan_mask);
> - else
> - indio_dev->active_scan_mask = buffer->scan_mask;
> -
> - if (indio_dev->active_scan_mask == NULL)
> - return -EINVAL;
> + compound_mask);
> + if (indio_dev->active_scan_mask == NULL) {
> + /*
> + * Roll back.
> + * Note can only occur when adding a buffer.
> + */
> + list_del(&insert_buffer->buffer_list);
What if insert buffer is NULL? Is it possible that we end up in this path if
it is NULL?
> + indio_dev->active_scan_mask = old_mask;
> + success = -EINVAL;
> + }
> + } else {
> + indio_dev->active_scan_mask = compound_mask;
> + }
>
> iio_update_demux(indio_dev);
>
> - if (indio_dev->info->update_scan_mode)
> - return indio_dev->info
> + /* Wind up again */
> + if (indio_dev->setup_ops->preenable) {
> + ret = indio_dev->setup_ops->preenable(indio_dev);
> + if (ret) {
> + printk(KERN_ERR
> + "Buffer not started:"
> + "buffer preenable failed\n");
> + goto error_remove_inserted;
> + }
> + }
> + indio_dev->scan_bytes =
> + iio_compute_scan_bytes(indio_dev,
> + indio_dev->active_scan_mask,
> + indio_dev->scan_timestamp);
> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
> + if (buffer->access->request_update) {
> + ret = buffer->access->request_update(buffer);
> + if (ret) {
> + printk(KERN_INFO
> + "Buffer not started:"
> + "buffer parameter update failed\n");
> + goto error_run_postdisable;
> + }
> + }
> + if (indio_dev->info->update_scan_mode) {
> + ret = indio_dev->info
> ->update_scan_mode(indio_dev,
> indio_dev->active_scan_mask);
> + if (ret < 0) {
> + printk(KERN_INFO "update scan mode failed\n");
> + goto error_run_postdisable;
> + }
> + }
> + /* Definitely possible for devices to support both of these.*/
> + if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
> + if (!indio_dev->trig) {
> + printk(KERN_INFO "Buffer not started: no trigger\n");
> + ret = -EINVAL;
> + /* Can only occur on first buffer */
> + goto error_run_postdisable;
> + }
> + indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
> + } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
> + indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
> + } else { /* should never be reached */
> + ret = -EINVAL;
> + goto error_run_postdisable;
> + }
> +
> + if (indio_dev->setup_ops->postenable) {
> + ret = indio_dev->setup_ops->postenable(indio_dev);
> + if (ret) {
> + printk(KERN_INFO
> + "Buffer not started: postenable failed\n");
> + indio_dev->currentmode = INDIO_DIRECT_MODE;
> + if (indio_dev->setup_ops->postdisable)
> + indio_dev->setup_ops->postdisable(indio_dev);
> + goto error_disable_all_buffers;
> + }
> + }
> +
> + if (indio_dev->available_scan_masks)
> + kfree(compound_mask);
> + else
> + kfree(old_mask);
> +
> + return success;
> +
> +error_disable_all_buffers:
> + indio_dev->currentmode = INDIO_DIRECT_MODE;
> +error_run_postdisable:
> + if (indio_dev->setup_ops->postdisable)
> + indio_dev->setup_ops->postdisable(indio_dev);
> +error_remove_inserted:
> +
> + if (insert_buffer)
> + list_del(&insert_buffer->buffer_list);
> + indio_dev->active_scan_mask = old_mask;
> + kfree(compound_mask);
> +error_ret:
> +
> + return ret;
> +}
> +EXPORT_SYMBOL_GPL(iio_update_buffers);
> +
> +ssize_t iio_buffer_store_enable(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf,
> + size_t len)
> +{
> + int ret;
> + bool requested_state;
> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
dev_to_iio_dev
I don't think dev_get_drvdata works anymore
> + struct iio_buffer *pbuf = indio_dev->buffer;
> + bool inlist;
> +
> + ret = strtobool(buf, &requested_state);
> + if (ret < 0)
> + return ret;
> +
> + mutex_lock(&indio_dev->mlock);
> +
> + /* Find out if it is in the list */
> + inlist = iio_buffer_is_active(indio_dev, pbuf);
> + /* Already enabled */
> + if (inlist && requested_state)
> + goto done;
> + /* Already disabled */
> + if (!inlist && !requested_state)
> + goto done;
if (inlist == requested_state)
goto done;
> +
> + if (requested_state)
> + ret = iio_update_buffers(indio_dev,
> + indio_dev->buffer, NULL);
> + else
> + ret = iio_update_buffers(indio_dev,
> + NULL, indio_dev->buffer);
> +
> + if (ret < 0)
> + goto done;
> +done:
> + mutex_unlock(&indio_dev->mlock);
> + return (ret < 0) ? ret : len;
> +}
> +EXPORT_SYMBOL(iio_buffer_store_enable);
> +
> +int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
> +{
> + struct iio_buffer *buffer;
> + unsigned bytes;
> + dev_dbg(&indio_dev->dev, "%s\n", __func__);
> +
> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
> + if (buffer->access->set_bytes_per_datum) {
> + bytes = iio_compute_scan_bytes(indio_dev,
> + buffer->scan_mask,
> + buffer->scan_timestamp);
> +
> + buffer->access->set_bytes_per_datum(buffer, bytes);
> + }
> return 0;
> }
> EXPORT_SYMBOL(iio_sw_buffer_preenable);
> [...]
>
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index c0ae76a..0ff0e66 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -410,6 +410,7 @@ struct iio_buffer_setup_ops {
> * and owner
> * @event_interface: [INTERN] event chrdevs associated with interrupt lines
> * @buffer: [DRIVER] any buffer present
> + * @buffer_list: [INTERN] list of all buffers currently attached
> * @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
> * @mlock: [INTERN] lock used to prevent simultaneous device state
> * changes
> @@ -448,6 +449,7 @@ struct iio_dev {
> struct iio_event_interface *event_interface;
>
> struct iio_buffer *buffer;
> + struct list_head buffer_list;
> int scan_bytes;
> struct mutex mlock;
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-10-17 8:37 ` Lars-Peter Clausen
@ 2012-10-19 15:03 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-10-19 15:03 UTC (permalink / raw)
To: Lars-Peter Clausen; +Cc: linux-iio, Michael.Hennerich, srinivas.pandruvada
On 10/17/2012 09:37 AM, Lars-Peter Clausen wrote:
> On 10/13/2012 11:24 AM, Jonathan Cameron wrote:
>> Route all buffer writes through the demux.
>> Addition or removal of a buffer results in tear down and
>> setup of all the buffers for a given device.
>>
Thanks Lars!
All fixed except the case commented below where unless something
really weird is going on it can't get there on removal.
Maybe it's safer to have the check anyway, but that might in turn
make people think it is possible when it shouldn't be!)
Jonathan
>> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
>> ---
>> [...]
>> /* Callback handler to send event after all samples are received and captured */
>> diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
>> index d4ad374..8caa0d7 100644
>> --- a/drivers/iio/industrialio-buffer.c
>> +++ b/drivers/iio/industrialio-buffer.c
>> @@ -31,6 +31,18 @@ static const char * const iio_endian_prefix[] = {
>> [IIO_LE] = "le",
>> };
>>
>> +static bool iio_buffer_is_active(struct iio_dev *indio_dev,
>> + struct iio_buffer *buf)
>> +{
>> + struct list_head *p;
>> +
>> + list_for_each(p, &indio_dev->buffer_list)
>> + if (p == &buf->buffer_list)
>> + return true;
>> +
>> + return false;
>> +}
>> +
>> /**
>> * iio_buffer_read_first_n_outer() - chrdev read for buffer access
>> *
>> @@ -134,7 +146,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
>> if (ret < 0)
>> return ret;
>> mutex_lock(&indio_dev->mlock);
>> - if (iio_buffer_enabled(indio_dev)) {
>> + if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
>> ret = -EBUSY;
>> goto error_ret;
>> }
>> @@ -180,12 +192,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
>> return ret;
>>
>> mutex_lock(&indio_dev->mlock);
>> - if (iio_buffer_enabled(indio_dev)) {
>> + if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
>> ret = -EBUSY;
>> goto error_ret;
>> }
>> indio_dev->buffer->scan_timestamp = state;
>> - indio_dev->scan_timestamp = state;
>> error_ret:
>> mutex_unlock(&indio_dev->mlock);
>>
>> @@ -385,7 +396,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
>> return len;
>>
>> mutex_lock(&indio_dev->mlock);
>> - if (iio_buffer_enabled(indio_dev)) {
>> + if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
>> ret = -EBUSY;
>> } else {
>> if (buffer->access->set_length)
>> @@ -398,102 +409,14 @@ ssize_t iio_buffer_write_length(struct device *dev,
>> }
>> EXPORT_SYMBOL(iio_buffer_write_length);
>>
>> -ssize_t iio_buffer_store_enable(struct device *dev,
>> - struct device_attribute *attr,
>> - const char *buf,
>> - size_t len)
>> -{
>> - int ret;
>> - bool requested_state, current_state;
>> - int previous_mode;
>> - struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>> - struct iio_buffer *buffer = indio_dev->buffer;
>> -
>> - mutex_lock(&indio_dev->mlock);
>> - previous_mode = indio_dev->currentmode;
>> - requested_state = !(buf[0] == '0');
>> - current_state = iio_buffer_enabled(indio_dev);
>> - if (current_state == requested_state) {
>> - printk(KERN_INFO "iio-buffer, current state requested again\n");
>> - goto done;
>> - }
>> - if (requested_state) {
>> - if (indio_dev->setup_ops->preenable) {
>> - ret = indio_dev->setup_ops->preenable(indio_dev);
>> - if (ret) {
>> - printk(KERN_ERR
>> - "Buffer not started: "
>> - "buffer preenable failed\n");
>> - goto error_ret;
>> - }
>> - }
>> - if (buffer->access->request_update) {
>> - ret = buffer->access->request_update(buffer);
>> - if (ret) {
>> - printk(KERN_INFO
>> - "Buffer not started: "
>> - "buffer parameter update failed\n");
>> - goto error_ret;
>> - }
>> - }
>> - /* Definitely possible for devices to support both of these. */
>> - if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
>> - if (!indio_dev->trig) {
>> - printk(KERN_INFO
>> - "Buffer not started: no trigger\n");
>> - ret = -EINVAL;
>> - goto error_ret;
>> - }
>> - indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
>> - } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
>> - indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
>> - else { /* should never be reached */
>> - ret = -EINVAL;
>> - goto error_ret;
>> - }
>> -
>> - if (indio_dev->setup_ops->postenable) {
>> - ret = indio_dev->setup_ops->postenable(indio_dev);
>> - if (ret) {
>> - printk(KERN_INFO
>> - "Buffer not started: "
>> - "postenable failed\n");
>> - indio_dev->currentmode = previous_mode;
>> - if (indio_dev->setup_ops->postdisable)
>> - indio_dev->setup_ops->
>> - postdisable(indio_dev);
>> - goto error_ret;
>> - }
>> - }
>> - } else {
>> - if (indio_dev->setup_ops->predisable) {
>> - ret = indio_dev->setup_ops->predisable(indio_dev);
>> - if (ret)
>> - goto error_ret;
>> - }
>> - indio_dev->currentmode = INDIO_DIRECT_MODE;
>> - if (indio_dev->setup_ops->postdisable) {
>> - ret = indio_dev->setup_ops->postdisable(indio_dev);
>> - if (ret)
>> - goto error_ret;
>> - }
>> - }
>> -done:
>> - mutex_unlock(&indio_dev->mlock);
>> - return len;
>> -
>> -error_ret:
>> - mutex_unlock(&indio_dev->mlock);
>> - return ret;
>> -}
>> -EXPORT_SYMBOL(iio_buffer_store_enable);
>> -
>> ssize_t iio_buffer_show_enable(struct device *dev,
>> struct device_attribute *attr,
>> char *buf)
>> {
>> struct iio_dev *indio_dev = dev_to_iio_dev(dev);
>> - return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
>> + return sprintf(buf, "%d\n",
>> + iio_buffer_is_active(indio_dev,
>> + indio_dev->buffer));
>> }
>> EXPORT_SYMBOL(iio_buffer_show_enable);
>>
>> @@ -537,35 +460,217 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
>> return bytes;
>> }
>>
>> -int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>> +int iio_update_buffers(struct iio_dev *indio_dev,
>> + struct iio_buffer *insert_buffer,
>> + struct iio_buffer *remove_buffer)
>> {
>> - struct iio_buffer *buffer = indio_dev->buffer;
>> - dev_dbg(&indio_dev->dev, "%s\n", __func__);
>> + int ret;
>> + int success = 0;
>> + struct iio_buffer *buffer;
>> + unsigned long *compound_mask;
>> + const unsigned long *old_mask;
>>
>> - /* How much space will the demuxed element take? */
>> - indio_dev->scan_bytes =
>> - iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
>> - buffer->scan_timestamp);
>> - buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
>> + /* Wind down existing buffers - iff there are any */
>> + if (!list_empty(&indio_dev->buffer_list)) {
>> + if (indio_dev->setup_ops->predisable) {
>> + ret = indio_dev->setup_ops->predisable(indio_dev);
>> + if (ret)
>> + goto error_ret;
>> + }
>> + indio_dev->currentmode = INDIO_DIRECT_MODE;
>> + if (indio_dev->setup_ops->postdisable) {
>> + ret = indio_dev->setup_ops->postdisable(indio_dev);
>> + if (ret)
>> + goto error_ret;
>> + }
>> + }
>> + /* Keep a copy of current setup to allow roll back */
>> + old_mask = indio_dev->active_scan_mask;
>> + if (!indio_dev->available_scan_masks)
>> + indio_dev->active_scan_mask = NULL;
>> +
>> + if (remove_buffer)
>> + list_del(&remove_buffer->buffer_list);
>> + if (insert_buffer)
>> + list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
>> +
>> + /* If no buffers in list, we are done */
>> + if (list_empty(&indio_dev->buffer_list)) {
>> + indio_dev->currentmode = INDIO_DIRECT_MODE;
>> + return 0;
>
> You leak old mask here, if indio_dev->available_scan_masks == NULL
>
>> + }
>>
>> /* What scan mask do we actually have ?*/
>> - if (indio_dev->available_scan_masks)
>> + compound_mask = kzalloc(BITS_TO_LONGS(indio_dev->masklength)
>> + *sizeof(long), GFP_KERNEL);
>
> kcalloc
>
>> + if (compound_mask == NULL)
>> + return -ENOMEM;
>
> Also leaks oldmask
>
>> +
>> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
>> + bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
>> + indio_dev->masklength);
>> + indio_dev->scan_timestamp |= buffer->scan_timestamp;
>
> As far as I can see indio_dev->scan_timestamp is never set to 0, so once
> enabled it stays enabled.
>
>> + }
>> + if (indio_dev->available_scan_masks) {
>> indio_dev->active_scan_mask =
>> iio_scan_mask_match(indio_dev->available_scan_masks,
>> indio_dev->masklength,
>> - buffer->scan_mask);
>> - else
>> - indio_dev->active_scan_mask = buffer->scan_mask;
>> -
>> - if (indio_dev->active_scan_mask == NULL)
>> - return -EINVAL;
>> + compound_mask);
>> + if (indio_dev->active_scan_mask == NULL) {
>> + /*
>> + * Roll back.
>> + * Note can only occur when adding a buffer.
>> + */
>> + list_del(&insert_buffer->buffer_list);
>
> What if insert buffer is NULL? Is it possible that we end up in this path if
> it is NULL?
I don't think there is anyway we could go from a valid scan mask to there
not being one that exists (e.g. on removal of a buffer). Afterall the
scan mask with the buffer there covers all desired channels so it still
will after the buffer is removed.
>
>> + indio_dev->active_scan_mask = old_mask;
>> + success = -EINVAL;
>> + }
>> + } else {
>> + indio_dev->active_scan_mask = compound_mask;
>> + }
>>
>> iio_update_demux(indio_dev);
>>
>> - if (indio_dev->info->update_scan_mode)
>> - return indio_dev->info
>> + /* Wind up again */
>> + if (indio_dev->setup_ops->preenable) {
>> + ret = indio_dev->setup_ops->preenable(indio_dev);
>> + if (ret) {
>> + printk(KERN_ERR
>> + "Buffer not started:"
>> + "buffer preenable failed\n");
>> + goto error_remove_inserted;
>> + }
>> + }
>> + indio_dev->scan_bytes =
>> + iio_compute_scan_bytes(indio_dev,
>> + indio_dev->active_scan_mask,
>> + indio_dev->scan_timestamp);
>> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
>> + if (buffer->access->request_update) {
>> + ret = buffer->access->request_update(buffer);
>> + if (ret) {
>> + printk(KERN_INFO
>> + "Buffer not started:"
>> + "buffer parameter update failed\n");
>> + goto error_run_postdisable;
>> + }
>> + }
>> + if (indio_dev->info->update_scan_mode) {
>> + ret = indio_dev->info
>> ->update_scan_mode(indio_dev,
>> indio_dev->active_scan_mask);
>> + if (ret < 0) {
>> + printk(KERN_INFO "update scan mode failed\n");
>> + goto error_run_postdisable;
>> + }
>> + }
>> + /* Definitely possible for devices to support both of these.*/
>> + if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
>> + if (!indio_dev->trig) {
>> + printk(KERN_INFO "Buffer not started: no trigger\n");
>> + ret = -EINVAL;
>> + /* Can only occur on first buffer */
>> + goto error_run_postdisable;
>> + }
>> + indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
>> + } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
>> + indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
>> + } else { /* should never be reached */
>> + ret = -EINVAL;
>> + goto error_run_postdisable;
>> + }
>> +
>> + if (indio_dev->setup_ops->postenable) {
>> + ret = indio_dev->setup_ops->postenable(indio_dev);
>> + if (ret) {
>> + printk(KERN_INFO
>> + "Buffer not started: postenable failed\n");
>> + indio_dev->currentmode = INDIO_DIRECT_MODE;
>> + if (indio_dev->setup_ops->postdisable)
>> + indio_dev->setup_ops->postdisable(indio_dev);
>> + goto error_disable_all_buffers;
>> + }
>> + }
>> +
>> + if (indio_dev->available_scan_masks)
>> + kfree(compound_mask);
>> + else
>> + kfree(old_mask);
>> +
>> + return success;
>> +
>> +error_disable_all_buffers:
>> + indio_dev->currentmode = INDIO_DIRECT_MODE;
>> +error_run_postdisable:
>> + if (indio_dev->setup_ops->postdisable)
>> + indio_dev->setup_ops->postdisable(indio_dev);
>> +error_remove_inserted:
>> +
>> + if (insert_buffer)
>> + list_del(&insert_buffer->buffer_list);
>> + indio_dev->active_scan_mask = old_mask;
>> + kfree(compound_mask);
>> +error_ret:
>> +
>> + return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_update_buffers);
>> +
>> +ssize_t iio_buffer_store_enable(struct device *dev,
>> + struct device_attribute *attr,
>> + const char *buf,
>> + size_t len)
>> +{
>> + int ret;
>> + bool requested_state;
>> + struct iio_dev *indio_dev = dev_get_drvdata(dev);
>
> dev_to_iio_dev
>
> I don't think dev_get_drvdata works anymore
oops.. :)
>
>> + struct iio_buffer *pbuf = indio_dev->buffer;
>> + bool inlist;
>> +
>> + ret = strtobool(buf, &requested_state);
>> + if (ret < 0)
>> + return ret;
>> +
>> + mutex_lock(&indio_dev->mlock);
>> +
>> + /* Find out if it is in the list */
>> + inlist = iio_buffer_is_active(indio_dev, pbuf);
>> + /* Already enabled */
>> + if (inlist && requested_state)
>> + goto done;
>> + /* Already disabled */
>> + if (!inlist && !requested_state)
>> + goto done;
>
> if (inlist == requested_state)
> goto done;
oops again. I like to think it evolved to this state, but
maybe I was just being an idiot ;)
>
>> +
>> + if (requested_state)
>> + ret = iio_update_buffers(indio_dev,
>> + indio_dev->buffer, NULL);
>> + else
>> + ret = iio_update_buffers(indio_dev,
>> + NULL, indio_dev->buffer);
>> +
>> + if (ret < 0)
>> + goto done;
>> +done:
>> + mutex_unlock(&indio_dev->mlock);
>> + return (ret < 0) ? ret : len;
>> +}
>> +EXPORT_SYMBOL(iio_buffer_store_enable);
>> +
>> +int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>> +{
>> + struct iio_buffer *buffer;
>> + unsigned bytes;
>> + dev_dbg(&indio_dev->dev, "%s\n", __func__);
>> +
>> + list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
>> + if (buffer->access->set_bytes_per_datum) {
>> + bytes = iio_compute_scan_bytes(indio_dev,
>> + buffer->scan_mask,
>> + buffer->scan_timestamp);
>> +
>> + buffer->access->set_bytes_per_datum(buffer, bytes);
>> + }
>> return 0;
>> }
>> EXPORT_SYMBOL(iio_sw_buffer_preenable);
>> [...]
>>
>> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
>> index c0ae76a..0ff0e66 100644
>> --- a/include/linux/iio/iio.h
>> +++ b/include/linux/iio/iio.h
>> @@ -410,6 +410,7 @@ struct iio_buffer_setup_ops {
>> * and owner
>> * @event_interface: [INTERN] event chrdevs associated with interrupt lines
>> * @buffer: [DRIVER] any buffer present
>> + * @buffer_list: [INTERN] list of all buffers currently attached
>> * @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
>> * @mlock: [INTERN] lock used to prevent simultaneous device state
>> * changes
>> @@ -448,6 +449,7 @@ struct iio_dev {
>> struct iio_event_interface *event_interface;
>>
>> struct iio_buffer *buffer;
>> + struct list_head buffer_list;
>> int scan_bytes;
>> struct mutex mlock;
>>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 1/4] staging:iio: Add support for multiple buffers
2012-10-31 10:30 [PATCH 0/4 V6] staging:iio: Add support for multiple buffers (testing required!) Jonathan Cameron
@ 2012-10-31 10:30 ` Jonathan Cameron
0 siblings, 0 replies; 16+ messages in thread
From: Jonathan Cameron @ 2012-10-31 10:30 UTC (permalink / raw)
To: linux-iio; +Cc: Jonathan Cameron
Route all buffer writes through the demux.
Addition or removal of a buffer results in tear down and
setup of all the buffers for a given device.
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Tested-by: srinivas pandruvada <srinivas.pandruvada@intel.com>
---
drivers/iio/accel/hid-sensor-accel-3d.c | 15 +-
drivers/iio/adc/ad7266.c | 3 +-
drivers/iio/adc/ad7476.c | 2 +-
drivers/iio/adc/ad_sigma_delta.c | 2 +-
drivers/iio/adc/at91_adc.c | 3 +-
drivers/iio/gyro/hid-sensor-gyro-3d.c | 15 +-
drivers/iio/industrialio-buffer.c | 380 ++++++++++++++++--------
drivers/iio/industrialio-core.c | 1 +
drivers/iio/light/adjd_s311.c | 3 +-
drivers/iio/light/hid-sensor-als.c | 15 +-
drivers/iio/magnetometer/hid-sensor-magn-3d.c | 15 +-
drivers/staging/iio/accel/adis16201_ring.c | 2 +-
drivers/staging/iio/accel/adis16203_ring.c | 2 +-
drivers/staging/iio/accel/adis16204_ring.c | 2 +-
drivers/staging/iio/accel/adis16209_ring.c | 2 +-
drivers/staging/iio/accel/adis16240_ring.c | 2 +-
drivers/staging/iio/accel/lis3l02dq_ring.c | 2 +-
drivers/staging/iio/adc/ad7298_ring.c | 2 +-
drivers/staging/iio/adc/ad7606_ring.c | 2 +-
drivers/staging/iio/adc/ad7887_ring.c | 2 +-
drivers/staging/iio/adc/ad799x_ring.c | 2 +-
drivers/staging/iio/adc/max1363_ring.c | 2 +-
drivers/staging/iio/gyro/adis16260_ring.c | 2 +-
drivers/staging/iio/iio_simple_dummy_buffer.c | 5 +-
drivers/staging/iio/impedance-analyzer/ad5933.c | 4 +-
drivers/staging/iio/imu/adis16400_ring.c | 5 +-
drivers/staging/iio/meter/ade7758_ring.c | 2 +-
include/linux/iio/buffer.h | 24 +-
include/linux/iio/iio.h | 2 +
29 files changed, 312 insertions(+), 208 deletions(-)
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index 314a405..a95cda0 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -197,21 +197,8 @@ static const struct iio_info accel_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c
index b11f214..a6f4fc5 100644
--- a/drivers/iio/adc/ad7266.c
+++ b/drivers/iio/adc/ad7266.c
@@ -91,7 +91,6 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
struct ad7266_state *st = iio_priv(indio_dev);
int ret;
@@ -99,7 +98,7 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p)
if (ret == 0) {
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = pf->timestamp;
- iio_push_to_buffer(buffer, (u8 *)st->data);
+ iio_push_to_buffers(indio_dev, (u8 *)st->data);
}
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad7476.c b/drivers/iio/adc/ad7476.c
index 7f2f45a..330248b 100644
--- a/drivers/iio/adc/ad7476.c
+++ b/drivers/iio/adc/ad7476.c
@@ -76,7 +76,7 @@ static irqreturn_t ad7476_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
((s64 *)st->data)[1] = time_ns;
- iio_push_to_buffer(indio_dev->buffer, st->data);
+ iio_push_to_buffers(indio_dev, st->data);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c
index 67baa13..afe6d78 100644
--- a/drivers/iio/adc/ad_sigma_delta.c
+++ b/drivers/iio/adc/ad_sigma_delta.c
@@ -391,7 +391,7 @@ static irqreturn_t ad_sd_trigger_handler(int irq, void *p)
break;
}
- iio_push_to_buffer(indio_dev->buffer, (uint8_t *)data);
+ iio_push_to_buffers(indio_dev, (uint8_t *)data);
iio_trigger_notify_done(indio_dev->trig);
sigma_delta->irq_dis = false;
diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
index a917672..7e5648c 100644
--- a/drivers/iio/adc/at91_adc.c
+++ b/drivers/iio/adc/at91_adc.c
@@ -65,7 +65,6 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *idev = pf->indio_dev;
struct at91_adc_state *st = iio_priv(idev);
- struct iio_buffer *buffer = idev->buffer;
int i, j = 0;
for (i = 0; i < idev->masklength; i++) {
@@ -81,7 +80,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p)
*timestamp = pf->timestamp;
}
- iio_push_to_buffer(buffer, st->buffer);
+ iio_push_to_buffers(indio_dev, (u8 *)st->buffer);
iio_trigger_notify_done(idev->trig);
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index 4c56ada..02ef989 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -197,21 +197,8 @@ static const struct iio_info gyro_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 722a83f..aaadd32 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -31,6 +31,18 @@ static const char * const iio_endian_prefix[] = {
[IIO_LE] = "le",
};
+static bool iio_buffer_is_active(struct iio_dev *indio_dev,
+ struct iio_buffer *buf)
+{
+ struct list_head *p;
+
+ list_for_each(p, &indio_dev->buffer_list)
+ if (p == &buf->buffer_list)
+ return true;
+
+ return false;
+}
+
/**
* iio_buffer_read_first_n_outer() - chrdev read for buffer access
*
@@ -134,7 +146,7 @@ static ssize_t iio_scan_el_store(struct device *dev,
if (ret < 0)
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
@@ -180,12 +192,11 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
return ret;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
goto error_ret;
}
indio_dev->buffer->scan_timestamp = state;
- indio_dev->scan_timestamp = state;
error_ret:
mutex_unlock(&indio_dev->mlock);
@@ -385,7 +396,7 @@ ssize_t iio_buffer_write_length(struct device *dev,
return len;
mutex_lock(&indio_dev->mlock);
- if (iio_buffer_enabled(indio_dev)) {
+ if (iio_buffer_is_active(indio_dev, indio_dev->buffer)) {
ret = -EBUSY;
} else {
if (buffer->access->set_length)
@@ -398,102 +409,14 @@ ssize_t iio_buffer_write_length(struct device *dev,
}
EXPORT_SYMBOL(iio_buffer_write_length);
-ssize_t iio_buffer_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
-{
- int ret;
- bool requested_state, current_state;
- int previous_mode;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct iio_buffer *buffer = indio_dev->buffer;
-
- mutex_lock(&indio_dev->mlock);
- previous_mode = indio_dev->currentmode;
- requested_state = !(buf[0] == '0');
- current_state = iio_buffer_enabled(indio_dev);
- if (current_state == requested_state) {
- printk(KERN_INFO "iio-buffer, current state requested again\n");
- goto done;
- }
- if (requested_state) {
- if (indio_dev->setup_ops->preenable) {
- ret = indio_dev->setup_ops->preenable(indio_dev);
- if (ret) {
- printk(KERN_ERR
- "Buffer not started: "
- "buffer preenable failed\n");
- goto error_ret;
- }
- }
- if (buffer->access->request_update) {
- ret = buffer->access->request_update(buffer);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started: "
- "buffer parameter update failed\n");
- goto error_ret;
- }
- }
- /* Definitely possible for devices to support both of these. */
- if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
- if (!indio_dev->trig) {
- printk(KERN_INFO
- "Buffer not started: no trigger\n");
- ret = -EINVAL;
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
- } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE)
- indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
- else { /* should never be reached */
- ret = -EINVAL;
- goto error_ret;
- }
-
- if (indio_dev->setup_ops->postenable) {
- ret = indio_dev->setup_ops->postenable(indio_dev);
- if (ret) {
- printk(KERN_INFO
- "Buffer not started: "
- "postenable failed\n");
- indio_dev->currentmode = previous_mode;
- if (indio_dev->setup_ops->postdisable)
- indio_dev->setup_ops->
- postdisable(indio_dev);
- goto error_ret;
- }
- }
- } else {
- if (indio_dev->setup_ops->predisable) {
- ret = indio_dev->setup_ops->predisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- indio_dev->currentmode = INDIO_DIRECT_MODE;
- if (indio_dev->setup_ops->postdisable) {
- ret = indio_dev->setup_ops->postdisable(indio_dev);
- if (ret)
- goto error_ret;
- }
- }
-done:
- mutex_unlock(&indio_dev->mlock);
- return len;
-
-error_ret:
- mutex_unlock(&indio_dev->mlock);
- return ret;
-}
-EXPORT_SYMBOL(iio_buffer_store_enable);
-
ssize_t iio_buffer_show_enable(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- return sprintf(buf, "%d\n", iio_buffer_enabled(indio_dev));
+ return sprintf(buf, "%d\n",
+ iio_buffer_is_active(indio_dev,
+ indio_dev->buffer));
}
EXPORT_SYMBOL(iio_buffer_show_enable);
@@ -537,35 +460,220 @@ static int iio_compute_scan_bytes(struct iio_dev *indio_dev, const long *mask,
return bytes;
}
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- dev_dbg(&indio_dev->dev, "%s\n", __func__);
+ int ret;
+ int success = 0;
+ struct iio_buffer *buffer;
+ unsigned long *compound_mask;
+ const unsigned long *old_mask;
- /* How much space will the demuxed element take? */
- indio_dev->scan_bytes =
- iio_compute_scan_bytes(indio_dev, buffer->scan_mask,
- buffer->scan_timestamp);
- buffer->access->set_bytes_per_datum(buffer, indio_dev->scan_bytes);
+ /* Wind down existing buffers - iff there are any */
+ if (!list_empty(&indio_dev->buffer_list)) {
+ if (indio_dev->setup_ops->predisable) {
+ ret = indio_dev->setup_ops->predisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable) {
+ ret = indio_dev->setup_ops->postdisable(indio_dev);
+ if (ret)
+ goto error_ret;
+ }
+ }
+ /* Keep a copy of current setup to allow roll back */
+ old_mask = indio_dev->active_scan_mask;
+ if (!indio_dev->available_scan_masks)
+ indio_dev->active_scan_mask = NULL;
+
+ if (remove_buffer)
+ list_del(&remove_buffer->buffer_list);
+ if (insert_buffer)
+ list_add(&insert_buffer->buffer_list, &indio_dev->buffer_list);
+
+ /* If no buffers in list, we are done */
+ if (list_empty(&indio_dev->buffer_list)) {
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->available_scan_masks == NULL)
+ kfree(old_mask);
+ return 0;
+ }
/* What scan mask do we actually have ?*/
- if (indio_dev->available_scan_masks)
+ compound_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
+ sizeof(long), GFP_KERNEL);
+ if (compound_mask == NULL) {
+ if (indio_dev->available_scan_masks == NULL)
+ kfree(old_mask);
+ return -ENOMEM;
+ }
+ indio_dev->scan_timestamp = 0;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ bitmap_or(compound_mask, compound_mask, buffer->scan_mask,
+ indio_dev->masklength);
+ indio_dev->scan_timestamp |= buffer->scan_timestamp;
+ }
+ if (indio_dev->available_scan_masks) {
indio_dev->active_scan_mask =
iio_scan_mask_match(indio_dev->available_scan_masks,
indio_dev->masklength,
- buffer->scan_mask);
- else
- indio_dev->active_scan_mask = buffer->scan_mask;
-
- if (indio_dev->active_scan_mask == NULL)
- return -EINVAL;
+ compound_mask);
+ if (indio_dev->active_scan_mask == NULL) {
+ /*
+ * Roll back.
+ * Note can only occur when adding a buffer.
+ */
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ success = -EINVAL;
+ }
+ } else {
+ indio_dev->active_scan_mask = compound_mask;
+ }
iio_update_demux(indio_dev);
- if (indio_dev->info->update_scan_mode)
- return indio_dev->info
+ /* Wind up again */
+ if (indio_dev->setup_ops->preenable) {
+ ret = indio_dev->setup_ops->preenable(indio_dev);
+ if (ret) {
+ printk(KERN_ERR
+ "Buffer not started:"
+ "buffer preenable failed\n");
+ goto error_remove_inserted;
+ }
+ }
+ indio_dev->scan_bytes =
+ iio_compute_scan_bytes(indio_dev,
+ indio_dev->active_scan_mask,
+ indio_dev->scan_timestamp);
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->request_update) {
+ ret = buffer->access->request_update(buffer);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started:"
+ "buffer parameter update failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ if (indio_dev->info->update_scan_mode) {
+ ret = indio_dev->info
->update_scan_mode(indio_dev,
indio_dev->active_scan_mask);
+ if (ret < 0) {
+ printk(KERN_INFO "update scan mode failed\n");
+ goto error_run_postdisable;
+ }
+ }
+ /* Definitely possible for devices to support both of these.*/
+ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) {
+ if (!indio_dev->trig) {
+ printk(KERN_INFO "Buffer not started: no trigger\n");
+ ret = -EINVAL;
+ /* Can only occur on first buffer */
+ goto error_run_postdisable;
+ }
+ indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
+ } else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
+ indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+ } else { /* should never be reached */
+ ret = -EINVAL;
+ goto error_run_postdisable;
+ }
+
+ if (indio_dev->setup_ops->postenable) {
+ ret = indio_dev->setup_ops->postenable(indio_dev);
+ if (ret) {
+ printk(KERN_INFO
+ "Buffer not started: postenable failed\n");
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+ goto error_disable_all_buffers;
+ }
+ }
+
+ if (indio_dev->available_scan_masks)
+ kfree(compound_mask);
+ else
+ kfree(old_mask);
+
+ return success;
+
+error_disable_all_buffers:
+ indio_dev->currentmode = INDIO_DIRECT_MODE;
+error_run_postdisable:
+ if (indio_dev->setup_ops->postdisable)
+ indio_dev->setup_ops->postdisable(indio_dev);
+error_remove_inserted:
+
+ if (insert_buffer)
+ list_del(&insert_buffer->buffer_list);
+ indio_dev->active_scan_mask = old_mask;
+ kfree(compound_mask);
+error_ret:
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_update_buffers);
+
+ssize_t iio_buffer_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
+{
+ int ret;
+ bool requested_state;
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
+ struct iio_buffer *pbuf = indio_dev->buffer;
+ bool inlist;
+
+ ret = strtobool(buf, &requested_state);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&indio_dev->mlock);
+
+ /* Find out if it is in the list */
+ inlist = iio_buffer_is_active(indio_dev, pbuf);
+ /* Already in desired state */
+ if (inlist == requested_state)
+ goto done;
+
+ if (requested_state)
+ ret = iio_update_buffers(indio_dev,
+ indio_dev->buffer, NULL);
+ else
+ ret = iio_update_buffers(indio_dev,
+ NULL, indio_dev->buffer);
+
+ if (ret < 0)
+ goto done;
+done:
+ mutex_unlock(&indio_dev->mlock);
+ return (ret < 0) ? ret : len;
+}
+EXPORT_SYMBOL(iio_buffer_store_enable);
+
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ unsigned bytes;
+ dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ if (buffer->access->set_bytes_per_datum) {
+ bytes = iio_compute_scan_bytes(indio_dev,
+ buffer->scan_mask,
+ buffer->scan_timestamp);
+
+ buffer->access->set_bytes_per_datum(buffer, bytes);
+ }
return 0;
}
EXPORT_SYMBOL(iio_sw_buffer_preenable);
@@ -599,7 +707,11 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
* iio_scan_mask_set() - set particular bit in the scan mask
* @buffer: the buffer whose scan mask we are interested in
* @bit: the bit to be set.
- **/
+ *
+ * Note that at this point we have no way of knowing what other
+ * buffers might request, hence this code only verifies that the
+ * individual buffers request is plausible.
+ */
int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
@@ -682,13 +794,12 @@ static unsigned char *iio_demux(struct iio_buffer *buffer,
return buffer->demux_bounce;
}
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
+static int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data)
{
unsigned char *dataout = iio_demux(buffer, data);
return buffer->access->store_to(buffer, dataout);
}
-EXPORT_SYMBOL_GPL(iio_push_to_buffer);
static void iio_buffer_demux_free(struct iio_buffer *buffer)
{
@@ -699,10 +810,26 @@ static void iio_buffer_demux_free(struct iio_buffer *buffer)
}
}
-int iio_update_demux(struct iio_dev *indio_dev)
+
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data)
+{
+ int ret;
+ struct iio_buffer *buf;
+
+ list_for_each_entry(buf, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_push_to_buffer(buf, data);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(iio_push_to_buffers);
+
+static int iio_buffer_update_demux(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer)
{
const struct iio_chan_spec *ch;
- struct iio_buffer *buffer = indio_dev->buffer;
int ret, in_ind = -1, out_ind, length;
unsigned in_loc = 0, out_loc = 0;
struct iio_demux_table *p;
@@ -787,4 +914,23 @@ error_clear_mux_table:
return ret;
}
+
+int iio_update_demux(struct iio_dev *indio_dev)
+{
+ struct iio_buffer *buffer;
+ int ret;
+
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list) {
+ ret = iio_buffer_update_demux(indio_dev, buffer);
+ if (ret < 0)
+ goto error_clear_mux_table;
+ }
+ return 0;
+
+error_clear_mux_table:
+ list_for_each_entry(buffer, &indio_dev->buffer_list, buffer_list)
+ iio_buffer_demux_free(buffer);
+
+ return ret;
+}
EXPORT_SYMBOL_GPL(iio_update_demux);
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 37650a7..982edd3 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -856,6 +856,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
return NULL;
}
dev_set_name(&dev->dev, "iio:device%d", dev->id);
+ INIT_LIST_HEAD(&dev->buffer_list);
}
return dev;
diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c
index 164b62b..36d210a 100644
--- a/drivers/iio/light/adjd_s311.c
+++ b/drivers/iio/light/adjd_s311.c
@@ -164,7 +164,6 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adjd_s311_data *data = iio_priv(indio_dev);
- struct iio_buffer *buffer = indio_dev->buffer;
s64 time_ns = iio_get_time_ns();
int len = 0;
int i, j = 0;
@@ -187,7 +186,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64)))
= time_ns;
- iio_push_to_buffer(buffer, (u8 *)data->buffer);
+ iio_push_to_buffers(indio_dev, (u8 *)data->buffer);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index 96e3691..8e1f698 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -176,21 +176,8 @@ static const struct iio_info als_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index c4f0d27..d1b5fb7 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -198,21 +198,8 @@ static const struct iio_info magn_3d_info = {
/* Function to push data to buffer */
static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len)
{
- struct iio_buffer *buffer = indio_dev->buffer;
- int datum_sz;
-
dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n");
- if (!buffer) {
- dev_err(&indio_dev->dev, "Buffer == NULL\n");
- return;
- }
- datum_sz = buffer->access->get_bytes_per_datum(buffer);
- if (len > datum_sz) {
- dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len,
- datum_sz);
- return;
- }
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
}
/* Callback handler to send event after all samples are received and captured */
diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c
index 97c09f0..e14ca60 100644
--- a/drivers/staging/iio/accel/adis16201_ring.c
+++ b/drivers/staging/iio/accel/adis16201_ring.c
@@ -82,7 +82,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c
index 7507e1a..eba2e28 100644
--- a/drivers/staging/iio/accel/adis16203_ring.c
+++ b/drivers/staging/iio/accel/adis16203_ring.c
@@ -81,7 +81,7 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c
index 4c976be..3611a13 100644
--- a/drivers/staging/iio/accel/adis16204_ring.c
+++ b/drivers/staging/iio/accel/adis16204_ring.c
@@ -78,7 +78,7 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c
index f939e29..6af9a5d 100644
--- a/drivers/staging/iio/accel/adis16209_ring.c
+++ b/drivers/staging/iio/accel/adis16209_ring.c
@@ -78,7 +78,7 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c
index caff8e2..e2ac8a8 100644
--- a/drivers/staging/iio/accel/adis16240_ring.c
+++ b/drivers/staging/iio/accel/adis16240_ring.c
@@ -76,7 +76,7 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 2463527..bc38651 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -154,7 +154,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)data + ALIGN(len, sizeof(s64)))
= pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c
index c2906a8..b3dd514 100644
--- a/drivers/staging/iio/adc/ad7298_ring.c
+++ b/drivers/staging/iio/adc/ad7298_ring.c
@@ -93,7 +93,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p)
indio_dev->masklength); i++)
buf[i] = be16_to_cpu(st->rx_buf[i]);
- iio_push_to_buffer(indio_dev->buffer, (u8 *)buf);
+ iio_push_to_buffers(indio_dev, (u8 *)buf);
done:
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c
index ba04d0f..2b25cb0 100644
--- a/drivers/staging/iio/adc/ad7606_ring.c
+++ b/drivers/staging/iio/adc/ad7606_ring.c
@@ -83,7 +83,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s)
if (indio_dev->scan_timestamp)
*((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns;
- iio_push_to_buffer(indio_dev->buffer, buf);
+ iio_push_to_buffers(indio_dev, buf);
done:
gpio_set_value(st->pdata->gpio_convst, 0);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c
index b39923b..ccb8d4d 100644
--- a/drivers/staging/iio/adc/ad7887_ring.c
+++ b/drivers/staging/iio/adc/ad7887_ring.c
@@ -95,7 +95,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p)
memcpy(buf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, buf);
+ iio_push_to_buffers(indio_dev, buf);
done:
kfree(buf);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c
index 86026d9..2c5f384 100644
--- a/drivers/staging/iio/adc/ad799x_ring.c
+++ b/drivers/staging/iio/adc/ad799x_ring.c
@@ -77,7 +77,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p)
memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64),
&time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, rxbuf);
+ iio_push_to_buffers(indio_dev, rxbuf);
done:
kfree(rxbuf);
out:
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index 5f74f3b..688304b 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -80,7 +80,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
- iio_push_to_buffer(indio_dev->buffer, rxbuf);
+ iio_push_to_buffers(indio_dev, rxbuf);
done_free:
kfree(rxbuf);
diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c
index e294cb4..d6c48f8 100644
--- a/drivers/staging/iio/gyro/adis16260_ring.c
+++ b/drivers/staging/iio/gyro/adis16260_ring.c
@@ -81,7 +81,7 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
done:
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index 697d970..dee16f0 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -46,7 +46,6 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
{
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
- struct iio_buffer *buffer = indio_dev->buffer;
int len = 0;
u16 *data;
@@ -76,7 +75,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
i < bitmap_weight(indio_dev->active_scan_mask,
indio_dev->masklength);
i++, j++) {
- j = find_next_bit(buffer->scan_mask,
+ j = find_next_bit(indio_dev->active_scan_mask,
indio_dev->masklength, j);
/* random access read from the 'device' */
data[i] = fakedata[j];
@@ -87,7 +86,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p)
if (indio_dev->scan_timestamp)
*(s64 *)((u8 *)data + ALIGN(len, sizeof(s64)))
= iio_get_time_ns();
- iio_push_to_buffer(buffer, (u8 *)data);
+ iio_push_to_buffers(indio_dev, (u8 *)data);
kfree(data);
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index de21d47..b1fef14 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -647,7 +647,6 @@ static void ad5933_work(struct work_struct *work)
struct ad5933_state *st = container_of(work,
struct ad5933_state, work.work);
struct iio_dev *indio_dev = i2c_get_clientdata(st->client);
- struct iio_buffer *ring = indio_dev->buffer;
signed short buf[2];
unsigned char status;
@@ -677,8 +676,7 @@ static void ad5933_work(struct work_struct *work)
} else {
buf[0] = be16_to_cpu(buf[0]);
}
- /* save datum to the ring */
- iio_push_to_buffer(ring, (u8 *)buf);
+ iio_push_to_buffers(indio_dev, (u8 *)buf);
} else {
/* no data available - try again later */
schedule_delayed_work(&st->work, st->poll_time_jiffies);
diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c
index 260bdd1..d46c1e3 100644
--- a/drivers/staging/iio/imu/adis16400_ring.c
+++ b/drivers/staging/iio/imu/adis16400_ring.c
@@ -114,7 +114,6 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
struct iio_poll_func *pf = p;
struct iio_dev *indio_dev = pf->indio_dev;
struct adis16400_state *st = iio_priv(indio_dev);
- struct iio_buffer *ring = indio_dev->buffer;
int i = 0, j, ret = 0;
s16 *data;
@@ -148,9 +147,9 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p)
}
}
/* Guaranteed to be aligned with 8 byte boundary */
- if (ring->scan_timestamp)
+ if (indio_dev->scan_timestamp)
*((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp;
- iio_push_to_buffer(ring, (u8 *) data);
+ iio_push_to_buffers(indio_dev, (u8 *) data);
done:
kfree(data);
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 9e49bac..4552a4c 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -73,7 +73,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p)
if (indio_dev->scan_timestamp)
dat64[1] = pf->timestamp;
- iio_push_to_buffer(indio_dev->buffer, (u8 *)dat64);
+ iio_push_to_buffers(indio_dev, (u8 *)dat64);
iio_trigger_notify_done(indio_dev->trig);
diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h
index c629b3a..0270405 100644
--- a/include/linux/iio/buffer.h
+++ b/include/linux/iio/buffer.h
@@ -66,7 +66,8 @@ struct iio_buffer_access_funcs {
* @stufftoread: [INTERN] flag to indicate new data.
* @demux_list: [INTERN] list of operations required to demux the scan.
* @demux_bounce: [INTERN] buffer for doing gather from incoming scan.
- **/
+ * @buffer_list: [INTERN] entry in the devices list of current buffers.
+ */
struct iio_buffer {
int length;
int bytes_per_datum;
@@ -81,9 +82,22 @@ struct iio_buffer {
const struct attribute_group *attrs;
struct list_head demux_list;
unsigned char *demux_bounce;
+ struct list_head buffer_list;
};
/**
+ * iio_update_buffers() - add or remove buffer from active list
+ * @indio_dev: device to add buffer to
+ * @insert_buffer: buffer to insert
+ * @remove_buffer: buffer_to_remove
+ *
+ * Note this will tear down the all buffering and build it up again
+ */
+int iio_update_buffers(struct iio_dev *indio_dev,
+ struct iio_buffer *insert_buffer,
+ struct iio_buffer *remove_buffer);
+
+/**
* iio_buffer_init() - Initialize the buffer structure
* @buffer: buffer to be initialized
**/
@@ -115,11 +129,11 @@ int iio_scan_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit);
/**
- * iio_push_to_buffer() - push to a registered buffer.
- * @buffer: IIO buffer structure for device
- * @data: the data to push to the buffer
+ * iio_push_to_buffers() - push to a registered buffer.
+ * @indio_dev: iio_dev structure for device.
+ * @data: Full scan.
*/
-int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data);
+int iio_push_to_buffers(struct iio_dev *indio_dev, unsigned char *data);
int iio_update_demux(struct iio_dev *indio_dev);
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index 7806c24..adca93a 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -410,6 +410,7 @@ struct iio_buffer_setup_ops {
* and owner
* @event_interface: [INTERN] event chrdevs associated with interrupt lines
* @buffer: [DRIVER] any buffer present
+ * @buffer_list: [INTERN] list of all buffers currently attached
* @scan_bytes: [INTERN] num bytes captured to be fed to buffer demux
* @mlock: [INTERN] lock used to prevent simultaneous device state
* changes
@@ -448,6 +449,7 @@ struct iio_dev {
struct iio_event_interface *event_interface;
struct iio_buffer *buffer;
+ struct list_head buffer_list;
int scan_bytes;
struct mutex mlock;
--
1.7.12.4
^ permalink raw reply related [flat|nested] 16+ messages in thread
end of thread, other threads:[~2012-10-31 10:30 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-30 19:36 [PATCH 0/4 V2] staging:iio: Add support for multiple buffers Jonathan Cameron
2012-05-30 19:36 ` [PATCH 1/4] " Jonathan Cameron
2012-06-08 15:13 ` Lars-Peter Clausen
2012-06-09 12:17 ` Jonathan Cameron
2012-06-09 11:50 ` Lars-Peter Clausen
2012-06-09 17:56 ` Jonathan Cameron
2012-05-30 19:36 ` [PATCH 2/4] staging:iio:in kernel users: Add a data field for channel specific info Jonathan Cameron
2012-05-30 19:36 ` [PATCH 3/4] staging:iio: add a callback buffer for in kernel push interface Jonathan Cameron
2012-05-30 19:36 ` [PATCH 4/4] staging:iio: Proof of concept input driver Jonathan Cameron
2012-06-08 15:27 ` Lars-Peter Clausen
2012-06-09 17:56 ` Jonathan Cameron
-- strict thread matches above, loose matches on Subject: below --
2012-06-30 19:06 [PATCH 0/4 V3] staging:iio: Add support for multiple buffers Jonathan Cameron
2012-06-30 19:06 ` [PATCH 1/4] " Jonathan Cameron
2012-10-13 9:24 [PATCH 0/4 V5] staging:iio: Add support for multiple buffers (testing required!) Jonathan Cameron
2012-10-13 9:24 ` [PATCH 1/4] staging:iio: Add support for multiple buffers Jonathan Cameron
2012-10-17 8:37 ` Lars-Peter Clausen
2012-10-19 15:03 ` Jonathan Cameron
2012-10-31 10:30 [PATCH 0/4 V6] staging:iio: Add support for multiple buffers (testing required!) Jonathan Cameron
2012-10-31 10:30 ` [PATCH 1/4] staging:iio: Add support for multiple buffers Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).