All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alexandru Ardelean <alexandru.ardelean@analog.com>
To: <linux-kernel@vger.kernel.org>, <linux-iio@vger.kernel.org>
Cc: <lars@metafoo.de>, <Michael.Hennerich@analog.com>,
	<jic23@kernel.org>, <nuno.sa@analog.com>,
	<dragos.bogdan@analog.com>,
	Alexandru Ardelean <alexandru.ardelean@analog.com>
Subject: [PATCH v2 06/12] iio: buffer: re-route scan_elements via it's kobj_type
Date: Fri, 22 Jan 2021 17:57:59 +0200	[thread overview]
Message-ID: <20210122155805.83012-7-alexandru.ardelean@analog.com> (raw)
In-Reply-To: <20210122155805.83012-1-alexandru.ardelean@analog.com>

The scan_elements attributes are solely located inside
'industrialio-buffer-sysfs.c'. In order to support more than one buffer per
IIO device, we need to expand scan_elements attributes directly to IIO
buffer object, and not the IIO device.

This also requires that a new 'iio_buffer_attr' type be added which is
mostly a copy of 'iio_dev_attr', but this expands to an IIO buffer object.

The 'iio_dev_attr' type could have been re-used here, but managing 'device'
objects is a bit more tricky (than it looks at first). A 'device' object
needs to be initialized & managed and we only need to the 'kobj' to expand
from the 'bufferX' directory back to an IIO buffer.
kobjects are simpler to manage.

Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
---
 drivers/iio/iio_core.h            |   5 +
 drivers/iio/industrialio-buffer.c | 160 +++++++++++++++++++++++-------
 drivers/iio/industrialio-core.c   |   1 -
 3 files changed, 128 insertions(+), 38 deletions(-)

diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index fced02cadcc3..43d44ec92781 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -31,6 +31,11 @@ void iio_device_ioctl_handler_register(struct iio_dev *indio_dev,
 				       struct iio_ioctl_handler *h);
 void iio_device_ioctl_handler_unregister(struct iio_ioctl_handler *h);
 
+int iio_attr_init(struct attribute *attr,
+		  const char *postfix,
+		  struct iio_chan_spec const *chan,
+		  enum iio_shared_by shared_by);
+
 int __iio_add_chan_devattr(const char *postfix,
 			   struct iio_chan_spec const *chan,
 			   ssize_t (*func)(struct device *dev,
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index 628d78125126..524b897a1877 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -26,6 +26,26 @@
 #include <linux/iio/buffer.h>
 #include <linux/iio/buffer_impl.h>
 
+/**
+ * struct iio_buf_attr - iio buffer specific attribute
+ * @attr:	underlying attribute
+ * @address:	associated register address
+ * @l:		list head for maintaining list of dynamically created attrs
+ * @c:		specification for the underlying channel
+ * @show:	sysfs show hook for this attribute
+ * @store:	sysfs store hook for this attribute
+ */
+struct iio_buf_attr {
+	struct attribute attr;
+	u64 address;
+	struct list_head l;
+	struct iio_chan_spec const *c;
+	ssize_t (*show)(struct iio_buffer *buffer, struct iio_buf_attr *attr,
+			char *buf);
+	ssize_t (*store)(struct iio_buffer *buffer, struct iio_buf_attr *attr,
+			 const char *buf, size_t count);
+};
+
 static const char * const iio_endian_prefix[] = {
 	[IIO_BE] = "be",
 	[IIO_LE] = "le",
@@ -210,18 +230,17 @@ void iio_buffer_init(struct iio_buffer *buffer)
 }
 EXPORT_SYMBOL(iio_buffer_init);
 
-static ssize_t iio_show_scan_index(struct device *dev,
-				   struct device_attribute *attr,
+static ssize_t iio_show_scan_index(struct iio_buffer *buffer,
+				   struct iio_buf_attr *attr,
 				   char *buf)
 {
-	return sprintf(buf, "%u\n", to_iio_dev_attr(attr)->c->scan_index);
+	return sprintf(buf, "%u\n", attr->c->scan_index);
 }
 
-static ssize_t iio_show_fixed_type(struct device *dev,
-				   struct device_attribute *attr,
+static ssize_t iio_show_fixed_type(struct iio_buffer *buffer,
+				   struct iio_buf_attr *this_attr,
 				   char *buf)
 {
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 	u8 type = this_attr->c->scan_type.endianness;
 
 	if (type == IIO_CPU) {
@@ -248,17 +267,14 @@ static ssize_t iio_show_fixed_type(struct device *dev,
 		       this_attr->c->scan_type.shift);
 }
 
-static ssize_t iio_scan_el_show(struct device *dev,
-				struct device_attribute *attr,
+static ssize_t iio_scan_el_show(struct iio_buffer *buffer,
+				struct iio_buf_attr *attr,
 				char *buf)
 {
 	int ret;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
 
 	/* Ensure ret is 0 or 1. */
-	ret = !!test_bit(to_iio_dev_attr(attr)->address,
-		       buffer->scan_mask);
+	ret = !!test_bit(attr->address, buffer->scan_mask);
 
 	return sprintf(buf, "%d\n", ret);
 }
@@ -359,16 +375,14 @@ static int iio_scan_mask_query(struct iio_dev *indio_dev,
 	return !!test_bit(bit, buffer->scan_mask);
 };
 
-static ssize_t iio_scan_el_store(struct device *dev,
-				 struct device_attribute *attr,
+static ssize_t iio_scan_el_store(struct iio_buffer *buffer,
+				 struct iio_buf_attr *this_attr,
 				 const char *buf,
 				 size_t len)
 {
+	struct iio_dev *indio_dev = buffer->indio_dev;
 	int ret;
 	bool state;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
-	struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
 
 	ret = strtobool(buf, &state);
 	if (ret < 0)
@@ -398,24 +412,20 @@ static ssize_t iio_scan_el_store(struct device *dev,
 
 }
 
-static ssize_t iio_scan_el_ts_show(struct device *dev,
-				   struct device_attribute *attr,
+static ssize_t iio_scan_el_ts_show(struct iio_buffer *buffer,
+				   struct iio_buf_attr *attr,
 				   char *buf)
 {
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
-
 	return sprintf(buf, "%d\n", buffer->scan_timestamp);
 }
 
-static ssize_t iio_scan_el_ts_store(struct device *dev,
-				    struct device_attribute *attr,
+static ssize_t iio_scan_el_ts_store(struct iio_buffer *buffer,
+				    struct iio_buf_attr *attr,
 				    const char *buf,
 				    size_t len)
 {
+	struct iio_dev *indio_dev = buffer->indio_dev;
 	int ret;
-	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
-	struct iio_buffer *buffer = indio_dev->buffer;
 	bool state;
 
 	ret = strtobool(buf, &state);
@@ -434,13 +444,88 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
 	return ret ? ret : len;
 }
 
+static int __iio_add_chan_bufattr(const char *postfix,
+				  struct iio_chan_spec const *chan,
+				  ssize_t (*readfunc)(struct iio_buffer *buffer,
+						      struct iio_buf_attr *attr,
+						      char *buf),
+				  ssize_t (*writefunc)(struct iio_buffer *buffer,
+						       struct iio_buf_attr *attr,
+						       const char *buf,
+						       size_t len),
+				  u64 mask,
+				  enum iio_shared_by shared_by,
+				  struct device *dev,
+				  struct list_head *attr_list)
+{
+	struct iio_buf_attr *iio_attr, *t;
+	int ret;
+
+	iio_attr = kzalloc(sizeof(*iio_attr), GFP_KERNEL);
+	if (iio_attr == NULL)
+		return -ENOMEM;
+
+	ret = iio_attr_init(&iio_attr->attr, postfix, chan, shared_by);
+	if (ret)
+		goto error_iio_buf_attr_free;
+
+	iio_attr->c = chan;
+	iio_attr->address = mask;
+	list_for_each_entry(t, attr_list, l) {
+		if (strcmp(t->attr.name, iio_attr->attr.name) == 0) {
+			if (shared_by == IIO_SEPARATE)
+				dev_err(dev, "tried to double register : %s\n",
+					t->attr.name);
+			ret = -EBUSY;
+			goto error_iio_buf_attr_deinit;
+		}
+	}
+	list_add(&iio_attr->l, attr_list);
+
+	if (readfunc) {
+		iio_attr->attr.mode |= S_IRUGO;
+		iio_attr->show = readfunc;
+	}
+
+	if (writefunc) {
+		iio_attr->attr.mode |= S_IWUSR;
+		iio_attr->store = writefunc;
+	}
+
+	return 0;
+
+error_iio_buf_attr_deinit:
+	kfree(iio_attr->attr.name);
+error_iio_buf_attr_free:
+	kfree(iio_attr);
+	return ret;
+}
+
+/**
+ * iio_free_chan_bufattr_list() - Free a list of IIO buffer attributes
+ * @attr_list: List of IIO buffer attributes
+ *
+ * This function frees the memory allocated for each of the IIO buffer
+ * attributes in the list.
+ */
+static void iio_free_chan_bufattr_list(struct list_head *attr_list)
+{
+	struct iio_buf_attr *p, *n;
+
+	list_for_each_entry_safe(p, n, attr_list, l) {
+		list_del(&p->l);
+		kfree(p->attr.name);
+		kfree(p);
+	}
+}
+
 static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
 					struct iio_buffer *buffer,
 					const struct iio_chan_spec *chan)
 {
 	int ret, attrcount = 0;
 
-	ret = __iio_add_chan_devattr("index",
+	ret = __iio_add_chan_bufattr("index",
 				     chan,
 				     &iio_show_scan_index,
 				     NULL,
@@ -451,7 +536,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
 	if (ret)
 		return ret;
 	attrcount++;
-	ret = __iio_add_chan_devattr("type",
+	ret = __iio_add_chan_bufattr("type",
 				     chan,
 				     &iio_show_fixed_type,
 				     NULL,
@@ -463,7 +548,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
 		return ret;
 	attrcount++;
 	if (chan->type != IIO_TIMESTAMP)
-		ret = __iio_add_chan_devattr("en",
+		ret = __iio_add_chan_bufattr("en",
 					     chan,
 					     &iio_scan_el_show,
 					     &iio_scan_el_store,
@@ -472,7 +557,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
 					     &indio_dev->dev,
 					     &buffer->scan_el_dev_attr_list);
 	else
-		ret = __iio_add_chan_devattr("en",
+		ret = __iio_add_chan_bufattr("en",
 					     chan,
 					     &iio_scan_el_ts_show,
 					     &iio_scan_el_ts_store,
@@ -1251,6 +1336,7 @@ static struct attribute *iio_buffer_attrs[] = {
 };
 
 #define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
+#define to_iio_buf_attr(_attr) container_of(_attr, struct iio_buf_attr, attr)
 
 static ssize_t iio_buffer_dir_attr_show(struct kobject *kobj,
 					struct attribute *attr,
@@ -1291,9 +1377,9 @@ static ssize_t iio_scan_el_dir_attr_show(struct kobject *kobj,
 					 char *buf)
 {
 	struct iio_buffer *buffer = container_of(kobj, struct iio_buffer, scan_el_dir);
-	struct device_attribute *dattr = to_dev_attr(attr);
+	struct iio_buf_attr *battr = to_iio_buf_attr(attr);
 
-	return dattr->show(&buffer->indio_dev->dev, dattr, buf);
+	return battr->show(buffer, battr, buf);
 }
 
 static ssize_t iio_scan_el_dir_attr_store(struct kobject *kobj,
@@ -1302,9 +1388,9 @@ static ssize_t iio_scan_el_dir_attr_store(struct kobject *kobj,
 					  size_t len)
 {
 	struct iio_buffer *buffer = container_of(kobj, struct iio_buffer, scan_el_dir);
-	struct device_attribute *dattr = to_dev_attr(attr);
+	struct iio_buf_attr *battr = to_iio_buf_attr(attr);
 
-	return dattr->store(&buffer->indio_dev->dev, dattr, buf, len);
+	return battr->store(buffer, battr, buf, len);
 }
 
 static const struct sysfs_ops iio_scan_el_dir_sysfs_ops = {
@@ -1372,7 +1458,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
 					     struct iio_dev *indio_dev,
 					     unsigned int idx)
 {
-	struct iio_dev_attr *p;
+	struct iio_buf_attr *p;
 	struct attribute **attr;
 	int ret, i, attrn, attrcount;
 	const struct iio_chan_spec *channels;
@@ -1453,7 +1539,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
 
 	attrn = 0;
 	list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
-		buffer->scan_el_attrs[attrn++] = &p->dev_attr.attr;
+		buffer->scan_el_attrs[attrn++] = &p->attr;
 
 	ret = iio_sysfs_add_attrs(&buffer->scan_el_dir, buffer->scan_el_attrs);
 	if (ret)
@@ -1469,7 +1555,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer,
 	bitmap_free(buffer->scan_mask);
 error_cleanup_dynamic:
 	iio_sysfs_del_attrs(&buffer->buffer_dir, buffer->buffer_attrs);
-	iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
+	iio_free_chan_bufattr_list(&buffer->scan_el_dev_attr_list);
 error_buffer_kobject_put:
 	kobject_put(&buffer->buffer_dir);
 error_buffer_free_attrs:
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index b8f7261945f5..088e59042226 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -967,7 +967,6 @@ static ssize_t iio_write_channel_info(struct device *dev,
 	return len;
 }
 
-static
 int iio_attr_init(struct attribute *attr,
 		  const char *postfix,
 		  struct iio_chan_spec const *chan,
-- 
2.17.1


  parent reply	other threads:[~2021-01-22 15:57 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-22 15:57 [PATCH v2 00/12] iio: core,buffer: add support for multiple IIO buffers per IIO device Alexandru Ardelean
2021-01-22 15:57 ` [PATCH v2 01/12] iio: core: register chardev only if needed Alexandru Ardelean
2021-01-22 15:57 ` [PATCH v2 02/12] iio: buffer: add back-ref from iio_buffer to iio_dev Alexandru Ardelean
2021-01-22 15:57 ` [PATCH v2 03/12] iio: buffer: rework buffer & scan_elements dir creation Alexandru Ardelean
2021-01-22 15:57 ` [PATCH v2 04/12] iio: buffer: add index to the first IIO buffer dir and symlink it back Alexandru Ardelean
2021-01-22 15:57 ` [PATCH v2 05/12] iio: core: split __iio_device_attr_init() to init only the attr object Alexandru Ardelean
2021-01-22 15:57 ` Alexandru Ardelean [this message]
2021-01-22 16:12   ` [PATCH v2 06/12] iio: buffer: re-route scan_elements via it's kobj_type Alexandru Ardelean
2021-01-22 15:58 ` [PATCH v2 07/12] iio: buffer: re-route core buffer attributes via it's new kobj_type Alexandru Ardelean
2021-01-22 15:58 ` [PATCH v2 08/12] iio: buffer: add helper to get the IIO device to which a buffer belongs Alexandru Ardelean
2021-01-22 15:58 ` [PATCH v2 09/12] iio: re-route all buffer attributes through new buffer kobj_type Alexandru Ardelean
2021-01-22 15:58 ` [PATCH v2 10/12] iio: core: wrap iio device & buffer into struct for character devices Alexandru Ardelean
2021-01-22 15:58 ` [PATCH v2 11/12] iio: buffer: introduce support for attaching more IIO buffers Alexandru Ardelean
2021-01-22 15:58 ` [PATCH v2 12/12] iio: buffer: add ioctl() to support opening extra buffers for IIO device Alexandru Ardelean

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210122155805.83012-7-alexandru.ardelean@analog.com \
    --to=alexandru.ardelean@analog.com \
    --cc=Michael.Hennerich@analog.com \
    --cc=dragos.bogdan@analog.com \
    --cc=jic23@kernel.org \
    --cc=lars@metafoo.de \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nuno.sa@analog.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.