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 <alexandru.ardelean@xxxxxxxxxx> --- 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