On Fri, Jan 22, 2021 at 5:57 PM Alexandru Ardelean <alexandru.ardelean@xxxxxxxxxx> wrote: > > 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. Something odd happened here. I'm only seeing half the patches. No idea if the others will show. I'll leave this here for a while, and if they don't show up tomorrow I'll re-send. In the meantime, the set is visible here: https://github.com/analogdevicesinc/linux/commits/iio-multibuffer3 > > Signed-off-by: Alexandru Ardelean <alexandru.ardelean@xxxxxxxxxx> > --- > 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 >