summaryrefslogtreecommitdiffstats
path: root/drivers/staging/iio/industrialio-ring.c
diff options
context:
space:
mode:
authorJonathan Cameron <jic23@cam.ac.uk>2011-05-18 14:40:51 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2011-05-19 16:06:11 -0700
commit1d892719e70e477156f62e060e0805d991d450e5 (patch)
tree8793a50433e13d0df508c2cb91006ee2d28452d8 /drivers/staging/iio/industrialio-ring.c
parent32890b983086136fef8721363a2d3860f337ad53 (diff)
downloadop-kernel-dev-1d892719e70e477156f62e060e0805d991d450e5.zip
op-kernel-dev-1d892719e70e477156f62e060e0805d991d450e5.tar.gz
staging:iio: allow channels to be set up using a table of iio_channel_spec structures.
V8: Add missing address in IIO_CHAN macro. Spotted by Michael Hennerich. V7: Document additions to iio_dev structure. V6: Fixup the docs for iio_chan_spec structure. V5: Actually have the macro handle the _input type channels (oops) V4: Add ability to do, _input and modified channel naming in a coherent fashion. Scrap all the messy IIO_CHAN_* macros and move to only one. V3: Added more types - intensity and light. V2: Various fixes - some thanks to Arnd. Bug fix for unregistering of event attr group Changed iio_read_channel_info to have two part value - use for raw value read as well. constify the channelspec structures raw write support for calibbias and similar Additional strings for buidling attribute names. Signed-off-by: Jonathan Cameron <jic23@cam.ac.uk> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/iio/industrialio-ring.c')
-rw-r--r--drivers/staging/iio/industrialio-ring.c188
1 files changed, 181 insertions, 7 deletions
diff --git a/drivers/staging/iio/industrialio-ring.c b/drivers/staging/iio/industrialio-ring.c
index 3f6bee0..d6b4bb7 100644
--- a/drivers/staging/iio/industrialio-ring.c
+++ b/drivers/staging/iio/industrialio-ring.c
@@ -233,9 +233,162 @@ void iio_ring_buffer_init(struct iio_ring_buffer *ring,
}
EXPORT_SYMBOL(iio_ring_buffer_init);
-int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
+static ssize_t iio_show_scan_index(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ return sprintf(buf, "%u\n", this_attr->c->scan_index);
+}
+
+static ssize_t iio_show_fixed_type(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ return sprintf(buf, "%c%d/%d>>%u\n",
+ this_attr->c->scan_type.sign,
+ this_attr->c->scan_type.realbits,
+ this_attr->c->scan_type.storagebits,
+ this_attr->c->scan_type.shift);
+}
+
+static int __iio_add_chan_scan_elattr(const char *postfix,
+ const char *group,
+ const struct iio_chan_spec *chan,
+ struct device *dev,
+ struct list_head *attr_list)
{
int ret;
+ struct iio_scan_el *scan_el;
+
+ scan_el = kzalloc(sizeof *scan_el, GFP_KERNEL);
+ if (scan_el == NULL) {
+ ret = -ENOMEM;
+ goto error_ret;
+ }
+ if (chan->type != IIO_TIMESTAMP)
+ ret = __iio_device_attr_init(&scan_el->dev_attr, postfix, chan,
+ iio_scan_el_show,
+ iio_scan_el_store, 0);
+ else /*
+ * Timestamp handled separately because it simplifies a lot of
+ * drivers by ensuring they don't have to know its magic index
+ */
+ ret = __iio_device_attr_init(&scan_el->dev_attr, postfix, chan,
+ iio_scan_el_ts_show,
+ iio_scan_el_ts_store, 0);
+ if (ret)
+ goto error_free_scan_el;
+
+ scan_el->number = chan->scan_index;
+
+ ret = sysfs_add_file_to_group(&dev->kobj,
+ &scan_el->dev_attr.attr,
+ group);
+ if (ret < 0)
+ goto error_device_attr_deinit;
+
+ list_add(&scan_el->l, attr_list);
+
+ return 0;
+error_device_attr_deinit:
+ __iio_device_attr_deinit(&scan_el->dev_attr);
+error_free_scan_el:
+ kfree(scan_el);
+error_ret:
+ return ret;
+}
+
+static int iio_ring_add_channel_sysfs(struct iio_ring_buffer *ring,
+ const struct iio_chan_spec *chan)
+{
+ int ret;
+
+ ret = __iio_add_chan_devattr("index", "scan_elements",
+ chan,
+ &iio_show_scan_index,
+ NULL,
+ 0,
+ 0,
+ &ring->dev,
+ &ring->scan_el_dev_attr_list);
+ if (ret)
+ goto error_ret;
+
+ ret = __iio_add_chan_devattr("type", "scan_elements",
+ chan,
+ &iio_show_fixed_type,
+ NULL,
+ 0,
+ 0,
+ &ring->dev,
+ &ring->scan_el_dev_attr_list);
+
+ if (ret)
+ goto error_ret;
+
+ ret = __iio_add_chan_scan_elattr("en", "scan_elements",
+ chan, &ring->dev,
+ &ring->scan_el_en_attr_list);
+
+error_ret:
+ return ret;
+}
+
+static void iio_ring_remove_and_free_scan_el_attr(struct iio_ring_buffer *ring,
+ struct iio_scan_el *p)
+{
+ sysfs_remove_file_from_group(&ring->dev.kobj,
+ &p->dev_attr.attr, "scan_elements");
+ kfree(p->dev_attr.attr.name);
+ kfree(p);
+}
+
+static void iio_ring_remove_and_free_scan_dev_attr(struct iio_ring_buffer *ring,
+ struct iio_dev_attr *p)
+{
+ sysfs_remove_file_from_group(&ring->dev.kobj,
+ &p->dev_attr.attr, "scan_elements");
+ kfree(p->dev_attr.attr.name);
+ kfree(p);
+}
+
+static struct attribute *iio_scan_el_dummy_attrs[] = {
+ NULL
+};
+
+static struct attribute_group iio_scan_el_dummy_group = {
+ .name = "scan_elements",
+ .attrs = iio_scan_el_dummy_attrs
+};
+
+static void __iio_ring_attr_cleanup(struct iio_ring_buffer *ring)
+{
+ struct iio_dev_attr *p, *n;
+ struct iio_scan_el *q, *m;
+ int anydynamic = !(list_empty(&ring->scan_el_dev_attr_list) &&
+ list_empty(&ring->scan_el_en_attr_list));
+ list_for_each_entry_safe(p, n,
+ &ring->scan_el_dev_attr_list, l)
+ iio_ring_remove_and_free_scan_dev_attr(ring, p);
+ list_for_each_entry_safe(q, m,
+ &ring->scan_el_en_attr_list, l)
+ iio_ring_remove_and_free_scan_el_attr(ring, q);
+
+ if (ring->scan_el_attrs)
+ sysfs_remove_group(&ring->dev.kobj,
+ ring->scan_el_attrs);
+ else if (anydynamic)
+ sysfs_remove_group(&ring->dev.kobj,
+ &iio_scan_el_dummy_group);
+}
+
+int iio_ring_buffer_register_ex(struct iio_ring_buffer *ring, int id,
+ const struct iio_chan_spec *channels,
+ int num_channels)
+{
+ int ret, i;
ring->id = id;
@@ -268,9 +421,28 @@ int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
"Failed to add sysfs scan elements\n");
goto error_free_ring_buffer_event_chrdev;
}
+ } else if (channels) {
+ ret = sysfs_create_group(&ring->dev.kobj,
+ &iio_scan_el_dummy_group);
+ if (ret)
+ goto error_free_ring_buffer_event_chrdev;
}
- return ret;
+
+ INIT_LIST_HEAD(&ring->scan_el_dev_attr_list);
+ INIT_LIST_HEAD(&ring->scan_el_en_attr_list);
+ if (channels) {
+ /* new magic */
+ for (i = 0; i < num_channels; i++) {
+ ret = iio_ring_add_channel_sysfs(ring, &channels[i]);
+ if (ret < 0)
+ goto error_cleanup_dynamic;
+ }
+ }
+
+ return 0;
+error_cleanup_dynamic:
+ __iio_ring_attr_cleanup(ring);
error_free_ring_buffer_event_chrdev:
__iio_free_ring_buffer_event_chrdev(ring);
error_remove_device:
@@ -278,14 +450,17 @@ error_remove_device:
error_ret:
return ret;
}
+EXPORT_SYMBOL(iio_ring_buffer_register_ex);
+
+int iio_ring_buffer_register(struct iio_ring_buffer *ring, int id)
+{
+ return iio_ring_buffer_register_ex(ring, id, NULL, 0);
+}
EXPORT_SYMBOL(iio_ring_buffer_register);
void iio_ring_buffer_unregister(struct iio_ring_buffer *ring)
{
- if (ring->scan_el_attrs)
- sysfs_remove_group(&ring->dev.kobj,
- ring->scan_el_attrs);
-
+ __iio_ring_attr_cleanup(ring);
__iio_free_ring_buffer_access_chrdev(ring);
__iio_free_ring_buffer_event_chrdev(ring);
device_del(&ring->dev);
@@ -540,4 +715,3 @@ error_ret:
return ret ? ret : len;
}
EXPORT_SYMBOL(iio_scan_el_ts_store);
-
OpenPOWER on IntegriCloud