WIP

Currently, IIO is broken here.
Each buffer is now an object.
The part where this is broken is backwards compatibility.
We need to:
- convert all external buffer attributes to unpack to IIO buffers and not
  IIO devices
- symlink the 'scan_elements' folder of the (first) IIO buffer device to
  the IIO device
- symlink the chardev of the first IIO buffer device to the IIO device

Signed-off-by: Alexandru Ardelean <[email protected]>
---
 drivers/iio/iio_core.h            | 11 ++--
 drivers/iio/industrialio-buffer.c | 98 ++++++++++++++++++++++++-------
 drivers/iio/industrialio-core.c   | 39 +++++++-----
 include/linux/iio/buffer_impl.h   |  6 ++
 include/linux/iio/iio.h           |  2 +-
 5 files changed, 116 insertions(+), 40 deletions(-)

diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index f68de4af2738..890577766f9b 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -54,10 +54,13 @@ ssize_t iio_format_value(char *buf, unsigned int type, int 
size, int *vals);
 #ifdef CONFIG_IIO_BUFFER
 struct poll_table_struct;
 
+int iio_device_alloc_chrdev_id(struct device *dev);
+void iio_device_free_chrdev_id(struct device *dev);
+
 void iio_device_buffer_attach_chrdev(struct iio_dev *indio_dev);
 
-int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
-void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev);
+int iio_device_buffers_init(struct iio_dev *indio_dev);
+void iio_device_buffers_cleanup(struct iio_dev *indio_dev);
 
 void iio_device_buffers_put(struct iio_dev *indio_dev);
 
@@ -68,12 +71,12 @@ void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
 
 static inline void iio_device_buffer_attach_chrdev(struct iio_dev *indio_dev) 
{}
 
-static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+static inline int iio_device_buffers_init(struct iio_dev *indio_dev)
 {
        return 0;
 }
 
-static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {}
+static inline void iio_device_buffers_cleanup(struct iio_dev *indio_dev) {}
 
 static inline void iio_device_buffers_put(struct iio_dev *indio_dev) {}
 
diff --git a/drivers/iio/industrialio-buffer.c 
b/drivers/iio/industrialio-buffer.c
index efebf74a05af..6c35de7ebd9e 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -1235,8 +1235,6 @@ static ssize_t iio_buffer_store_enable(struct device *dev,
        return (ret < 0) ? ret : len;
 }
 
-static const char * const iio_scan_elements_group_name = "scan_elements";
-
 static ssize_t iio_buffer_show_watermark(struct device *dev,
                                         struct device_attribute *attr,
                                         char *buf)
@@ -1312,7 +1310,7 @@ static struct attribute *iio_buffer_attrs[] = {
        &dev_attr_data_available.attr,
 };
 
-static int __iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer)
+static int iio_buffer_alloc_sysfs_and_mask(struct iio_buffer *buffer)
 {
        struct iio_dev *indio_dev = buffer->indio_dev;
        struct iio_dev_attr *p;
@@ -1344,10 +1342,9 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct 
iio_buffer *buffer)
 
        attr[attrcount + ARRAY_SIZE(iio_buffer_attrs)] = NULL;
 
-       buffer->buffer_group.name = "buffer";
        buffer->buffer_group.attrs = attr;
 
-       indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
+       buffer->groups[0] = &buffer->buffer_group;
 
        attrcount = 0;
        INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
@@ -1373,7 +1370,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct 
iio_buffer *buffer)
                        goto error_cleanup_dynamic;
        }
 
-       buffer->scan_el_group.name = iio_scan_elements_group_name;
+       buffer->scan_el_group.name = "scan_elements";
 
        buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
                                              
sizeof(buffer->scan_el_group.attrs[0]),
@@ -1386,7 +1383,7 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct 
iio_buffer *buffer)
 
        list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
                buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
-       indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
+       buffer->groups[1] = &buffer->scan_el_group;
 
        return 0;
 
@@ -1399,11 +1396,66 @@ static int __iio_buffer_alloc_sysfs_and_mask(struct 
iio_buffer *buffer)
        return ret;
 }
 
-int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+static void iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer)
+{
+       iio_buffer_free_scanmask(buffer);
+       kfree(buffer->buffer_group.attrs);
+       kfree(buffer->scan_el_group.attrs);
+       iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
+}
+
+static int iio_device_buffer_init(struct iio_dev *indio_dev,
+                                 struct iio_buffer *buffer,
+                                 int index)
+{
+       int ret;
+
+       ret = iio_buffer_alloc_sysfs_and_mask(buffer);
+       if (ret)
+               return ret;
+
+       ret = iio_device_alloc_chrdev_id(&buffer->dev);
+       if (ret)
+               goto error_free_sysfs_and_mask;
+
+       buffer->dev.parent = &indio_dev->dev;
+       buffer->dev.groups = buffer->groups;
+       buffer->dev.bus = &iio_bus_type;
+       device_initialize(&buffer->dev);
+
+       dev_set_name(&buffer->dev, "iio:buffer%d:%d",
+                    indio_dev->id, index);
+
+       ret = cdev_device_add(&buffer->chrdev, &buffer->dev);
+       if (ret)
+               goto error_free_chrdev_id;
+
+       return 0;
+
+error_free_chrdev_id:
+       iio_device_free_chrdev_id(&buffer->dev);
+error_free_sysfs_and_mask:
+       iio_buffer_free_sysfs_and_mask(buffer);
+       return ret;
+}
+
+void iio_device_buffer_cleanup(struct iio_buffer *buffer)
+{
+       if (!buffer)
+               return;
+
+       iio_buffer_free_sysfs_and_mask(buffer);
+
+       cdev_device_del(&buffer->chrdev, &buffer->dev);
+
+       iio_device_free_chrdev_id(&buffer->dev);
+}
+
+int iio_device_buffers_init(struct iio_dev *indio_dev)
 {
        struct iio_buffer *buffer = indio_dev->buffer;
        const struct iio_chan_spec *channels;
-       int i;
+       int i, ret;
 
        channels = indio_dev->channels;
        if (channels) {
@@ -1417,25 +1469,29 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev 
*indio_dev)
        if (!buffer)
                return 0;
 
-       return __iio_buffer_alloc_sysfs_and_mask(buffer);
-}
+       ret = iio_device_buffer_init(indio_dev, buffer, 0);
+       if (ret)
+               return ret;
 
-static void __iio_buffer_free_sysfs_and_mask(struct iio_buffer *buffer)
-{
-       iio_buffer_free_scanmask(buffer);
-       kfree(buffer->buffer_group.attrs);
-       kfree(buffer->scan_el_group.attrs);
-       iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
+       ret = sysfs_create_link(&indio_dev->dev.kobj,
+                               &buffer->dev.kobj, "buffer");
+       if (ret)
+               goto error_cleanup_buffers;
+
+       return 0;
+
+error_cleanup_buffers:
+       iio_device_buffer_cleanup(buffer);
+       return 0;
 }
 
-void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
+void iio_device_buffers_cleanup(struct iio_dev *indio_dev)
 {
        struct iio_buffer *buffer = indio_dev->buffer;
 
-       if (!buffer)
-               return;
+       sysfs_remove_link(&indio_dev->dev.kobj, "buffer");
 
-       __iio_buffer_free_sysfs_and_mask(buffer);
+       iio_device_buffer_cleanup(buffer);
 }
 
 static const struct file_operations iio_buffer_fileops = {
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index 5df3af5e7dcb..b27fabf13e9c 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -1638,7 +1638,7 @@ static int iio_check_unique_scan_index(struct iio_dev 
*indio_dev)
        return 0;
 }
 
-static int iio_device_alloc_chrdev_id(struct device *dev)
+int iio_device_alloc_chrdev_id(struct device *dev)
 {
        int id;
 
@@ -1654,7 +1654,7 @@ static int iio_device_alloc_chrdev_id(struct device *dev)
        return 0;
 }
 
-static void iio_device_free_chrdev_id(struct device *dev)
+void iio_device_free_chrdev_id(struct device *dev)
 {
        if (!dev->devt)
                return;
@@ -1684,18 +1684,11 @@ int __iio_device_register(struct iio_dev *indio_dev, 
struct module *this_mod)
 
        iio_device_register_debugfs(indio_dev);
 
-       ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
-       if (ret) {
-               dev_err(indio_dev->dev.parent,
-                       "Failed to create buffer sysfs interfaces\n");
-               goto error_unreg_debugfs;
-       }
-
        ret = iio_device_register_sysfs(indio_dev);
        if (ret) {
                dev_err(indio_dev->dev.parent,
                        "Failed to register sysfs interfaces\n");
-               goto error_buffer_free_sysfs;
+               goto error_unreg_debugfs;
        }
        ret = iio_device_register_eventset(indio_dev);
        if (ret) {
@@ -1712,6 +1705,26 @@ int __iio_device_register(struct iio_dev *indio_dev, 
struct module *this_mod)
 
        iio_device_buffer_attach_chrdev(indio_dev);
 
+       if (indio_dev->chrdev) {
+               ret = device_add(&indio_dev->dev);
+
+               if (ret) {
+                       put_device(&indio_dev->dev);
+                       goto error_unreg_eventset;
+               }
+
+               ret = iio_device_buffers_init(indio_dev);
+               if (ret) {
+                       device_del(&indio_dev->dev);
+
+                       dev_err(indio_dev->dev.parent,
+                               "Failed to create buffer sysfs interfaces\n");
+                       goto error_unreg_eventset;
+               }
+
+               return 0;
+       }
+
        /* No chrdev attached from buffer, we go with event-only chrdev */
        if (!indio_dev->chrdev)
                iio_device_event_attach_chrdev(indio_dev);
@@ -1736,8 +1749,6 @@ int __iio_device_register(struct iio_dev *indio_dev, 
struct module *this_mod)
        iio_device_unregister_eventset(indio_dev);
 error_free_sysfs:
        iio_device_unregister_sysfs(indio_dev);
-error_buffer_free_sysfs:
-       iio_buffer_free_sysfs_and_mask(indio_dev);
 error_unreg_debugfs:
        iio_device_unregister_debugfs(indio_dev);
        return ret;
@@ -1752,6 +1763,8 @@ void iio_device_unregister(struct iio_dev *indio_dev)
 {
        struct iio_ioctl_handler *h, *t;
 
+       iio_device_buffers_cleanup(indio_dev);
+
        cdev_device_del(indio_dev->chrdev, &indio_dev->dev);
        iio_device_free_chrdev_id(&indio_dev->dev);
 
@@ -1770,8 +1783,6 @@ void iio_device_unregister(struct iio_dev *indio_dev)
        iio_buffer_wakeup_poll(indio_dev);
 
        mutex_unlock(&indio_dev->info_exist_lock);
-
-       iio_buffer_free_sysfs_and_mask(indio_dev);
 }
 EXPORT_SYMBOL(iio_device_unregister);
 
diff --git a/include/linux/iio/buffer_impl.h b/include/linux/iio/buffer_impl.h
index 46fc977deae3..eca3fe630230 100644
--- a/include/linux/iio/buffer_impl.h
+++ b/include/linux/iio/buffer_impl.h
@@ -104,6 +104,12 @@ struct iio_buffer {
        unsigned int watermark;
 
        /* private: */
+       /* @dev: underlying device object. */
+       struct device dev;
+
+#define IIO_BUFFER_MAX_GROUP   2
+       const struct attribute_group *groups[IIO_BUFFER_MAX_GROUP + 1];
+
        /* @scan_timestamp: Does the scan mode include a timestamp. */
        bool scan_timestamp;
 
diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
index b6ca8d85629e..671f5818fa67 100644
--- a/include/linux/iio/iio.h
+++ b/include/linux/iio/iio.h
@@ -561,7 +561,7 @@ struct iio_dev {
        struct mutex                    info_exist_lock;
        const struct iio_buffer_setup_ops       *setup_ops;
        struct cdev                     *chrdev;
-#define IIO_MAX_GROUPS 6
+#define IIO_MAX_GROUPS 5
        const struct attribute_group    *groups[IIO_MAX_GROUPS + 1];
        int                             groupcounter;
 
-- 
2.17.1

Reply via email to