lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Fri, 11 Nov 2011 11:40:42 +0100
From:	Michael Hennerich <michael.hennerich@...log.com>
To:	"jic23@....ac.uk" <jic23@....ac.uk>
CC:	"linux-iio@...r.kernel.org" <linux-iio@...r.kernel.org>,
	"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
	"guenter.roeck@...csson.com" <guenter.roeck@...csson.com>,
	"khali@...ux-fr.org" <khali@...ux-fr.org>,
	"dmitry.torokhov@...il.com" <dmitry.torokhov@...il.com>,
	"broonie@...nsource.wolfsonmicro.com" 
	<broonie@...nsource.wolfsonmicro.com>,
	"gregkh@...e.de" <gregkh@...e.de>,
	"alan@...rguk.ukuu.org.uk" <alan@...rguk.ukuu.org.uk>,
	"arnd@...db.de" <arnd@...db.de>,
	"linus.walleij@...aro.org" <linus.walleij@...aro.org>,
	"lars@...afoo.de" <lars@...afoo.de>,
	"maxime.ripard@...e-electrons.com" <maxime.ripard@...e-electrons.com>
Subject: Re: [PATCH 1/6] IIO: Core sysfs only support.

On 11/07/2011 03:52 PM, jic23@....ac.uk wrote:
> From: Jonathan Cameron<jic23@....ac.uk>
>
> Add support for simple sysfs only interfaces.
>
> Bulk of patch is concerned with taking struct iio_chan_spec
> arrays and generating all the relevant interfaces from them.
>
> Signed-off-by: Jonathan Cameron<jic23@....ac.uk>
Since this is a subset of what we already reviewed and tested while in 
staging -
I'm happy to add my ACK.

Acked-by: Michael Hennerich <michael.hennerich@...log.com>

> ---
>   drivers/Kconfig           |    2 +
>   drivers/Makefile          |    3 +
>   drivers/iio/Kconfig       |   11 +
>   drivers/iio/Makefile      |    6 +
>   drivers/iio/iio.c         |  591 +++++++++++++++++++++++++++++++++++++++++++++
>   include/linux/iio/iio.h   |  244 +++++++++++++++++++
>   include/linux/iio/sysfs.h |   68 +++++
>   include/linux/iio/types.h |   52 ++++
>   8 files changed, 977 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/Kconfig b/drivers/Kconfig
> index b5e6f24..7410537 100644
> --- a/drivers/Kconfig
> +++ b/drivers/Kconfig
> @@ -136,4 +136,6 @@ source "drivers/hv/Kconfig"
>
>   source "drivers/devfreq/Kconfig"
>
> +source "drivers/iio/Kconfig"
> +
>   endmenu
> diff --git a/drivers/Makefile b/drivers/Makefile
> index 1b31421..216bba4 100644
> --- a/drivers/Makefile
> +++ b/drivers/Makefile
> @@ -129,6 +129,9 @@ obj-$(CONFIG_IOMMU_SUPPORT) += iommu/
>
>   # Virtualization drivers
>   obj-$(CONFIG_VIRT_DRIVERS)     += virt/
> +
>   obj-$(CONFIG_HYPERV)           += hv/
>
>   obj-$(CONFIG_PM_DEVFREQ)       += devfreq/
> +
> +obj-$(CONFIG_IIO)              += iio/
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> new file mode 100644
> index 0000000..012ebb0
> --- /dev/null
> +++ b/drivers/iio/Kconfig
> @@ -0,0 +1,11 @@
> +#
> +# Industrial I/O subsystem
> +#
> +
> +menuconfig IIO
> +       tristate "Industrial I/O support"
> +       depends on GENERIC_HARDIRQS
> +       help
> +         The Industrial input / output subsystem provides a unified
> +         framework for many different types of embedded sensor.
> +
> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
> new file mode 100644
> index 0000000..733846b
> --- /dev/null
> +++ b/drivers/iio/Makefile
> @@ -0,0 +1,6 @@
> +#
> +# Makefile for the Industrial I/O subsystem
> +#
> +
> +obj-$(CONFIG_IIO) += iio.o
> +industrialio-y := core.o
> diff --git a/drivers/iio/iio.c b/drivers/iio/iio.c
> new file mode 100644
> index 0000000..9a98f5f
> --- /dev/null
> +++ b/drivers/iio/iio.c
> @@ -0,0 +1,591 @@
> +/* The industrial I/O core
> + *
> + * Copyright (c) 2008-2011 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * Based on elements of hwmon and input subsystems.
> + */
> +#include<linux/kernel.h>
> +#include<linux/module.h>
> +#include<linux/slab.h>
> +#include<linux/idr.h>
> +#include<linux/iio/iio.h>
> +#include<linux/iio/sysfs.h>
> +
> +static DEFINE_IDA(iio_ida);
> +
> +static struct bus_type iio_bus_type = {
> +       .name = "iio",
> +};
> +
> +static const char * const iio_data_type_name[] = {
> +       [IIO_RAW] = "raw",
> +       [IIO_PROCESSED] = "input",
> +};
> +
> +static const char * const iio_chan_type_name_spec[] = {
> +       [IIO_VOLTAGE] = "voltage",
> +       [IIO_CURRENT] = "current",
> +       [IIO_POWER] = "power",
> +       [IIO_ACCEL] = "accel",
> +       [IIO_ANGL_VEL] = "anglvel",
> +       [IIO_MAGN] = "magn",
> +       [IIO_LIGHT] = "illuminance",
> +       [IIO_INTENSITY] = "intensity",
> +       [IIO_PROXIMITY] = "proximity",
> +       [IIO_TEMP] = "temp",
> +       [IIO_INCLI] = "incli",
> +       [IIO_ROT] = "rot",
> +       [IIO_ANGL] = "angl",
> +       [IIO_TIMESTAMP] = "timestamp",
> +};
> +
> +static const char * const iio_direction_name[] = {
> +       [IIO_IN] = "in",
> +       [IIO_OUT] = "out",
> +};
> +
> +static const char * const iio_modifier_names[] = {
> +       [IIO_MOD_X] = "x",
> +       [IIO_MOD_Y] = "y",
> +       [IIO_MOD_Z] = "z",
> +       [IIO_MOD_LIGHT_BOTH] = "both",
> +       [IIO_MOD_LIGHT_INFRARED] = "ir",
> +};
> +
> +static const char * const iio_chan_info_postfix[] = {
> +       [IIO_CHAN_INFO_SCALE] = "scale",
> +       [IIO_CHAN_INFO_OFFSET] = "offset",
> +       [IIO_CHAN_INFO_CALIBSCALE] = "calibscale",
> +       [IIO_CHAN_INFO_CALIBBIAS] = "calibbias",
> +       [IIO_CHAN_INFO_PEAK] = "peak_raw",
> +       [IIO_CHAN_INFO_PEAK_SCALE] = "peak_scale",
> +       [IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW] = "quadrature_correction_raw",
> +};
> +
> +static void iio_device_free_read_attr(struct iio_dev *indio_dev,
> +                                                struct iio_dev_attr *p)
> +{
> +       kfree(p->dev_attr.attr.name);
> +       kfree(p);
> +}
> +
> +static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
> +{
> +
> +       struct iio_dev_attr *p, *n;
> +
> +       list_for_each_entry_safe(p, n,&indio_dev->channel_attr_list, l) {
> +               list_del(&p->l);
> +               iio_device_free_read_attr(indio_dev, p);
> +       }
> +       kfree(indio_dev->chan_attr_group.attrs);
> +}
> +
> +static void iio_dev_release(struct device *device)
> +{
> +       struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);
> +       iio_device_unregister_sysfs(indio_dev);
> +}
> +
> +static struct device_type iio_dev_type = {
> +       .name = "iio_device",
> +       .release = iio_dev_release,
> +};
> +
> +struct iio_dev *iio_device_allocate(int sizeof_priv)
> +{
> +       struct iio_dev *dev;
> +       size_t alloc_size;
> +
> +       alloc_size = sizeof(struct iio_dev);
> +       if (sizeof_priv) {
> +               alloc_size = ALIGN(alloc_size, IIO_ALIGN);
> +               alloc_size += sizeof_priv;
> +       }
> +       /* ensure cacheline alignment of whole construct */
> +       alloc_size += IIO_ALIGN - 1;
> +
> +       dev = kzalloc(alloc_size, GFP_KERNEL);
> +
> +       if (dev) {
> +               dev->dev.groups = dev->groups;
> +               dev->dev.type =&iio_dev_type;
> +               dev->dev.bus =&iio_bus_type;
> +               device_initialize(&dev->dev);
> +               dev_set_drvdata(&dev->dev, (void *)dev);
> +               mutex_init(&dev->mlock);
> +       }
> +
> +       return dev;
> +}
> +EXPORT_SYMBOL_GPL(iio_device_allocate);
> +
> +void iio_device_free(struct iio_dev *dev)
> +{
> +       if (dev)
> +               iio_put_device(dev);
> +}
> +EXPORT_SYMBOL_GPL(iio_device_free);
> +
> +ssize_t __iio_read_const_attr(struct device *dev,
> +                           struct device_attribute *attr,
> +                           char *buf)
> +{
> +       return sprintf(buf, "%s\n",
> +                      container_of(attr,
> +                                   struct iio_const_attr,
> +                                   dev_attr)->string);
> +}
> +EXPORT_SYMBOL_GPL(__iio_read_const_attr);
> +
> +static ssize_t iio_read_channel_info(struct device *dev,
> +                                    struct device_attribute *attr,
> +                                    char *buf)
> +{
> +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
> +       int val, val2;
> +       int ret = indio_dev->info->read_raw(indio_dev, this_attr->c,
> +&val,&val2, this_attr->address);
> +
> +       if (ret<  0)
> +               return ret;
> +
> +       if (ret == IIO_VAL_INT)
> +               return sprintf(buf, "%d\n", val);
> +       else if (ret == IIO_VAL_INT_PLUS_MICRO) {
> +               if (val2<  0)
> +                       return sprintf(buf, "-%d.%06u\n", val, -val2);
> +               else
> +                       return sprintf(buf, "%d.%06u\n", val, val2);
> +       } else if (ret == IIO_VAL_INT_PLUS_NANO) {
> +               if (val2<  0)
> +                       return sprintf(buf, "-%d.%09u\n", val, -val2);
> +               else
> +                       return sprintf(buf, "%d.%09u\n", val, val2);
> +       } else
> +               return 0;
> +}
> +
> +static ssize_t iio_write_channel_info(struct device *dev,
> +                                     struct device_attribute *attr,
> +                                     const char *buf,
> +                                     size_t len)
> +{
> +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +       struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
> +       int ret, integer = 0, fract = 0, fract_mult = 100000;
> +       bool integer_part = true, negative = false;
> +
> +       /* Assumes decimal - precision based on number of digits */
> +       if (!indio_dev->info->write_raw)
> +               return -EINVAL;
> +
> +       if (indio_dev->info->write_raw_get_fmt)
> +               switch (indio_dev->info->write_raw_get_fmt(indio_dev,
> +                       this_attr->c, this_attr->address)) {
> +               case IIO_VAL_INT_PLUS_MICRO:
> +                       fract_mult = 100000;
> +                       break;
> +               case IIO_VAL_INT_PLUS_NANO:
> +                       fract_mult = 100000000;
> +                       break;
> +               default:
> +                       return -EINVAL;
> +               }
> +
> +       if (buf[0] == '-') {
> +               negative = true;
> +               buf++;
> +       }
> +
> +       while (*buf) {
> +               if ('0'<= *buf&&  *buf<= '9') {
> +                       if (integer_part)
> +                               integer = integer*10 + *buf - '0';
> +                       else {
> +                               fract += fract_mult*(*buf - '0');
> +                               if (fract_mult == 1)
> +                                       break;
> +                               fract_mult /= 10;
> +                       }
> +               } else if (*buf == '\n') {
> +                       if (*(buf + 1) == '\0')
> +                               break;
> +                       else
> +                               return -EINVAL;
> +               } else if (*buf == '.') {
> +                       integer_part = false;
> +               } else {
> +                       return -EINVAL;
> +               }
> +               buf++;
> +       }
> +       if (negative) {
> +               if (integer)
> +                       integer = -integer;
> +               else
> +                       fract = -fract;
> +       }
> +
> +       ret = indio_dev->info->write_raw(indio_dev, this_attr->c,
> +                                        integer, fract, this_attr->address);
> +       if (ret)
> +               return ret;
> +
> +       return len;
> +}
> +
> +static
> +int __iio_device_attr_init(struct device_attribute *dev_attr,
> +                          const char *postfix,
> +                          struct iio_chan_spec const *chan,
> +                          ssize_t (*readfunc)(struct device *dev,
> +                                              struct device_attribute *attr,
> +                                              char *buf),
> +                          ssize_t (*writefunc)(struct device *dev,
> +                                               struct device_attribute *attr,
> +                                               const char *buf,
> +                                               size_t len),
> +                          bool generic)
> +{
> +       int ret;
> +       char *name_format, *full_postfix;
> +       sysfs_attr_init(&dev_attr->attr);
> +
> +       /* Build up postfix of<extend_name>_<modifier>_postfix */
> +       if (chan->modified&&  !generic) {
> +               if (chan->extend_name)
> +                       full_postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
> +                                                iio_modifier_names[chan
> +                                                                   ->channel2],
> +                                                chan->extend_name,
> +                                                postfix);
> +               else
> +                       full_postfix = kasprintf(GFP_KERNEL, "%s_%s",
> +                                                iio_modifier_names[chan
> +                                                                   ->channel2],
> +                                                postfix);
> +       } else {
> +               if (chan->extend_name == NULL)
> +                       full_postfix = kstrdup(postfix, GFP_KERNEL);
> +               else
> +                       full_postfix = kasprintf(GFP_KERNEL,
> +                                                "%s_%s",
> +                                                chan->extend_name,
> +                                                postfix);
> +       }
> +       if (full_postfix == NULL) {
> +               ret = -ENOMEM;
> +               goto error_ret;
> +       }
> +
> +       if (chan->differential) { /* Differential  can not have modifier */
> +               if (generic)
> +                       name_format
> +                               = kasprintf(GFP_KERNEL, "%s_%s-%s_%s",
> +                                           iio_direction_name[chan->output],
> +                                           iio_chan_type_name_spec[chan->type],
> +                                           iio_chan_type_name_spec[chan->type],
> +                                           full_postfix);
> +               else if (chan->indexed)
> +                       name_format
> +                               = kasprintf(GFP_KERNEL, "%s_%s%d-%s%d_%s",
> +                                           iio_direction_name[chan->output],
> +                                           iio_chan_type_name_spec[chan->type],
> +                                           chan->channel,
> +                                           iio_chan_type_name_spec[chan->type],
> +                                           chan->channel2,
> +                                           full_postfix);
> +               else {
> +                       WARN_ON("Differential channels must be indexed\n");
> +                       ret = -EINVAL;
> +                       goto error_free_full_postfix;
> +               }
> +       } else { /* Single ended */
> +               if (generic)
> +                       name_format
> +                               = kasprintf(GFP_KERNEL, "%s_%s_%s",
> +                                           iio_direction_name[chan->output],
> +                                           iio_chan_type_name_spec[chan->type],
> +                                           full_postfix);
> +               else if (chan->indexed)
> +                       name_format
> +                               = kasprintf(GFP_KERNEL, "%s_%s%d_%s",
> +                                           iio_direction_name[chan->output],
> +                                           iio_chan_type_name_spec[chan->type],
> +                                           chan->channel,
> +                                           full_postfix);
> +               else
> +                       name_format
> +                               = kasprintf(GFP_KERNEL, "%s_%s_%s",
> +                                           iio_direction_name[chan->output],
> +                                           iio_chan_type_name_spec[chan->type],
> +                                           full_postfix);
> +       }
> +       if (name_format == NULL) {
> +               ret = -ENOMEM;
> +               goto error_free_full_postfix;
> +       }
> +       dev_attr->attr.name = kasprintf(GFP_KERNEL,
> +                                       name_format,
> +                                       chan->channel,
> +                                       chan->channel2);
> +       if (dev_attr->attr.name == NULL) {
> +               ret = -ENOMEM;
> +               goto error_free_name_format;
> +       }
> +
> +       if (readfunc) {
> +               dev_attr->attr.mode |= S_IRUGO;
> +               dev_attr->show = readfunc;
> +       }
> +
> +       if (writefunc) {
> +               dev_attr->attr.mode |= S_IWUSR;
> +               dev_attr->store = writefunc;
> +       }
> +       kfree(name_format);
> +       kfree(full_postfix);
> +
> +       return 0;
> +
> +error_free_name_format:
> +       kfree(name_format);
> +error_free_full_postfix:
> +       kfree(full_postfix);
> +error_ret:
> +       return ret;
> +}
> +
> +static void __iio_device_attr_deinit(struct device_attribute *dev_attr)
> +{
> +       kfree(dev_attr->attr.name);
> +}
> +
> +static
> +int __iio_add_chan_devattr(const char *postfix,
> +                          struct iio_chan_spec const *chan,
> +                          ssize_t (*readfunc)(struct device *dev,
> +                                              struct device_attribute *attr,
> +                                              char *buf),
> +                          ssize_t (*writefunc)(struct device *dev,
> +                                               struct device_attribute *attr,
> +                                               const char *buf,
> +                                               size_t len),
> +                          u64 mask,
> +                          bool generic,
> +                          struct device *dev,
> +                          struct list_head *attr_list)
> +{
> +       int ret;
> +       struct iio_dev_attr *iio_attr, *t;
> +
> +       iio_attr = kzalloc(sizeof *iio_attr, GFP_KERNEL);
> +       if (iio_attr == NULL) {
> +               ret = -ENOMEM;
> +               goto error_ret;
> +       }
> +       ret = __iio_device_attr_init(&iio_attr->dev_attr,
> +                                    postfix, chan,
> +                                    readfunc, writefunc, generic);
> +       if (ret)
> +               goto error_iio_dev_attr_free;
> +       iio_attr->c = chan;
> +       iio_attr->address = mask;
> +       list_for_each_entry(t, attr_list, l)
> +               if (strcmp(t->dev_attr.attr.name,
> +                          iio_attr->dev_attr.attr.name) == 0) {
> +                       if (!generic)
> +                               dev_err(dev, "tried to double register : %s\n",
> +                                       t->dev_attr.attr.name);
> +                       ret = -EBUSY;
> +                       goto error_device_attr_deinit;
> +               }
> +
> +       list_add(&iio_attr->l, attr_list);
> +
> +       return 0;
> +
> +error_device_attr_deinit:
> +       __iio_device_attr_deinit(&iio_attr->dev_attr);
> +error_iio_dev_attr_free:
> +       kfree(iio_attr);
> +error_ret:
> +       return ret;
> +}
> +
> +static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
> +                                       struct iio_chan_spec const *chan)
> +{
> +       int ret, i, attrcount = 0;
> +
> +       if (chan->channel<  0)
> +               return 0;
> +       ret = __iio_add_chan_devattr(iio_data_type_name[chan->processed_val],
> +                                    chan,
> +&iio_read_channel_info,
> +                                    (chan->output ?
> +&iio_write_channel_info : NULL),
> +                                    0,
> +                                    0,
> +&indio_dev->dev,
> +&indio_dev->channel_attr_list);
> +       if (ret)
> +               goto error_ret;
> +       attrcount++;
> +
> +       for_each_set_bit(i,&chan->info_mask,
> +                        ARRAY_SIZE(iio_chan_info_postfix)*2) {
> +               ret = __iio_add_chan_devattr(iio_chan_info_postfix[i/2],
> +                                            chan,
> +&iio_read_channel_info,
> +&iio_write_channel_info,
> +                                            i/2,
> +                                            !(i%2),
> +&indio_dev->dev,
> +&indio_dev->channel_attr_list);
> +               if (ret == -EBUSY&&  (i%2 == 0)) {
> +                       ret = 0;
> +                       continue;
> +               }
> +               if (ret<  0)
> +                       goto error_ret;
> +               attrcount++;
> +       }
> +       ret = attrcount;
> +error_ret:
> +       return ret;
> +}
> +
> +static ssize_t iio_show_dev_name(struct device *dev,
> +                                struct device_attribute *attr,
> +                                char *buf)
> +{
> +       struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +       return sprintf(buf, "%s\n", indio_dev->name);
> +}
> +
> +static DEVICE_ATTR(name, S_IRUGO, iio_show_dev_name, NULL);
> +
> +static int iio_device_register_sysfs(struct iio_dev *indio_dev)
> +{
> +       int i, ret = 0, attrcount, attrn, attrcount_orig = 0;
> +       struct iio_dev_attr *p, *n;
> +       struct attribute **attr;
> +
> +       /* First count elements in any existing group */
> +       if (indio_dev->info->attrs) {
> +               attr = indio_dev->info->attrs->attrs;
> +               while (*attr++ != NULL)
> +                       attrcount_orig++;
> +       }
> +       attrcount = attrcount_orig;
> +
> +       INIT_LIST_HEAD(&indio_dev->channel_attr_list);
> +       if (indio_dev->channels)
> +               for (i = 0; i<  indio_dev->num_channels; i++) {
> +                       ret = iio_device_add_channel_sysfs(indio_dev,
> +&indio_dev
> +                                                          ->channels[i]);
> +                       if (ret<  0)
> +                               goto error_clear_attrs;
> +                       attrcount += ret;
> +               }
> +       if (indio_dev->name)
> +               attrcount++;
> +
> +       indio_dev->chan_attr_group.attrs
> +               = kzalloc(sizeof(indio_dev->chan_attr_group.attrs[0])*
> +                         (attrcount + 1),
> +                         GFP_KERNEL);
> +       if (indio_dev->chan_attr_group.attrs == NULL) {
> +               ret = -ENOMEM;
> +               goto error_clear_attrs;
> +       }
> +       /* Copy across original attributes */
> +       if (indio_dev->info->attrs)
> +               memcpy(indio_dev->chan_attr_group.attrs,
> +                      indio_dev->info->attrs->attrs,
> +                      sizeof(indio_dev->chan_attr_group.attrs[0])
> +                      *attrcount_orig);
> +       attrn = attrcount_orig;
> +       /* Add all elements from the list. */
> +       list_for_each_entry(p,&indio_dev->channel_attr_list, l)
> +               indio_dev->chan_attr_group.attrs[attrn++] =&p->dev_attr.attr;
> +       if (indio_dev->name)
> +               indio_dev->chan_attr_group.attrs[attrn++] =&dev_attr_name.attr;
> +
> +       indio_dev->groups[indio_dev->groupcounter++] =
> +&indio_dev->chan_attr_group;
> +
> +       return 0;
> +
> +error_clear_attrs:
> +       list_for_each_entry_safe(p, n,
> +&indio_dev->channel_attr_list, l) {
> +               list_del(&p->l);
> +               iio_device_free_read_attr(indio_dev, p);
> +       }
> +
> +       return ret;
> +}
> +
> +int iio_device_register(struct iio_dev *indio_dev)
> +{
> +       int ret;
> +
> +       indio_dev->id = ida_simple_get(&iio_ida, 0, 0, GFP_KERNEL);
> +       if (indio_dev->id<  0) {
> +               ret = indio_dev->id;
> +               goto error_ret;
> +       }
> +
> +       dev_set_name(&indio_dev->dev, "iio:device%d", indio_dev->id);
> +
> +       ret = iio_device_register_sysfs(indio_dev);
> +       if (ret) {
> +               dev_err(indio_dev->dev.parent,
> +                       "Failed to register sysfs interfaces\n");
> +               goto error_free_ida;
> +       }
> +       ret = device_add(&indio_dev->dev);
> +       if (ret)
> +               goto error_free_sysfs;
> +
> +       return 0;
> +
> +error_free_sysfs:
> +       iio_device_unregister_sysfs(indio_dev);
> +error_free_ida:
> +       ida_simple_remove(&iio_ida, indio_dev->id);
> +error_ret:
> +       return ret;
> +}
> +EXPORT_SYMBOL(iio_device_register);
> +
> +void iio_device_unregister(struct iio_dev *indio_dev)
> +{
> +       device_unregister(&indio_dev->dev);
> +}
> +EXPORT_SYMBOL(iio_device_unregister);
> +
> +static int __init iio_init(void)
> +{
> +       return bus_register(&iio_bus_type);
> +}
> +subsys_initcall(iio_init);
> +
> +static void __exit iio_exit(void)
> +{
> +       bus_unregister(&iio_bus_type);
> +}
> +module_exit(iio_exit);
> +
> +MODULE_AUTHOR("Jonathan Cameron<jic23@....ac.uk>");
> +MODULE_DESCRIPTION("Industrial I/O core");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> new file mode 100644
> index 0000000..4367d82
> --- /dev/null
> +++ b/include/linux/iio/iio.h
> @@ -0,0 +1,244 @@
> +/*
> + * The industrial I/O core
> + *
> + * Copyright (c) 2008-2011 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + */
> +#ifndef _IIO_H_
> +#define _IIO_H_
> +
> +#include<linux/klist.h>
> +#include<linux/device.h>
> +#include<linux/iio/types.h>
> +
> +/* Minimum alignment of priv within iio_dev */
> +#define IIO_ALIGN L1_CACHE_BYTES
> +
> +enum iio_data_type {
> +       IIO_RAW,
> +       IIO_PROCESSED,
> +};
> +
> +enum iio_chan_info_enum {
> +       IIO_CHAN_INFO_SCALE = 1,
> +       IIO_CHAN_INFO_OFFSET,
> +       IIO_CHAN_INFO_CALIBSCALE,
> +       IIO_CHAN_INFO_CALIBBIAS,
> +       IIO_CHAN_INFO_PEAK,
> +       IIO_CHAN_INFO_PEAK_SCALE,
> +       IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW,
> +};
> +
> +#define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2)
> +#define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1)
> +
> +#define IIO_CHAN_INFO_SCALE_SEPARATE_BIT               \
> +       IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_SCALE)
> +#define IIO_CHAN_INFO_SCALE_SHARED_BIT                 \
> +       IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_SCALE)
> +#define IIO_CHAN_INFO_OFFSET_SEPARATE_BIT                      \
> +       IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_OFFSET)
> +#define IIO_CHAN_INFO_OFFSET_SHARED_BIT                        \
> +       IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_OFFSET)
> +#define IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT                  \
> +       IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBSCALE)
> +#define IIO_CHAN_INFO_CALIBSCALE_SHARED_BIT                    \
> +       IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBSCALE)
> +#define IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT                   \
> +       IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_CALIBBIAS)
> +#define IIO_CHAN_INFO_CALIBBIAS_SHARED_BIT                     \
> +       IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_CALIBBIAS)
> +#define IIO_CHAN_INFO_PEAK_SEPARATE_BIT                        \
> +       IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAK)
> +#define IIO_CHAN_INFO_PEAK_SHARED_BIT                  \
> +       IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAK)
> +#define IIO_CHAN_INFO_PEAKSCALE_SEPARATE_BIT                   \
> +       IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_PEAKSCALE)
> +#define IIO_CHAN_INFO_PEAKSCALE_SHARED_BIT                     \
> +       IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_PEAKSCALE)
> +#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SEPARATE_BIT   \
> +       IIO_CHAN_INFO_SEPARATE_BIT(                             \
> +               IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
> +#define IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW_SHARED_BIT     \
> +       IIO_CHAN_INFO_SHARED_BIT(                               \
> +               IIO_CHAN_INFO_QUADRATURE_CORRECTION_RAW)
> +#define IIO_CHAN_INFO_AVERAGE_RAW_SEPARATE_BIT                 \
> +       IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
> +#define IIO_CHAN_INFO_AVERAGE_RAW_SHARED_BIT                   \
> +       IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_AVERAGE_RAW)
> +
> +
> +enum iio_direction {
> +       IIO_IN,
> +       IIO_OUT,
> +};
> +
> +/**
> + * struct iio_chan_spec - specification of a single channel
> + * @type:              What type of measurement is the channel making.
> + * @channel:           What number or name do we wish to asign the channel.
> + * @channel2:          If there is a second number for a differential
> + *                     channel then this is it. If modified is set then the
> + *                     value here specifies the modifier.
> + * @address:           Driver specific identifier.
> + * @scan_type:         Description of data format.
> + * @info_mask:         What information is to be exported about this channel.
> + *                     This includes calibbias, scale etc.
> + * @extend_name:       Allows labeling of channel attributes with an
> + *                     informative name. Note this has no effect codes etc,
> + *                     unlike modifiers.
> + * @processed_val:     Flag to specify the data access attribute should be
> + *                     *_input rather than *_raw.
> + * @modified:          Does a modifier apply to this channel. What these are
> + *                     depends on the channel type.  Modifier is set in
> + *                     channel2. Examples are IIO_MOD_X for axial sensors about
> + *                     the 'x' axis.
> + * @indexed:           Specify the channel has a numerical index. If not,
> + *                     the value in channel will be suppressed for attribute
> + *                     but not for event codes. Typically set it to 0 when
> + *                     the index is false.
> + * @output:            Specify the channel is an output channel (DAC).
> + * @differential:      Is the channel a differential channel. Cannot coexist
> + *                     with modified and requires indexed.
> + */
> +struct iio_chan_spec {
> +       enum iio_chan_type      type;
> +       int                     channel;
> +       int                     channel2;
> +       unsigned long           address;
> +       /**
> +        * struct scan_type - description of the data format
> +        * @sign:       Set if signed value
> +        * @realbits:   Number of valid bits of data
> +        * @shift:      Shift right by this before masking out realbits.
> +        */
> +       struct {
> +               char            sign;
> +               u8              realbits;
> +               u8              shift;
> +       } scan_type;
> +       long                    info_mask;
> +       char                    *extend_name;
> +       unsigned                processed_val:1;
> +       unsigned                modified:1;
> +       unsigned                indexed:1;
> +       unsigned                output:1;
> +       unsigned                differential:1;
> +};
> +
> +struct iio_dev;
> +
> +/**
> + * struct iio_info - constant information about device
> + * @driver_module:     module structure used to ensure correct
> + *                     ownership of chrdevs etc
> + * @attrs:             general purpose device attributes
> + * @read_raw:          function to request a value from the device.
> + *                     mask specifies which value. Note 0 means a reading of
> + *                     the channel in question.  Return value will specify the
> + *                     type of value returned by the device. val and val2 will
> + *                     contain the elements making up the returned value.
> + * @write_raw:         function to write a value to the device.
> + *                     Parameters are the same as for read_raw.
> + * @write_raw_get_fmt: callback function to query the expected
> + *                     format/precision. If not set by the driver, write_raw
> + *                     returns IIO_VAL_INT_PLUS_MICRO.
> + **/
> +struct iio_info {
> +       struct module                   *driver_module;
> +       const struct attribute_group    *attrs;
> +
> +       int (*read_raw)(struct iio_dev *indio_dev,
> +                       struct iio_chan_spec const *chan,
> +                       int *val,
> +                       int *val2,
> +                       long mask);
> +
> +       int (*write_raw)(struct iio_dev *indio_dev,
> +                        struct iio_chan_spec const *chan,
> +                        int val,
> +                        int val2,
> +                        long mask);
> +
> +       int (*write_raw_get_fmt)(struct iio_dev *indio_dev,
> +                        struct iio_chan_spec const *chan,
> +                        long mask);
> +};
> +
> +/**
> + * struct iio_dev - industrial I/O device
> + * @id:                        [INTERN] used to identify device internally
> + * @dev:               [DRIVER] device structure, should be assigned a parent
> + *                     and owner
> + * @mlock:             [INTERN] lock used to prevent simultaneous device state
> + *                     changes
> + * @available_scan_masks: [DRIVER] optional array of allowed bitmasks
> + * @channels:          [DRIVER] channel specification structure table
> + * @num_channels:      [DRIVER] number of chanels specified in @channels
> + * @channel_attr_list: [INTERN] keep track of automatically created channel
> + *                     attributes
> + * @chan_attr_group:   [INTERN] group for all attrs in base directory
> + * @name:              [DRIVER] name of the device
> + * @info:              [DRIVER] callbacks and constant info from driver
> + * @groups:            [INTERN] attribute groups
> + * @groupcounter:      [INTERN] index of next attribute group
> + **/
> +struct iio_dev {
> +       int                             id;
> +       struct device                   dev;
> +       struct mutex                    mlock;
> +       unsigned long                   *available_scan_masks;
> +       struct iio_chan_spec const      *channels;
> +       int                             num_channels;
> +       struct list_head                channel_attr_list;
> +       struct attribute_group          chan_attr_group;
> +       const char                      *name;
> +       const struct iio_info           *info;
> +#define IIO_MAX_GROUPS 1
> +       const struct attribute_group    *groups[IIO_MAX_GROUPS + 1];
> +       int                             groupcounter;
> +};
> +
> +/**
> + * iio_device_allocate() - allocate an iio_dev from a driver
> + * @sizeof_priv:       Space to allocate for private structure.
> + **/
> +struct iio_dev *iio_device_allocate(int sizeof_priv);
> +
> +static inline void *iio_priv(const struct iio_dev *dev)
> +{
> +       return (char *)dev + ALIGN(sizeof(struct iio_dev), IIO_ALIGN);
> +}
> +
> +/**
> + * iio_device_free() - free an iio_dev from a driver
> + * @dev: the iio_dev associated with the device
> + **/
> +void iio_device_free(struct iio_dev *dev);
> +
> +/**
> + * iio_device_register() - register a device with the IIO subsystem
> + * @indio_dev:         Device structure filled by the device driver
> + **/
> +int iio_device_register(struct iio_dev *indio_dev);
> +
> +/**
> + * iio_device_unregister() - unregister a device from the IIO subsystem
> + * @indio_dev:         Device structure representing the device.
> + **/
> +void iio_device_unregister(struct iio_dev *indio_dev);
> +
> +/**
> + * iio_put_device() - reference counted deallocation of struct device
> + * @indio_dev: the iio_device containing the device
> + **/
> +static inline void iio_put_device(struct iio_dev *indio_dev)
> +{
> +       if (indio_dev)
> +               put_device(&indio_dev->dev);
> +};
> +
> +#endif /* _IIO_H_ */
> diff --git a/include/linux/iio/sysfs.h b/include/linux/iio/sysfs.h
> new file mode 100644
> index 0000000..c6735bf
> --- /dev/null
> +++ b/include/linux/iio/sysfs.h
> @@ -0,0 +1,68 @@
> +/*
> + * The industrial I/O core
> + *
> + * Copyright (c) 2008 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + *
> + * General attributes
> + */
> +
> +#include<linux/klist.h>
> +#include<linux/device.h>
> +
> +#ifndef _IIO_SYSFS_H_
> +#define _IIO_SYSFS_H_
> +
> +struct iio_chan_spec;
> +
> +/**
> + * struct iio_dev_attr - iio specific device attribute
> + * @dev_attr:  underlying device attribute
> + * @address:   associated register address
> + * @l:         list head for maintaining list of dynamically created attrs
> + * @c:         channel spec for channel with which attr is associated if any
> + */
> +struct iio_dev_attr {
> +       struct device_attribute dev_attr;
> +       int address;
> +       struct list_head l;
> +       struct iio_chan_spec const *c;
> +};
> +
> +#define to_iio_dev_attr(_dev_attr)                             \
> +       container_of(_dev_attr, struct iio_dev_attr, dev_attr)
> +
> +#define IIO_ATTR(_name, _mode, _show, _store, _addr)           \
> +       { .dev_attr = __ATTR(_name, _mode, _show, _store),      \
> +         .address = _addr }
> +
> +#define IIO_DEVICE_ATTR(_name, _mode, _show, _store, _addr)    \
> +       struct iio_dev_attr iio_dev_attr_##_name                \
> +       = IIO_ATTR(_name, _mode, _show, _store, _addr)
> +
> +/**
> + * struct iio_const_attr - constant device specific attribute
> + *                         often used for things like available modes
> + * @string:    attribute string
> + * @dev_attr:  underlying device attribute
> + */
> +struct iio_const_attr {
> +       const char *string;
> +       struct device_attribute dev_attr;
> +};
> +
> +#define to_iio_const_attr(_dev_attr) \
> +       container_of(_dev_attr, struct iio_const_attr, dev_attr)
> +
> +ssize_t __iio_read_const_attr(struct device *dev,
> +                             struct device_attribute *attr,
> +                             char *len);
> +
> +#define IIO_CONST_ATTR(_name, _string)                                 \
> +       struct iio_const_attr iio_const_attr_##_name                    \
> +       = { .string = _string,                                          \
> +           .dev_attr = __ATTR(_name, S_IRUGO, __iio_read_const_attr, NULL) }
> +#endif /* _IIO_SYSFS_H_ */
> diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h
> new file mode 100644
> index 0000000..4cb24aa
> --- /dev/null
> +++ b/include/linux/iio/types.h
> @@ -0,0 +1,52 @@
> +/* industrial I/O data types needed both in and out of kernel
> + *
> + * Copyright (c) 2011 Jonathan Cameron
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License version 2 as published by
> + * the Free Software Foundation.
> + */
> +
> +#ifndef _IIO_TYPES_H_
> +#define _IIO_TYPES_H_
> +
> +enum iio_chan_type {
> +       IIO_VOLTAGE,
> +       IIO_CURRENT,
> +       IIO_POWER,
> +       IIO_CAPACITANCE,
> +       IIO_ACCEL,
> +       IIO_ANGL_VEL,
> +       IIO_MAGN,
> +       IIO_LIGHT,
> +       IIO_INTENSITY,
> +       IIO_PROXIMITY,
> +       IIO_TEMP,
> +       IIO_INCLI,
> +       IIO_ROT,
> +       IIO_ANGL,
> +       IIO_TIMESTAMP,
> +};
> +
> +enum iio_modifier {
> +       IIO_NO_MOD,
> +       IIO_MOD_X,
> +       IIO_MOD_Y,
> +       IIO_MOD_Z,
> +       IIO_MOD_X_AND_Y,
> +       IIO_MOD_X_ANX_Z,
> +       IIO_MOD_Y_AND_Z,
> +       IIO_MOD_X_AND_Y_AND_Z,
> +       IIO_MOD_X_OR_Y,
> +       IIO_MOD_X_OR_Z,
> +       IIO_MOD_Y_OR_Z,
> +       IIO_MOD_X_OR_Y_OR_Z,
> +       IIO_MOD_LIGHT_BOTH,
> +       IIO_MOD_LIGHT_INFRARED,
> +};
> +
> +#define IIO_VAL_INT 1
> +#define IIO_VAL_INT_PLUS_MICRO 2
> +#define IIO_VAL_INT_PLUS_NANO 3
> +
> +#endif /* _IIO_TYPES_H_ */
> --
> 1.7.7.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo@...r.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Greetings,
Michael

--
Analog Devices GmbH      Wilhelm-Wagenfeld-Str. 6      80807 Muenchen
Sitz der Gesellschaft: Muenchen; Registergericht: Muenchen HRB 40368;
Geschaeftsfuehrer:Dr.Carsten Suckrow, Thomas Wessel, William A. Martin,
Margaret Seif


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ