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.ardel...@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

Reply via email to