linux-iio.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] Add scan demux unit and use it in max1363
@ 2011-11-27 13:10 Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 1/7] staging:iio:find iio channel from scan index util function Jonathan Cameron
                   ` (6 more replies)
  0 siblings, 7 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

The last patch technically is a simple bug fix, but included here as
it came up during testing of this series.

The 'interesting' bits are the rewrite of iio_sw_buffer_preenable. I'd like
people with drivers currently using that function to test and see what
I have broken.  We should also be able to drop a number of cases in specific
drivers in favour of this version.

The demux unit is designed to offer a straight path with little or no
overhead if the client (here still the IIO buffer) needs all the data and to
only get in the way when a subset of the active scan mask is requested.

I may well have messed this up so please please test this set.

Thanks,

Jonathan

Jonathan Cameron (7):
  staging:iio:find iio channel from scan index util function
  staging:iio:buffer add a cache of the timestamp scan index.
  staging:iio: add hook to allow core to perform scan related config.
  staging:iio: make iio_sw_buffer_preenable much more general.
  staging:iio: add demux optionally to path from device to buffer
  staging:iio:adc:max1363 use new demuxing support.
  staging:iio:adc:max1363 correctly set channels as big endian.

 drivers/staging/iio/adc/max1363.h         |   11 ++-
 drivers/staging/iio/adc/max1363_core.c    |   18 ++-
 drivers/staging/iio/adc/max1363_ring.c    |   51 ++-----
 drivers/staging/iio/buffer.h              |   16 ++
 drivers/staging/iio/iio.h                 |   13 ++-
 drivers/staging/iio/industrialio-buffer.c |  216 +++++++++++++++++++++++++----
 drivers/staging/iio/industrialio-core.c   |   11 ++
 7 files changed, 263 insertions(+), 73 deletions(-)

-- 
1.7.7.3

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/7] staging:iio:find iio channel from scan index util function
  2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
@ 2011-11-27 13:10 ` Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 2/7] staging:iio:buffer add a cache of the timestamp scan index Jonathan Cameron
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

From: Jonathan Cameron <jic23@cam.ac.uk>

Useful for getting to the channel based on scan mask alone.

Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
---
 drivers/staging/iio/iio.h               |    8 ++++++++
 drivers/staging/iio/industrialio-core.c |   11 +++++++++++
 2 files changed, 19 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
index 4aed915..95d6318 100644
--- a/drivers/staging/iio/iio.h
+++ b/drivers/staging/iio/iio.h
@@ -323,6 +323,14 @@ struct iio_dev {
 };
 
 /**
+ * iio_find_channel_from_si() - get channel from its scan index
+ * @indio_dev:		device
+ * @si:			scan index to match
+ */
+const struct iio_chan_spec
+*iio_find_channel_from_si(struct iio_dev *indio_dev, int si);
+
+/**
  * iio_device_register() - register a device with the IIO subsystem
  * @indio_dev:		Device structure filled by the device driver
  **/
diff --git a/drivers/staging/iio/industrialio-core.c b/drivers/staging/iio/industrialio-core.c
index 55c0b48..3754b85 100644
--- a/drivers/staging/iio/industrialio-core.c
+++ b/drivers/staging/iio/industrialio-core.c
@@ -89,6 +89,17 @@ static const char * const iio_chan_info_postfix[] = {
 	= "filter_low_pass_3db_frequency",
 };
 
+const struct iio_chan_spec
+*iio_find_channel_from_si(struct iio_dev *indio_dev, int si)
+{
+	int i;
+
+	for (i = 0; i < indio_dev->num_channels; i++)
+		if (indio_dev->channels[i].scan_index == si)
+			return &indio_dev->channels[i];
+	return NULL;
+}
+
 /**
  * struct iio_detected_event_list - list element for events that have occurred
  * @list:		linked list header
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/7] staging:iio:buffer add a cache of the timestamp scan index.
  2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 1/7] staging:iio:find iio channel from scan index util function Jonathan Cameron
@ 2011-11-27 13:10 ` Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 3/7] staging:iio: add hook to allow core to perform scan related config Jonathan Cameron
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

From: Jonathan Cameron <jic23@cam.ac.uk>

Basically avoids looking it up lots of times.

Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
---
 drivers/staging/iio/buffer.h              |    1 +
 drivers/staging/iio/industrialio-buffer.c |    3 +++
 2 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/drivers/staging/iio/buffer.h b/drivers/staging/iio/buffer.h
index 9de581e..4b8f619 100644
--- a/drivers/staging/iio/buffer.h
+++ b/drivers/staging/iio/buffer.h
@@ -106,6 +106,7 @@ struct iio_buffer {
 	int					scan_count;
 	long					*scan_mask;
 	bool					scan_timestamp;
+	unsigned				scan_index_timestamp;
 	const struct iio_buffer_access_funcs	*access;
 	const struct iio_buffer_setup_ops		*setup_ops;
 	struct list_head			scan_el_dev_attr_list;
diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
index f757bb7..cae7922 100644
--- a/drivers/staging/iio/industrialio-buffer.c
+++ b/drivers/staging/iio/industrialio-buffer.c
@@ -313,6 +313,9 @@ int iio_buffer_register(struct iio_dev *indio_dev,
 			if (ret < 0)
 				goto error_cleanup_dynamic;
 			attrcount += ret;
+			if (channels[i].type == IIO_TIMESTAMP)
+				buffer->scan_index_timestamp =
+					channels[i].scan_index;
 		}
 		if (indio_dev->masklength && buffer->scan_mask == NULL) {
 			buffer->scan_mask
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/7] staging:iio: add hook to allow core to perform scan related config.
  2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 1/7] staging:iio:find iio channel from scan index util function Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 2/7] staging:iio:buffer add a cache of the timestamp scan index Jonathan Cameron
@ 2011-11-27 13:10 ` Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 4/7] staging:iio: make iio_sw_buffer_preenable much more general Jonathan Cameron
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
 drivers/staging/iio/iio.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
index 95d6318..4fb8f2f 100644
--- a/drivers/staging/iio/iio.h
+++ b/drivers/staging/iio/iio.h
@@ -262,7 +262,8 @@ struct iio_info {
 				 int val);
 	int (*validate_trigger)(struct iio_dev *indio_dev,
 				struct iio_trigger *trig);
-
+	int (*update_scan_mode)(struct iio_dev *indio_dev,
+				const unsigned long *scan_mask);
 };
 
 /**
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/7] staging:iio: make iio_sw_buffer_preenable much more general.
  2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
                   ` (2 preceding siblings ...)
  2011-11-27 13:10 ` [PATCH 3/7] staging:iio: add hook to allow core to perform scan related config Jonathan Cameron
@ 2011-11-27 13:10 ` Jonathan Cameron
  2011-11-28  9:23   ` Lars-Peter Clausen
  2011-11-27 13:10 ` [PATCH 5/7] staging:iio: add demux optionally to path from device to buffer Jonathan Cameron
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

Also introduces active_scan_mask storage to tell the core what is
really being currently captured from the device (different from
what is desired as often has bonus channels).

Signed-off-by: Jonathan Cameron <jic23@kernel.org>
---
 drivers/staging/iio/iio.h                 |    2 +
 drivers/staging/iio/industrialio-buffer.c |   65 +++++++++++++++++-----------
 2 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
index 4fb8f2f..c225542 100644
--- a/drivers/staging/iio/iio.h
+++ b/drivers/staging/iio/iio.h
@@ -280,6 +280,7 @@ struct iio_info {
  * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
  * @masklength:		[INTERN] the length of the mask established from
  *			channels
+ * @active_scan_mask:	[INTERN] union of all scan masks requested by buffers
  * @trig:		[INTERN] current device trigger (buffer modes)
  * @pollfunc:		[DRIVER] function run on trigger being received
  * @channels:		[DRIVER] channel specification structure table
@@ -307,6 +308,7 @@ struct iio_dev {
 
 	unsigned long			*available_scan_masks;
 	unsigned			masklength;
+	unsigned long			*active_scan_mask;
 	struct iio_trigger		*trig;
 	struct iio_poll_func		*pollfunc;
 
diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
index cae7922..fb14e37 100644
--- a/drivers/staging/iio/industrialio-buffer.c
+++ b/drivers/staging/iio/industrialio-buffer.c
@@ -533,32 +533,6 @@ ssize_t iio_buffer_show_enable(struct device *dev,
 }
 EXPORT_SYMBOL(iio_buffer_show_enable);
 
-int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
-{
-	struct iio_buffer *buffer = indio_dev->buffer;
-	size_t size;
-	dev_dbg(&indio_dev->dev, "%s\n", __func__);
-	/* Check if there are any scan elements enabled, if not fail*/
-	if (!(buffer->scan_count || buffer->scan_timestamp))
-		return -EINVAL;
-	if (buffer->scan_timestamp)
-		if (buffer->scan_count)
-			/* Timestamp (aligned to s64) and data */
-			size = (((buffer->scan_count * buffer->bpe)
-					+ sizeof(s64) - 1)
-				& ~(sizeof(s64) - 1))
-				+ sizeof(s64);
-		else /* Timestamp only  */
-			size = sizeof(s64);
-	else /* Data only */
-		size = buffer->scan_count * buffer->bpe;
-	buffer->access->set_bytes_per_datum(buffer, size);
-
-	return 0;
-}
-EXPORT_SYMBOL(iio_sw_buffer_preenable);
-
-
 /* note NULL used as error indicator as it doesn't make sense. */
 static unsigned long *iio_scan_mask_match(unsigned long *av_masks,
 					  unsigned int masklength,
@@ -574,6 +548,45 @@ static unsigned long *iio_scan_mask_match(unsigned long *av_masks,
 	return NULL;
 }
 
+int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
+{
+	struct iio_buffer *buffer = indio_dev->buffer;
+	const struct iio_chan_spec *ch;
+	unsigned bytes = 0;
+	int length, i;
+	dev_dbg(&indio_dev->dev, "%s\n", __func__);
+
+	/* How much space will the demuxed element take? */
+	for_each_set_bit(i, buffer->scan_mask,
+			 indio_dev->masklength) {
+		ch = iio_find_channel_from_si(indio_dev, i);
+		length = ch->scan_type.storagebits/8;
+		if (bytes % length)
+			bytes += length - bytes % length;
+		bytes += length;
+	}
+	if (buffer->scan_timestamp) {
+		ch = iio_find_channel_from_si(indio_dev,
+					      buffer->scan_index_timestamp);
+		length = ch->scan_type.storagebits/8;
+		if (bytes % length)
+			bytes += length - bytes % length;
+		bytes += length;
+	}
+	buffer->access->set_bytes_per_datum(buffer, bytes);
+
+	/* What scan mask do we actually have ?*/
+	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;
+	return 0;
+}
+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
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/7] staging:iio: add demux optionally to path from device to buffer
  2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
                   ` (3 preceding siblings ...)
  2011-11-27 13:10 ` [PATCH 4/7] staging:iio: make iio_sw_buffer_preenable much more general Jonathan Cameron
@ 2011-11-27 13:10 ` Jonathan Cameron
  2011-11-28  9:39   ` Lars-Peter Clausen
  2011-11-27 13:10 ` [PATCH 6/7] staging:iio:adc:max1363 use new demuxing support Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 7/7] staging:iio:adc:max1363 correctly set channels as big endian Jonathan Cameron
  6 siblings, 1 reply; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

From: Jonathan Cameron <jic23@cam.ac.uk>

This gives you only what you ask for which is handy
for some devices with weird scan combinations.

Routes all data flow through a core utility function.
That and this demuxing support will be needed to do
demuxing to multiple destinations in kernel.

Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
---
 drivers/staging/iio/buffer.h              |   15 +++
 drivers/staging/iio/industrialio-buffer.c |  148 ++++++++++++++++++++++++++++-
 2 files changed, 159 insertions(+), 4 deletions(-)

diff --git a/drivers/staging/iio/buffer.h b/drivers/staging/iio/buffer.h
index 4b8f619..5282441 100644
--- a/drivers/staging/iio/buffer.h
+++ b/drivers/staging/iio/buffer.h
@@ -95,6 +95,8 @@ struct iio_buffer_setup_ops {
  * @access:		[DRIVER] buffer access functions associated with the
  *			implementation.
  * @flags:		[INTERN] file ops related flags including busy flag.
+ * @demux_list:		[INTERN] list of operations required to demux the scan.
+ * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
  **/
 struct iio_buffer {
 	struct iio_dev				*indio_dev;
@@ -115,6 +117,8 @@ struct iio_buffer {
 	bool					stufftoread;
 	unsigned long				flags;
 	const struct attribute_group *attrs;
+	struct list_head			demux_list;
+	unsigned char				*demux_bounce;
 };
 
 /**
@@ -153,6 +157,17 @@ int iio_scan_mask_set(struct iio_buffer *buffer, int bit);
 	container_of(d, struct iio_buffer, dev)
 
 /**
+ * iio_push_to_buffer() - push to a registered buffer.
+ * @buffer:		IIO buffer structure for device
+ * @scan:		Full scan.
+ * @timestamp:
+ */
+int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
+		       s64 timestamp);
+
+int iio_update_demux(struct iio_dev *indio_dev);
+
+/**
  * iio_buffer_register() - register the buffer with IIO core
  * @indio_dev: device with the buffer to be registered
  **/
diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
index fb14e37..352f9f1 100644
--- a/drivers/staging/iio/industrialio-buffer.c
+++ b/drivers/staging/iio/industrialio-buffer.c
@@ -87,6 +87,7 @@ void iio_chrdev_buffer_release(struct iio_dev *indio_dev)
 
 void iio_buffer_init(struct iio_buffer *buffer, struct iio_dev *indio_dev)
 {
+	INIT_LIST_HEAD(&buffer->demux_list);
 	buffer->indio_dev = indio_dev;
 	init_waitqueue_head(&buffer->pollq);
 }
@@ -128,10 +129,9 @@ static ssize_t iio_scan_el_show(struct device *dev,
 	int ret;
 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
-	ret = iio_scan_mask_query(indio_dev->buffer,
-				  to_iio_dev_attr(attr)->address);
-	if (ret < 0)
-		return ret;
+	ret = test_bit(to_iio_dev_attr(attr)->address,
+		       indio_dev->buffer->scan_mask);
+
 	return sprintf(buf, "%d\n", ret);
 }
 
@@ -583,6 +583,12 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
 					    buffer->scan_mask);
 	else
 		indio_dev->active_scan_mask = buffer->scan_mask;
+	iio_update_demux(indio_dev);
+
+	if (indio_dev->info->update_scan_mode)
+		return indio_dev->info
+			->update_scan_mode(indio_dev,
+					   indio_dev->active_scan_mask);
 	return 0;
 }
 EXPORT_SYMBOL(iio_sw_buffer_preenable);
@@ -652,3 +658,137 @@ int iio_scan_mask_query(struct iio_buffer *buffer, int bit)
 	return test_bit(bit, mask);
 };
 EXPORT_SYMBOL_GPL(iio_scan_mask_query);
+
+/**
+ * struct iio_demux_table() - table describing demux memcpy ops
+ * @from:	index to copy from
+ * @to:	index to copy to
+ * @length:	how many bytes to copy
+ * @l:		list head used for management
+ */
+struct iio_demux_table {
+	unsigned from;
+	unsigned to;
+	unsigned length;
+	struct list_head l;
+};
+
+static unsigned char *iio_demux(struct iio_buffer *buffer,
+				 unsigned char *datain)
+{
+	struct iio_demux_table *t;
+
+	if (list_empty(&buffer->demux_list))
+		return datain;
+	list_for_each_entry(t, &buffer->demux_list, l)
+		memcpy(buffer->demux_bounce + t->to,
+		       datain + t->from, t->length);
+
+	return buffer->demux_bounce;
+}
+
+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);
+
+int iio_update_demux(struct iio_dev *indio_dev)
+{
+	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, *q;
+
+	/* Clear out any old demux */
+	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
+		list_del(&p->l);
+		kfree(p);
+	}
+	kfree(buffer->demux_bounce);
+	buffer->demux_bounce = NULL;
+
+	/* First work out which scan mode we will actually have */
+	if (bitmap_equal(indio_dev->active_scan_mask,
+			 buffer->scan_mask,
+			 indio_dev->masklength))
+		return 0;
+
+	out_ind = find_first_bit(buffer->scan_mask, indio_dev->masklength);
+	/* Now we have the two masks, work from least sig and build up sizes */
+	while (out_ind != indio_dev->masklength) {
+		in_ind = find_next_bit(indio_dev->active_scan_mask,
+				       indio_dev->masklength,
+				       in_ind + 1);
+		while (in_ind != out_ind) {
+			in_ind = find_next_bit(indio_dev->active_scan_mask,
+					       indio_dev->masklength,
+					       in_ind + 1);
+			ch = iio_find_channel_from_si(indio_dev, in_ind);
+			length = ch->scan_type.storagebits/8;
+			/* Make sure we are aligned */
+			in_loc += length;
+			if (in_loc % length)
+				in_loc += length - in_loc % length;
+		}
+		p = kmalloc(sizeof(*p), GFP_KERNEL);
+		if (p == NULL) {
+			ret = -ENOMEM;
+			goto error_clear_mux_table;
+		}
+		ch = iio_find_channel_from_si(indio_dev, in_ind);
+		length = ch->scan_type.storagebits/8;
+		if (out_loc % length)
+			out_loc += length - out_loc % length;
+		if (in_loc % length)
+			in_loc += length - in_loc % length;
+		p->from = in_loc;
+		p->to = out_loc;
+		p->length = length;
+		list_add_tail(&p->l, &buffer->demux_list);
+		out_loc += length;
+		in_loc += length;
+		out_ind = find_next_bit(buffer->scan_mask,
+					indio_dev->masklength,
+					out_ind + 1);
+	}
+	/* Relies on scan_timestamp being last */
+	if (buffer->scan_timestamp) {
+		p = kmalloc(sizeof(*p), GFP_KERNEL);
+		if (p == NULL) {
+			ret = -ENOMEM;
+			goto error_clear_mux_table;
+		}
+		ch = iio_find_channel_from_si(indio_dev,
+			buffer->scan_index_timestamp);
+		length = ch->scan_type.storagebits/8;
+		if (out_loc % length)
+			out_loc += length - out_loc % length;
+		if (in_loc % length)
+			in_loc += length - in_loc % length;
+		p->from = in_loc;
+		p->to = out_loc;
+		p->length = length;
+		list_add_tail(&p->l, &buffer->demux_list);
+		out_loc += length;
+		in_loc += length;
+	}
+	buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
+	if (buffer->demux_bounce == NULL) {
+		ret = -ENOMEM;
+		goto error_clear_mux_table;
+	}
+	return 0;
+
+error_clear_mux_table:
+	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
+		list_del(&p->l);
+		kfree(p);
+	}
+	return ret;
+}
+EXPORT_SYMBOL_GPL(iio_update_demux);
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 6/7] staging:iio:adc:max1363 use new demuxing support.
  2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
                   ` (4 preceding siblings ...)
  2011-11-27 13:10 ` [PATCH 5/7] staging:iio: add demux optionally to path from device to buffer Jonathan Cameron
@ 2011-11-27 13:10 ` Jonathan Cameron
  2011-11-27 13:10 ` [PATCH 7/7] staging:iio:adc:max1363 correctly set channels as big endian Jonathan Cameron
  6 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

From: Jonathan Cameron <jic23@cam.ac.uk>

Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
---
 drivers/staging/iio/adc/max1363.h      |   11 +++++-
 drivers/staging/iio/adc/max1363_core.c |    4 ++-
 drivers/staging/iio/adc/max1363_ring.c |   51 +++++++++-----------------------
 3 files changed, 26 insertions(+), 40 deletions(-)

diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h
index cbcb08a..fb52783 100644
--- a/drivers/staging/iio/adc/max1363.h
+++ b/drivers/staging/iio/adc/max1363.h
@@ -146,18 +146,25 @@ struct max1363_state {
 };
 
 const struct max1363_mode
-*max1363_match_mode(unsigned long *mask, const struct max1363_chip_info *ci);
+*max1363_match_mode(const unsigned long *mask,
+		    const struct max1363_chip_info *ci);
 
 int max1363_set_scan_mode(struct max1363_state *st);
 
 #ifdef CONFIG_MAX1363_RING_BUFFER
-
+int max1363_update_scan_mode(struct iio_dev *indio_dev,
+			     const unsigned long *scan_mask);
 int max1363_single_channel_from_ring(const long *mask,
 				     struct max1363_state *st);
 int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev);
 void max1363_ring_cleanup(struct iio_dev *indio_dev);
 
 #else /* CONFIG_MAX1363_RING_BUFFER */
+int max1363_update_scan_mode(struct iio_dev *indio_dev,
+			     const long *scan_mask)
+{
+	return 0;
+}
 
 int max1363_single_channel_from_ring(long mask, struct max1363_state *st)
 {
diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index c3e28e1..7e078fc 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -148,7 +148,8 @@ static const struct max1363_mode max1363_mode_table[] = {
 };
 
 const struct max1363_mode
-*max1363_match_mode(unsigned long *mask, const struct max1363_chip_info *ci)
+*max1363_match_mode(const unsigned long *mask,
+const struct max1363_chip_info *ci)
 {
 	int i;
 	if (mask)
@@ -834,6 +835,7 @@ static const struct iio_info max1363_info = {
 	.read_event_config = &max1363_read_event_config,
 	.write_event_config = &max1363_write_event_config,
 	.read_raw = &max1363_read_raw,
+	.update_scan_mode = &max1363_update_scan_mode,
 	.driver_module = THIS_MODULE,
 	.event_attrs = &max1363_event_attribute_group,
 };
diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c
index 3c5e199..19977a6 100644
--- a/drivers/staging/iio/adc/max1363_ring.c
+++ b/drivers/staging/iio/adc/max1363_ring.c
@@ -57,46 +57,19 @@ error_ret:
 	return ret;
 }
 
-
-/**
- * max1363_ring_preenable() - setup the parameters of the ring before enabling
- *
- * The complex nature of the setting of the nuber of bytes per datum is due
- * to this driver currently ensuring that the timestamp is stored at an 8
- * byte boundary.
- **/
-static int max1363_ring_preenable(struct iio_dev *indio_dev)
+int max1363_update_scan_mode(struct iio_dev *indio_dev,
+			     const unsigned long *scan_mask)
 {
 	struct max1363_state *st = iio_priv(indio_dev);
-	struct iio_buffer *ring = indio_dev->buffer;
-	size_t d_size = 0;
-	unsigned long numvals;
 
 	/*
 	 * Need to figure out the current mode based upon the requested
 	 * scan mask in iio_dev
 	 */
-	st->current_mode = max1363_match_mode(ring->scan_mask,
-					st->chip_info);
+	st->current_mode = max1363_match_mode(scan_mask, st->chip_info);
 	if (!st->current_mode)
 		return -EINVAL;
-
 	max1363_set_scan_mode(st);
-
-	numvals = bitmap_weight(st->current_mode->modemask,
-				indio_dev->masklength);
-	if (ring->access->set_bytes_per_datum) {
-		if (ring->scan_timestamp)
-			d_size += sizeof(s64);
-		if (st->chip_info->bits != 8)
-			d_size += numvals*2;
-		else
-			d_size += numvals;
-		if (ring->scan_timestamp && (d_size % 8))
-			d_size += 8 - (d_size % 8);
-		ring->access->set_bytes_per_datum(ring, d_size);
-	}
-
 	return 0;
 }
 
@@ -114,12 +87,14 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
 
 	/* Ensure the timestamp is 8 byte aligned */
 	if (st->chip_info->bits != 8)
-		d_size = numvals*2 + sizeof(s64);
+		d_size = numvals*2;
 	else
-		d_size = numvals + sizeof(s64);
-	if (d_size % sizeof(s64))
-		d_size += sizeof(s64) - (d_size % sizeof(s64));
-
+		d_size = numvals;
+	if (indio_dev->buffer->scan_timestamp) {
+		d_size += sizeof(s64);
+		if (d_size % sizeof(s64))
+			d_size += sizeof(s64) - (d_size % sizeof(s64));
+	}
 	/* Monitor mode prevents reading. Whilst not currently implemented
 	 * might as well have this test in here in the meantime as it does
 	 * no harm.
@@ -138,9 +113,11 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p)
 		goto done;
 
 	time_ns = iio_get_time_ns();
+
 	if (indio_dev->buffer->scan_timestamp)
 		memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns));
-	indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns);
+	iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns);
+
 done:
 	iio_trigger_notify_done(indio_dev->trig);
 	kfree(rxbuf);
@@ -150,7 +127,7 @@ done:
 
 static const struct iio_buffer_setup_ops max1363_ring_setup_ops = {
 	.postenable = &iio_triggered_buffer_postenable,
-	.preenable = &max1363_ring_preenable,
+	.preenable = &iio_sw_buffer_preenable,
 	.predisable = &iio_triggered_buffer_predisable,
 };
 
-- 
1.7.7.3

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 7/7] staging:iio:adc:max1363 correctly set channels as big endian.
  2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
                   ` (5 preceding siblings ...)
  2011-11-27 13:10 ` [PATCH 6/7] staging:iio:adc:max1363 use new demuxing support Jonathan Cameron
@ 2011-11-27 13:10 ` Jonathan Cameron
  6 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-11-27 13:10 UTC (permalink / raw)
  To: linux-iio; +Cc: lars, Michael.Hennerich, Jonathan Cameron

From: Jonathan Cameron <jic23@cam.ac.uk>

Also, the differential channels should always have been signed.

Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
---
 drivers/staging/iio/adc/max1363_core.c |   14 ++++++++++++--
 1 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c
index 7e078fc..9febd1b 100644
--- a/drivers/staging/iio/adc/max1363_core.c
+++ b/drivers/staging/iio/adc/max1363_core.c
@@ -298,7 +298,12 @@ static const enum max1363_modes max1363_mode_list[] = {
 		.channel = num,						\
 		.address = addr,					\
 		.info_mask = MAX1363_INFO_MASK,				\
-		.scan_type = IIO_ST('u', bits, (bits > 8) ? 16 : 8, 0), \
+		.scan_type = {						\
+			.sign = 'u',					\
+			.realbits = bits,				\
+			.storagebits = (bits > 8) ? 16 : 8,		\
+			.endianness = IIO_BE,				\
+		},							\
 		.scan_index = si,					\
 		.event_mask = evmask,					\
 	}
@@ -313,7 +318,12 @@ static const enum max1363_modes max1363_mode_list[] = {
 		.channel2 = num2,					\
 		.address = addr,					\
 		.info_mask = MAX1363_INFO_MASK,				\
-		.scan_type = IIO_ST('u', bits, (bits > 8) ? 16 : 8, 0), \
+		.scan_type = {						\
+			.sign = 's',					\
+			.realbits = bits,				\
+			.storagebits = (bits > 8) ? 16 : 8,		\
+			.endianness = IIO_BE,				\
+		},							\
 		.scan_index = si,					\
 		.event_mask = evmask,					\
 	}
-- 
1.7.7.3


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/7] staging:iio: make iio_sw_buffer_preenable much more general.
  2011-11-27 13:10 ` [PATCH 4/7] staging:iio: make iio_sw_buffer_preenable much more general Jonathan Cameron
@ 2011-11-28  9:23   ` Lars-Peter Clausen
  2011-12-01 21:17     ` Jonathan Cameron
  0 siblings, 1 reply; 12+ messages in thread
From: Lars-Peter Clausen @ 2011-11-28  9:23 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Michael.Hennerich

On 11/27/2011 02:10 PM, Jonathan Cameron wrote:
> Also introduces active_scan_mask storage to tell the core what is
> really being currently captured from the device (different from
> what is desired as often has bonus channels).
> 
> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
> ---
>  drivers/staging/iio/iio.h                 |    2 +
>  drivers/staging/iio/industrialio-buffer.c |   65 +++++++++++++++++-----------
>  2 files changed, 41 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/staging/iio/iio.h b/drivers/staging/iio/iio.h
> index 4fb8f2f..c225542 100644
> --- a/drivers/staging/iio/iio.h
> +++ b/drivers/staging/iio/iio.h
> @@ -280,6 +280,7 @@ struct iio_info {
>   * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
>   * @masklength:		[INTERN] the length of the mask established from
>   *			channels
> + * @active_scan_mask:	[INTERN] union of all scan masks requested by buffers
>   * @trig:		[INTERN] current device trigger (buffer modes)
>   * @pollfunc:		[DRIVER] function run on trigger being received
>   * @channels:		[DRIVER] channel specification structure table
> @@ -307,6 +308,7 @@ struct iio_dev {
>  
>  	unsigned long			*available_scan_masks;
>  	unsigned			masklength;
> +	unsigned long			*active_scan_mask;
>  	struct iio_trigger		*trig;
>  	struct iio_poll_func		*pollfunc;
>  
> diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
> index cae7922..fb14e37 100644
> --- a/drivers/staging/iio/industrialio-buffer.c
> +++ b/drivers/staging/iio/industrialio-buffer.c
> @@ -533,32 +533,6 @@ ssize_t iio_buffer_show_enable(struct device *dev,
>  }
>  EXPORT_SYMBOL(iio_buffer_show_enable);
>  
> -int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
> -{
> -	struct iio_buffer *buffer = indio_dev->buffer;
> -	size_t size;
> -	dev_dbg(&indio_dev->dev, "%s\n", __func__);
> -	/* Check if there are any scan elements enabled, if not fail*/
> -	if (!(buffer->scan_count || buffer->scan_timestamp))
> -		return -EINVAL;
> -	if (buffer->scan_timestamp)
> -		if (buffer->scan_count)
> -			/* Timestamp (aligned to s64) and data */
> -			size = (((buffer->scan_count * buffer->bpe)
> -					+ sizeof(s64) - 1)
> -				& ~(sizeof(s64) - 1))
> -				+ sizeof(s64);
> -		else /* Timestamp only  */
> -			size = sizeof(s64);
> -	else /* Data only */
> -		size = buffer->scan_count * buffer->bpe;
> -	buffer->access->set_bytes_per_datum(buffer, size);
> -
> -	return 0;
> -}
> -EXPORT_SYMBOL(iio_sw_buffer_preenable);
> -
> -
>  /* note NULL used as error indicator as it doesn't make sense. */
>  static unsigned long *iio_scan_mask_match(unsigned long *av_masks,
>  					  unsigned int masklength,
> @@ -574,6 +548,45 @@ static unsigned long *iio_scan_mask_match(unsigned long *av_masks,
>  	return NULL;
>  }
>  
> +int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
> +{
> +	struct iio_buffer *buffer = indio_dev->buffer;
> +	const struct iio_chan_spec *ch;
> +	unsigned bytes = 0;
> +	int length, i;
> +	dev_dbg(&indio_dev->dev, "%s\n", __func__);
> +
> +	/* How much space will the demuxed element take? */
> +	for_each_set_bit(i, buffer->scan_mask,
> +			 indio_dev->masklength) {
> +		ch = iio_find_channel_from_si(indio_dev, i);
> +		length = ch->scan_type.storagebits/8;
> +		if (bytes % length)
> +			bytes += length - bytes % length;

bytes = ALIGN(bytes, length); would probably make it more obvious what is
going on here.

> +		bytes += length;
> +	}
> +	if (buffer->scan_timestamp) {
> +		ch = iio_find_channel_from_si(indio_dev,
> +					      buffer->scan_index_timestamp);
> +		length = ch->scan_type.storagebits/8;
> +		if (bytes % length)
> +			bytes += length - bytes % length;
> +		bytes += length;
> +	}
> +	buffer->access->set_bytes_per_datum(buffer, bytes);
> +
> +	/* What scan mask do we actually have ?*/
> +	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;
> +	return 0;
> +}
> +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


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/7] staging:iio: add demux optionally to path from device to buffer
  2011-11-27 13:10 ` [PATCH 5/7] staging:iio: add demux optionally to path from device to buffer Jonathan Cameron
@ 2011-11-28  9:39   ` Lars-Peter Clausen
  2011-12-01 21:34     ` Jonathan Cameron
  0 siblings, 1 reply; 12+ messages in thread
From: Lars-Peter Clausen @ 2011-11-28  9:39 UTC (permalink / raw)
  To: Jonathan Cameron; +Cc: linux-iio, Michael.Hennerich, Jonathan Cameron

On 11/27/2011 02:10 PM, Jonathan Cameron wrote:
> From: Jonathan Cameron <jic23@cam.ac.uk>
> 
> This gives you only what you ask for which is handy
> for some devices with weird scan combinations.
> 
> Routes all data flow through a core utility function.
> That and this demuxing support will be needed to do
> demuxing to multiple destinations in kernel.
> 
> Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
> ---
>  drivers/staging/iio/buffer.h              |   15 +++
>  drivers/staging/iio/industrialio-buffer.c |  148 ++++++++++++++++++++++++++++-
>  2 files changed, 159 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/staging/iio/buffer.h b/drivers/staging/iio/buffer.h
> index 4b8f619..5282441 100644
> --- a/drivers/staging/iio/buffer.h
> +++ b/drivers/staging/iio/buffer.h
> @@ -95,6 +95,8 @@ struct iio_buffer_setup_ops {
>   * @access:		[DRIVER] buffer access functions associated with the
>   *			implementation.
>   * @flags:		[INTERN] file ops related flags including busy flag.
> + * @demux_list:		[INTERN] list of operations required to demux the scan.
> + * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
>   **/
>  struct iio_buffer {
>  	struct iio_dev				*indio_dev;
> @@ -115,6 +117,8 @@ struct iio_buffer {
>  	bool					stufftoread;
>  	unsigned long				flags;
>  	const struct attribute_group *attrs;
> +	struct list_head			demux_list;
> +	unsigned char				*demux_bounce;
>  };
>  
>  /**
> @@ -153,6 +157,17 @@ int iio_scan_mask_set(struct iio_buffer *buffer, int bit);
>  	container_of(d, struct iio_buffer, dev)
>  
>  /**
> + * iio_push_to_buffer() - push to a registered buffer.
> + * @buffer:		IIO buffer structure for device
> + * @scan:		Full scan.
> + * @timestamp:
> + */
> +int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
> +		       s64 timestamp);
> +
> +int iio_update_demux(struct iio_dev *indio_dev);
> +
> +/**
>   * iio_buffer_register() - register the buffer with IIO core
>   * @indio_dev: device with the buffer to be registered
>   **/
> diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
> index fb14e37..352f9f1 100644
> --- a/drivers/staging/iio/industrialio-buffer.c
> +++ b/drivers/staging/iio/industrialio-buffer.c
> @@ -87,6 +87,7 @@ void iio_chrdev_buffer_release(struct iio_dev *indio_dev)
>  
>  void iio_buffer_init(struct iio_buffer *buffer, struct iio_dev *indio_dev)
>  {
> +	INIT_LIST_HEAD(&buffer->demux_list);
>  	buffer->indio_dev = indio_dev;
>  	init_waitqueue_head(&buffer->pollq);
>  }
> @@ -128,10 +129,9 @@ static ssize_t iio_scan_el_show(struct device *dev,
>  	int ret;
>  	struct iio_dev *indio_dev = dev_get_drvdata(dev);
>  
> -	ret = iio_scan_mask_query(indio_dev->buffer,
> -				  to_iio_dev_attr(attr)->address);
> -	if (ret < 0)
> -		return ret;
> +	ret = test_bit(to_iio_dev_attr(attr)->address,
> +		       indio_dev->buffer->scan_mask);
> +
>  	return sprintf(buf, "%d\n", ret);
>  }
>  
> @@ -583,6 +583,12 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>  					    buffer->scan_mask);
>  	else
>  		indio_dev->active_scan_mask = buffer->scan_mask;
> +	iio_update_demux(indio_dev);
> +
> +	if (indio_dev->info->update_scan_mode)
> +		return indio_dev->info
> +			->update_scan_mode(indio_dev,
> +					   indio_dev->active_scan_mask);
>  	return 0;
>  }
>  EXPORT_SYMBOL(iio_sw_buffer_preenable);
> @@ -652,3 +658,137 @@ int iio_scan_mask_query(struct iio_buffer *buffer, int bit)
>  	return test_bit(bit, mask);
>  };
>  EXPORT_SYMBOL_GPL(iio_scan_mask_query);
> +
> +/**
> + * struct iio_demux_table() - table describing demux memcpy ops
> + * @from:	index to copy from
> + * @to:	index to copy to
> + * @length:	how many bytes to copy
> + * @l:		list head used for management
> + */
> +struct iio_demux_table {
> +	unsigned from;
> +	unsigned to;
> +	unsigned length;
> +	struct list_head l;
> +};
> +
> +static unsigned char *iio_demux(struct iio_buffer *buffer,
> +				 unsigned char *datain)
> +{
> +	struct iio_demux_table *t;
> +
> +	if (list_empty(&buffer->demux_list))
> +		return datain;
> +	list_for_each_entry(t, &buffer->demux_list, l)
> +		memcpy(buffer->demux_bounce + t->to,
> +		       datain + t->from, t->length);
> +
> +	return buffer->demux_bounce;
> +}
> +
> +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);

I wonder if we want to integrate the demuxing into the store_to callbacks of
the buffer, this would avoid the need for the bounce buffer and reduce the
number of memcpys. But maybe we can just add it later.


> +
> +int iio_update_demux(struct iio_dev *indio_dev)
> +{
> +	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, *q;
> +
> +	/* Clear out any old demux */
> +	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
> +		list_del(&p->l);
> +		kfree(p);
> +	}
> +	kfree(buffer->demux_bounce);
> +	buffer->demux_bounce = NULL;
> +
> +	/* First work out which scan mode we will actually have */
> +	if (bitmap_equal(indio_dev->active_scan_mask,
> +			 buffer->scan_mask,
> +			 indio_dev->masklength))
> +		return 0;
> +
> +	out_ind = find_first_bit(buffer->scan_mask, indio_dev->masklength);
> +	/* Now we have the two masks, work from least sig and build up sizes */
> +	while (out_ind != indio_dev->masklength) {

	This looks a bit like an open-coded for_each_set_bit

> +		in_ind = find_next_bit(indio_dev->active_scan_mask,
> +				       indio_dev->masklength,
> +				       in_ind + 1);
> +		while (in_ind != out_ind) {
> +			in_ind = find_next_bit(indio_dev->active_scan_mask,
> +					       indio_dev->masklength,
> +					       in_ind + 1);

same here for_each_set_bit(in_ind, indio->active_scan_mask, out_ind)

> +			ch = iio_find_channel_from_si(indio_dev, in_ind);
> +			length = ch->scan_type.storagebits/8;
> +			/* Make sure we are aligned */
> +			in_loc += length;
> +			if (in_loc % length)
> +				in_loc += length - in_loc % length;
> +		}
> +		p = kmalloc(sizeof(*p), GFP_KERNEL);
> +		if (p == NULL) {
> +			ret = -ENOMEM;
> +			goto error_clear_mux_table;
> +		}
> +		ch = iio_find_channel_from_si(indio_dev, in_ind);
> +		length = ch->scan_type.storagebits/8;
> +		if (out_loc % length)
> +			out_loc += length - out_loc % length;
> +		if (in_loc % length)
> +			in_loc += length - in_loc % length;
> +		p->from = in_loc;
> +		p->to = out_loc;
> +		p->length = length;
> +		list_add_tail(&p->l, &buffer->demux_list);
> +		out_loc += length;
> +		in_loc += length;
> +		out_ind = find_next_bit(buffer->scan_mask,
> +					indio_dev->masklength,
> +					out_ind + 1);
> +	}
> +	/* Relies on scan_timestamp being last */
> +	if (buffer->scan_timestamp) {
> +		p = kmalloc(sizeof(*p), GFP_KERNEL);
> +		if (p == NULL) {
> +			ret = -ENOMEM;
> +			goto error_clear_mux_table;
> +		}
> +		ch = iio_find_channel_from_si(indio_dev,
> +			buffer->scan_index_timestamp);
> +		length = ch->scan_type.storagebits/8;
> +		if (out_loc % length)
> +			out_loc += length - out_loc % length;
> +		if (in_loc % length)
> +			in_loc += length - in_loc % length;
> +		p->from = in_loc;
> +		p->to = out_loc;
> +		p->length = length;
> +		list_add_tail(&p->l, &buffer->demux_list);
> +		out_loc += length;
> +		in_loc += length;
> +	}
> +	buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
> +	if (buffer->demux_bounce == NULL) {
> +		ret = -ENOMEM;
> +		goto error_clear_mux_table;
> +	}
> +	return 0;
> +
> +error_clear_mux_table:
> +	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
> +		list_del(&p->l);
> +		kfree(p);
> +	}
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(iio_update_demux);


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 4/7] staging:iio: make iio_sw_buffer_preenable much more general.
  2011-11-28  9:23   ` Lars-Peter Clausen
@ 2011-12-01 21:17     ` Jonathan Cameron
  0 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-12-01 21:17 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: linux-iio, Michael.Hennerich

...
>> +int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>> +{
>> +	struct iio_buffer *buffer = indio_dev->buffer;
>> +	const struct iio_chan_spec *ch;
>> +	unsigned bytes = 0;
>> +	int length, i;
>> +	dev_dbg(&indio_dev->dev, "%s\n", __func__);
>> +
>> +	/* How much space will the demuxed element take? */
>> +	for_each_set_bit(i, buffer->scan_mask,
>> +			 indio_dev->masklength) {
>> +		ch = iio_find_channel_from_si(indio_dev, i);
>> +		length = ch->scan_type.storagebits/8;
>> +		if (bytes % length)
>> +			bytes += length - bytes % length;
> 
> bytes = ALIGN(bytes, length); would probably make it more obvious what is
> going on here.
Good idea. Thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/7] staging:iio: add demux optionally to path from device to buffer
  2011-11-28  9:39   ` Lars-Peter Clausen
@ 2011-12-01 21:34     ` Jonathan Cameron
  0 siblings, 0 replies; 12+ messages in thread
From: Jonathan Cameron @ 2011-12-01 21:34 UTC (permalink / raw)
  To: Lars-Peter Clausen; +Cc: linux-iio, Michael.Hennerich, Jonathan Cameron

On 11/28/2011 09:39 AM, Lars-Peter Clausen wrote:
> On 11/27/2011 02:10 PM, Jonathan Cameron wrote:
>> From: Jonathan Cameron <jic23@cam.ac.uk>
>>
>> This gives you only what you ask for which is handy
>> for some devices with weird scan combinations.
>>
>> Routes all data flow through a core utility function.
>> That and this demuxing support will be needed to do
>> demuxing to multiple destinations in kernel.
>>
>> Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk>
>> ---
>>  drivers/staging/iio/buffer.h              |   15 +++
>>  drivers/staging/iio/industrialio-buffer.c |  148 ++++++++++++++++++++++++++++-
>>  2 files changed, 159 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/staging/iio/buffer.h b/drivers/staging/iio/buffer.h
>> index 4b8f619..5282441 100644
>> --- a/drivers/staging/iio/buffer.h
>> +++ b/drivers/staging/iio/buffer.h
>> @@ -95,6 +95,8 @@ struct iio_buffer_setup_ops {
>>   * @access:		[DRIVER] buffer access functions associated with the
>>   *			implementation.
>>   * @flags:		[INTERN] file ops related flags including busy flag.
>> + * @demux_list:		[INTERN] list of operations required to demux the scan.
>> + * @demux_bounce:	[INTERN] buffer for doing gather from incoming scan.
>>   **/
>>  struct iio_buffer {
>>  	struct iio_dev				*indio_dev;
>> @@ -115,6 +117,8 @@ struct iio_buffer {
>>  	bool					stufftoread;
>>  	unsigned long				flags;
>>  	const struct attribute_group *attrs;
>> +	struct list_head			demux_list;
>> +	unsigned char				*demux_bounce;
>>  };
>>  
>>  /**
>> @@ -153,6 +157,17 @@ int iio_scan_mask_set(struct iio_buffer *buffer, int bit);
>>  	container_of(d, struct iio_buffer, dev)
>>  
>>  /**
>> + * iio_push_to_buffer() - push to a registered buffer.
>> + * @buffer:		IIO buffer structure for device
>> + * @scan:		Full scan.
>> + * @timestamp:
>> + */
>> +int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data,
>> +		       s64 timestamp);
>> +
>> +int iio_update_demux(struct iio_dev *indio_dev);
>> +
>> +/**
>>   * iio_buffer_register() - register the buffer with IIO core
>>   * @indio_dev: device with the buffer to be registered
>>   **/
>> diff --git a/drivers/staging/iio/industrialio-buffer.c b/drivers/staging/iio/industrialio-buffer.c
>> index fb14e37..352f9f1 100644
>> --- a/drivers/staging/iio/industrialio-buffer.c
>> +++ b/drivers/staging/iio/industrialio-buffer.c
>> @@ -87,6 +87,7 @@ void iio_chrdev_buffer_release(struct iio_dev *indio_dev)
>>  
>>  void iio_buffer_init(struct iio_buffer *buffer, struct iio_dev *indio_dev)
>>  {
>> +	INIT_LIST_HEAD(&buffer->demux_list);
>>  	buffer->indio_dev = indio_dev;
>>  	init_waitqueue_head(&buffer->pollq);
>>  }
>> @@ -128,10 +129,9 @@ static ssize_t iio_scan_el_show(struct device *dev,
>>  	int ret;
>>  	struct iio_dev *indio_dev = dev_get_drvdata(dev);
>>  
>> -	ret = iio_scan_mask_query(indio_dev->buffer,
>> -				  to_iio_dev_attr(attr)->address);
>> -	if (ret < 0)
>> -		return ret;
>> +	ret = test_bit(to_iio_dev_attr(attr)->address,
>> +		       indio_dev->buffer->scan_mask);
>> +
>>  	return sprintf(buf, "%d\n", ret);
>>  }
>>  
>> @@ -583,6 +583,12 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev)
>>  					    buffer->scan_mask);
>>  	else
>>  		indio_dev->active_scan_mask = buffer->scan_mask;
>> +	iio_update_demux(indio_dev);
>> +
>> +	if (indio_dev->info->update_scan_mode)
>> +		return indio_dev->info
>> +			->update_scan_mode(indio_dev,
>> +					   indio_dev->active_scan_mask);
>>  	return 0;
>>  }
>>  EXPORT_SYMBOL(iio_sw_buffer_preenable);
>> @@ -652,3 +658,137 @@ int iio_scan_mask_query(struct iio_buffer *buffer, int bit)
>>  	return test_bit(bit, mask);
>>  };
>>  EXPORT_SYMBOL_GPL(iio_scan_mask_query);
>> +
>> +/**
>> + * struct iio_demux_table() - table describing demux memcpy ops
>> + * @from:	index to copy from
>> + * @to:	index to copy to
>> + * @length:	how many bytes to copy
>> + * @l:		list head used for management
>> + */
>> +struct iio_demux_table {
>> +	unsigned from;
>> +	unsigned to;
>> +	unsigned length;
>> +	struct list_head l;
>> +};
>> +
>> +static unsigned char *iio_demux(struct iio_buffer *buffer,
>> +				 unsigned char *datain)
>> +{
>> +	struct iio_demux_table *t;
>> +
>> +	if (list_empty(&buffer->demux_list))
>> +		return datain;
>> +	list_for_each_entry(t, &buffer->demux_list, l)
>> +		memcpy(buffer->demux_bounce + t->to,
>> +		       datain + t->from, t->length);
>> +
>> +	return buffer->demux_bounce;
>> +}
>> +
>> +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);
> 
> I wonder if we want to integrate the demuxing into the store_to callbacks of
> the buffer, this would avoid the need for the bounce buffer and reduce the
> number of memcpys. But maybe we can just add it later.
I'd rather do this later than mess too much with the buffers in this
patch.  I think we may want to do it the other way around and have
buffers offer a reserve_space and done_with_space pair of callbacks
where the first saves the room and passes back a pointer.  Then demux
can occur directly into there rather than the bounce buffer.

Still, same effective result!  So not now in my view.
> 
> 	This looks a bit like an open-coded for_each_set_bit
Indeed.  Will clean that up.
> 
>> +		in_ind = find_next_bit(indio_dev->active_scan_mask,
>> +				       indio_dev->masklength,
>> +				       in_ind + 1);
>> +		while (in_ind != out_ind) {
>> +			in_ind = find_next_bit(indio_dev->active_scan_mask,
>> +					       indio_dev->masklength,
>> +					       in_ind + 1);
> 
> same here for_each_set_bit(in_ind, indio->active_scan_mask, out_ind)
close but not quite.  It only counts bits above the previous in_ind
(which is also the previous out_ind).  Need a for_each_set_bit_after
function for this.
> 
>> +			ch = iio_find_channel_from_si(indio_dev, in_ind);
>> +			length = ch->scan_type.storagebits/8;
>> +			/* Make sure we are aligned */
>> +			in_loc += length;
>> +			if (in_loc % length)
>> +				in_loc += length - in_loc % length;
>> +		}
>> +		p = kmalloc(sizeof(*p), GFP_KERNEL);
>> +		if (p == NULL) {
>> +			ret = -ENOMEM;
>> +			goto error_clear_mux_table;
>> +		}
>> +		ch = iio_find_channel_from_si(indio_dev, in_ind);
>> +		length = ch->scan_type.storagebits/8;
>> +		if (out_loc % length)
>> +			out_loc += length - out_loc % length;
>> +		if (in_loc % length)
>> +			in_loc += length - in_loc % length;
>> +		p->from = in_loc;
>> +		p->to = out_loc;
>> +		p->length = length;
>> +		list_add_tail(&p->l, &buffer->demux_list);
>> +		out_loc += length;
>> +		in_loc += length;
>> +		out_ind = find_next_bit(buffer->scan_mask,
>> +					indio_dev->masklength,
>> +					out_ind + 1);
>> +	}
>> +	/* Relies on scan_timestamp being last */
>> +	if (buffer->scan_timestamp) {
>> +		p = kmalloc(sizeof(*p), GFP_KERNEL);
>> +		if (p == NULL) {
>> +			ret = -ENOMEM;
>> +			goto error_clear_mux_table;
>> +		}
>> +		ch = iio_find_channel_from_si(indio_dev,
>> +			buffer->scan_index_timestamp);
>> +		length = ch->scan_type.storagebits/8;
>> +		if (out_loc % length)
>> +			out_loc += length - out_loc % length;
>> +		if (in_loc % length)
>> +			in_loc += length - in_loc % length;
>> +		p->from = in_loc;
>> +		p->to = out_loc;
>> +		p->length = length;
>> +		list_add_tail(&p->l, &buffer->demux_list);
>> +		out_loc += length;
>> +		in_loc += length;
>> +	}
>> +	buffer->demux_bounce = kzalloc(out_loc, GFP_KERNEL);
>> +	if (buffer->demux_bounce == NULL) {
>> +		ret = -ENOMEM;
>> +		goto error_clear_mux_table;
>> +	}
>> +	return 0;
>> +
>> +error_clear_mux_table:
>> +	list_for_each_entry_safe(p, q, &buffer->demux_list, l) {
>> +		list_del(&p->l);
>> +		kfree(p);
>> +	}
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(iio_update_demux);
> 
> --
> 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] 12+ messages in thread

end of thread, other threads:[~2011-12-01 21:34 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-11-27 13:10 [PATCH 0/7] Add scan demux unit and use it in max1363 Jonathan Cameron
2011-11-27 13:10 ` [PATCH 1/7] staging:iio:find iio channel from scan index util function Jonathan Cameron
2011-11-27 13:10 ` [PATCH 2/7] staging:iio:buffer add a cache of the timestamp scan index Jonathan Cameron
2011-11-27 13:10 ` [PATCH 3/7] staging:iio: add hook to allow core to perform scan related config Jonathan Cameron
2011-11-27 13:10 ` [PATCH 4/7] staging:iio: make iio_sw_buffer_preenable much more general Jonathan Cameron
2011-11-28  9:23   ` Lars-Peter Clausen
2011-12-01 21:17     ` Jonathan Cameron
2011-11-27 13:10 ` [PATCH 5/7] staging:iio: add demux optionally to path from device to buffer Jonathan Cameron
2011-11-28  9:39   ` Lars-Peter Clausen
2011-12-01 21:34     ` Jonathan Cameron
2011-11-27 13:10 ` [PATCH 6/7] staging:iio:adc:max1363 use new demuxing support Jonathan Cameron
2011-11-27 13:10 ` [PATCH 7/7] staging:iio:adc:max1363 correctly set channels as big endian 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).