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 for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:   Mon, 9 Oct 2017 14:56:03 +0200
From:   Benjamin Gaignard <benjamin.gaignard@...aro.org>
To:     Jonathan Cameron <jic23@...nel.org>
Cc:     William Breathitt Gray <vilhelm.gray@...il.com>,
        Hartmut Knaack <knaack.h@....de>,
        Lars-Peter Clausen <lars@...afoo.de>,
        Peter Meerwald-Stadler <pmeerw@...erw.net>,
        linux-iio@...r.kernel.org,
        Linux Kernel Mailing List <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v3 2/6] iio: Introduce the generic counter interface

2017-10-08 16:30 GMT+02:00 Jonathan Cameron <jic23@...nel.org>:
> On Thu,  5 Oct 2017 14:13:44 -0400
> William Breathitt Gray <vilhelm.gray@...il.com> wrote:
>
>> This patch introduces the IIO generic counter interface for supporting
>> counter devices. The generic counter interface serves as a catch-all to
>> enable rudimentary support for devices that qualify as counters. More
>> specific and apt counter interfaces may be developed on top of the
>> generic counter interface, and those interfaces should be used by
>> drivers when possible rather than the generic counter interface.
>
> I think you probably want to avoid any additional layering and try to
> push things down here (maybe with a few utility functions to simplify
> common cases), but that's a question for another day!
>>
>> In the context of the IIO generic counter interface, a counter is
>> defined as a device that reports one or more "counter values" based on
>> the state changes of one or more "counter signals" as evaluated by a
>> defined "counter function."
>>
>> The IIO generic counter interface piggybacks off of the IIO core. This
>> is primarily used to leverage the existing sysfs setup: the IIO_COUNT
>> channel attributes represent the Counter Value, while the IIO_SIGNAL
>> channel attributes represent the Counter Signal; auxilary IIO_COUNT
>> attributes represent the Counter Signal connections (Triggers) and their
>> respective state change configurations which trigger an associated
>> "counter function" evaluation.
>>
>> The iio_counter_ops structure serves as a container for driver callbacks
>> to communicate with the device; function callbacks are provided to read
>> and write various Signals and Values, and set and get the "trigger mode"
>> and "function mode" for various Triggers and Values respectively.
>>
>> To support a counter device, a driver must first allocate the available
>> Counter Signals via iio_counter_signal structures. These Signals should
>> be stored as an array and set to the signals array member of an
>> allocated iio_counter structure before the Counter is registered to the
>> system.
>>
>> Counter Values may be allocated via iio_counter_value structures, and
>> respective Counter Signal associations (Triggers) made via
>> iio_counter_trigger structures. Associated iio_counter_trigger
>> structures are stored as an array and set to the the triggers array
>> member of the respective iio_counter_value structure. These
>> iio_counter_value structures are set to the values array member of an
>> allocated iio_counter structure before the Counter is registered to the
>> system.
>>
>> A counter device is registered to the system by passing the respective
>> initialized iio_counter structure to the iio_counter_register function;
>> similarly, the iio_counter_unregister function unregisters the
>> respective counter. The devm_iio_counter_register and
>> iio_devm_iio_counter_unregister functions serve as device memory-managed
>> versions of the iio_counter_register and iio_counter unregister
>> functions respectively.
>
> All the find by ids are the main complexity introduced by layering this
> on IIO that you probably wouldn't have if it wasn't so layered.  Hmm.
> I suggest inline that you could allow drivers to provide fast
> versions of that search given they can probably infer it directly from
> the index.  Might be something to ignore for now though in the interests
> of initial simplicity.
>
> Otherwise a few comments inline, but mostly this is coming together
> pretty well.  I'm actually surprised the layering on top of IIO didn't
> end up more painful than it did. It's not horrendous - which is not
> to say you wouldn't be better breaking free of that entirely...
> (I'm not sure either way).
>
> I think the big remaining questions are around naming more than anything
> else.  I don't like the name value when a user will think they are looking
> for a counter.  If you use counter though the current use of counter needs
> to change.
>
> Trigger is also, as has been raised, a rather overloaded term. Not totally
> obvious what a better term is but we shouldn't reuse that one...
>
> I'll try and think of something if you have no luck!
>
> Jonathan
>>
>> Signed-off-by: William Breathitt Gray <vilhelm.gray@...il.com>
>> ---
>>  MAINTAINERS                        |   7 +
>>  drivers/iio/Kconfig                |   8 +
>>  drivers/iio/Makefile               |   1 +
>>  drivers/iio/counter/Kconfig        |   1 +
>>  drivers/iio/industrialio-counter.c | 900 +++++++++++++++++++++++++++++++++++++
>>  include/linux/iio/counter.h        | 166 +++++++
>>  6 files changed, 1083 insertions(+)
>>  create mode 100644 drivers/iio/industrialio-counter.c
>>  create mode 100644 include/linux/iio/counter.h
>>
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 2281af4b41b6..8b7c37bed252 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -6693,6 +6693,13 @@ F:     Documentation/ABI/testing/sysfs-bus-iio-adc-envelope-detector
>>  F:   Documentation/devicetree/bindings/iio/adc/envelope-detector.txt
>>  F:   drivers/iio/adc/envelope-detector.c
>>
>> +IIO GENERIC COUNTER INTERFACE
>> +M:   William Breathitt Gray <vilhelm.gray@...il.com>
>> +L:   linux-iio@...r.kernel.org
>> +S:   Maintained
>> +F:   drivers/iio/industrialio-counter.c
>> +F:   include/linux/iio/counter.h
>
> Don't forget the directory the drivers are going in ;)
> *laughs manically*
>> +
>>  IIO MULTIPLEXER
>>  M:   Peter Rosin <peda@...ntia.se>
>>  L:   linux-iio@...r.kernel.org
>> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
>> index b3c8c6ef0dff..78e01f4f5937 100644
>> --- a/drivers/iio/Kconfig
>> +++ b/drivers/iio/Kconfig
>> @@ -30,6 +30,14 @@ config IIO_CONFIGFS
>>         (e.g. software triggers). For more info see
>>         Documentation/iio/iio_configfs.txt.
>>
>> +config IIO_COUNTER
>> +     bool "Enable IIO counter support"
>> +     help
>> +       Provides IIO core support for counters. This API provides
>> +       a generic interface that serves as the building blocks to
>> +       create more complex counter interfaces. Rudimentary support
>> +       for counters is enabled.
>> +
>>  config IIO_TRIGGER
>>       bool "Enable triggered sampling support"
>>       help
>> diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile
>> index 93c769cd99bf..6427ff38f964 100644
>> --- a/drivers/iio/Makefile
>> +++ b/drivers/iio/Makefile
>> @@ -5,6 +5,7 @@
>>  obj-$(CONFIG_IIO) += industrialio.o
>>  industrialio-y := industrialio-core.o industrialio-event.o inkern.o
>>  industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
>> +industrialio-$(CONFIG_IIO_COUNTER) += industrialio-counter.o
>>  industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
>>
>>  obj-$(CONFIG_IIO_CONFIGFS) += industrialio-configfs.o
>> diff --git a/drivers/iio/counter/Kconfig b/drivers/iio/counter/Kconfig
>> index 474e1ac4e7c0..c8becfe78e28 100644
>> --- a/drivers/iio/counter/Kconfig
>> +++ b/drivers/iio/counter/Kconfig
>> @@ -4,6 +4,7 @@
>>  # When adding new entries keep the list in alphabetical order
>>
>>  menu "Counters"
>> +     depends on IIO_COUNTER
>>
>>  config 104_QUAD_8
>>       tristate "ACCES 104-QUAD-8 driver"
>> diff --git a/drivers/iio/industrialio-counter.c b/drivers/iio/industrialio-counter.c
>> new file mode 100644
>> index 000000000000..dfb982dae3a8
>> --- /dev/null
>> +++ b/drivers/iio/industrialio-counter.c
>> @@ -0,0 +1,900 @@
>> +/*
>> + * Industrial I/O counter interface functions
>> + * Copyright (C) 2017 William Breathitt Gray
>> + *
>> + * 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.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * General Public License for more details.
>> + */
>> +#include <linux/device.h>
>> +#include <linux/err.h>
>> +#include <linux/export.h>
>> +#include <linux/gfp.h>
>> +#include <linux/kernel.h>
>> +#include <linux/printk.h>
>> +#include <linux/slab.h>
>> +#include <linux/string.h>
>> +
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/types.h>
>> +
>> +#include <linux/iio/counter.h>
>> +
>> +#define iio_priv_get_counter(_indio_dev) \
>> +     (*(struct iio_counter **)iio_priv(_indio_dev))
>> +
>> +static struct iio_counter_signal *iio_counter_signal_find_by_id(
>> +     const struct iio_counter *const counter, const int id)
>> +{
>> +     size_t i;
>> +     struct iio_counter_signal *signal;
>> +
>> +     for (i = 0; i < counter->num_signals; i++) {
>> +             signal = counter->signals + i;
>> +             if (signal->id == id)
>> +                     return signal;
>> +     }
>> +
>> +     return NULL;
>> +}
>> +
>> +static struct iio_counter_trigger *iio_counter_trigger_find_by_id(
>> +     const struct iio_counter_value *const value, const int id)
>> +{
>> +     size_t i;
>> +     struct iio_counter_trigger *trigger;
>> +
>> +     for (i = 0; i < value->num_triggers; i++) {
>> +             trigger = value->triggers + i;
>> +             if (trigger->signal->id == id)
>> +                     return trigger;
>> +     }
>> +
>> +     return NULL;
>> +}
>> +
>> +static struct iio_counter_value *iio_counter_value_find_by_id(
>> +     const struct iio_counter *const counter, const int id)
>> +{
>> +     size_t i;
>> +     struct iio_counter_value *value;
>
> In most cases this mapping will be entirely obvious to the
> driver - perhaps provide an optional callback to let it
> provide it directly without any searching?
>
> We could always add this later though if we start getting
> drivers with lots of instances of the various parts...
>
>> +
>> +     for (i = 0; i < counter->num_values; i++) {
>> +             value = counter->values + i;
>> +             if (value->id == id)
>> +                     return value;
>> +     }
>> +
>> +     return NULL;
>> +}
>> +
>> +static ssize_t iio_counter_signal_name_read(struct iio_dev *indio_dev,
>> +     uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     const struct iio_counter_signal *signal;
>> +
>> +     signal = iio_counter_signal_find_by_id(counter, chan->channel2);
>> +     if (!signal)
>> +             return -EINVAL;
>> +
>> +     return scnprintf(buf, PAGE_SIZE, "%s\n", signal->name);
>> +}
>> +
>> +static ssize_t iio_counter_value_name_read(struct iio_dev *indio_dev,
>> +     uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     const struct iio_counter_value *value;
>> +
>> +     value = iio_counter_value_find_by_id(counter, chan->channel2);
>> +     if (!value)
>> +             return -EINVAL;
>> +
>> +     return scnprintf(buf, PAGE_SIZE, "%s\n", value->name);
>
> I mentioned before but I wonder if we can just push name down into
> the chan spec itself in some fashion.  Whether to associate it with
> existing datasheet_name or not is an open question however.
>
>> +}
>> +
>> +static ssize_t iio_counter_value_triggers_read(struct iio_dev *indio_dev,
>> +     uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_value *value;
>> +     size_t i;
>> +     const struct iio_counter_trigger *trigger;
>> +     ssize_t len = 0;
>> +
>> +     value = iio_counter_value_find_by_id(counter, chan->channel2);
>> +     if (!value)
>> +             return -EINVAL;
>> +
>> +     /* Print out a list of every Signal association to Value */
>> +     for (i = 0; i < value->num_triggers; i++) {
>> +             trigger = value->triggers + i;
>> +             len += snprintf(buf + len, PAGE_SIZE - len, "%d\t%s\t%s\n",
>> +                     trigger->signal->id, trigger->signal->name,
>> +                     trigger->trigger_modes[trigger->mode]);
>> +             if (len >= PAGE_SIZE)
>> +                     return -ENOMEM;
>> +     }
>> +
>> +     return len;
>> +}
>> +
>> +static ssize_t iio_counter_trigger_mode_read(struct iio_dev *indio_dev,
>> +     uintptr_t priv, const struct iio_chan_spec *chan, char *buf)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_value *value;
>> +     struct iio_counter_trigger *trigger;
>> +     const int signal_id = *(int *)((void *)priv);
>> +     int mode;
>> +
>> +     if (!counter->ops->trigger_mode_get)
>> +             return -EINVAL;
>> +
>> +     value = iio_counter_value_find_by_id(counter, chan->channel2);
>> +     if (!value)
>> +             return -EINVAL;
>> +
>> +     trigger = iio_counter_trigger_find_by_id(value, signal_id);
>> +     if (!trigger)
>> +             return -EINVAL;
>> +
>> +     mode = counter->ops->trigger_mode_get(counter, value, trigger);
>> +
>> +     if (mode < 0)
>> +             return mode;
>> +     else if (mode >= trigger->num_trigger_modes)
>> +             return -EINVAL;
>> +
>> +     trigger->mode = mode;
>> +
>> +     return scnprintf(buf, PAGE_SIZE, "%s\n", trigger->trigger_modes[mode]);
>> +}
>> +
>> +static ssize_t iio_counter_trigger_mode_write(struct iio_dev *indio_dev,
>> +     uintptr_t priv, const struct iio_chan_spec *chan, const char *buf,
>> +     size_t len)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_value *value;
>> +     ssize_t err;
>> +     struct iio_counter_trigger *trigger;
>> +     const int signal_id = *(int *)((void *)priv);
>> +     unsigned int mode;
>> +
>> +     if (!counter->ops->trigger_mode_set)
>> +             return -EINVAL;
>> +
>> +     value = iio_counter_value_find_by_id(counter, chan->channel2);
>> +     if (!value)
>> +             return -EINVAL;
>> +
>> +     trigger = iio_counter_trigger_find_by_id(value, signal_id);
>> +     if (!trigger)
>> +             return -EINVAL;
>> +
>> +     for (mode = 0; mode < trigger->num_trigger_modes; mode++)
>> +             if (sysfs_streq(buf, trigger->trigger_modes[mode]))
>> +                     break;
>> +
>> +     if (mode >= trigger->num_trigger_modes)
>> +             return -EINVAL;
>> +
>> +     err = counter->ops->trigger_mode_set(counter, value, trigger, mode);
>> +     if (err)
>> +             return err;
>> +
>> +     trigger->mode = mode;
>> +
>> +     return len;
>> +}
>> +
>> +static ssize_t iio_counter_trigger_mode_available_read(
>> +     struct iio_dev *indio_dev, uintptr_t priv,
>> +     const struct iio_chan_spec *chan, char *buf)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_value *value;
>> +     ssize_t len = 0;
>> +     struct iio_counter_trigger *trigger;
>> +     const int signal_id = *(int *)((void *)priv);
>> +     unsigned int i;
>> +
>> +     value = iio_counter_value_find_by_id(counter, chan->channel2);
>> +     if (!value)
>> +             return -EINVAL;
>> +
>> +     trigger = iio_counter_trigger_find_by_id(value, signal_id);
>> +     if (!trigger)
>> +             return -EINVAL;
>> +
>> +     for (i = 0; i < trigger->num_trigger_modes; i++)
>> +             len += scnprintf(buf + len, PAGE_SIZE - len, "%s ",
>> +                     trigger->trigger_modes[i]);
>> +
>> +     buf[len - 1] = '\n';
>> +
>> +     return len;
>> +}
>> +
>> +static int iio_counter_value_function_set(struct iio_dev *indio_dev,
>> +     const struct iio_chan_spec *chan, unsigned int mode)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_value *value;
>> +     int err;
>> +
>> +     if (!counter->ops->value_function_set)
>> +             return -EINVAL;
>> +
>> +     /* Find relevant Value */
>> +     value = iio_counter_value_find_by_id(counter, chan->channel2);
>> +     if (!value)
>> +             return -EINVAL;
>> +
>> +     /* Map IIO core function_set to Generic Counter value_function_set */
>> +     err = counter->ops->value_function_set(counter, value, mode);
>> +     if (err)
>> +             return err;
>> +
>> +     value->mode = mode;
>> +
>> +     return 0;
>> +}
>> +
>> +static int iio_counter_value_function_get(struct iio_dev *indio_dev,
>> +     const struct iio_chan_spec *chan)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_value *value;
>> +     int retval;
>> +
>> +     if (!counter->ops->value_function_get)
>> +             return -EINVAL;
>> +
>> +     /* Find relevant Value */
>> +     value = iio_counter_value_find_by_id(counter, chan->channel2);
>
> Same argument as below - would the driver not be able to do this better?
> Often it would know a simple transform to get the right one...
>
>
>> +     if (!value)
>> +             return -EINVAL;
>> +
>> +     /* Map IIO core function_get to Generic Counter value_function_get */
>> +     retval = counter->ops->value_function_get(counter, value);
>> +     if (retval < 0)
>> +             return retval;
>> +     else if (retval >= value->num_function_modes)
>> +             return -EINVAL;
>> +
>> +     value->mode = retval;
>> +
>> +     return retval;
>> +}
>> +
>> +static int iio_counter_value_ext_info_alloc(struct iio_chan_spec *const chan,
>> +     struct iio_counter_value *const value)
>> +{
>> +     const struct iio_chan_spec_ext_info ext_info_default[] = {
>> +             {
>> +                     .name = "name",
>> +                     .shared = IIO_SEPARATE,
>> +                     .read = iio_counter_value_name_read
>> +             },
>> +             IIO_ENUM("function", IIO_SEPARATE, &value->function_enum),
>> +             {
>> +                     .name = "function_available",
>> +                     .shared = IIO_SEPARATE,
>> +                     .read = iio_enum_available_read,
>> +                     .private = (void *)&value->function_enum
>> +             },
>> +             {
>> +                     .name = "triggers",
>> +                     .shared = IIO_SEPARATE,
>> +                     .read = iio_counter_value_triggers_read
>> +             }
>> +     };
>> +     const size_t num_default = ARRAY_SIZE(ext_info_default);
>> +     const struct iio_chan_spec_ext_info ext_info_trigger[] = {
>> +             {
>> +                     .shared = IIO_SEPARATE,
>> +                     .read = iio_counter_trigger_mode_read,
>> +                     .write = iio_counter_trigger_mode_write
>> +             },
>> +             {
>> +                     .shared = IIO_SEPARATE,
>> +                     .read = iio_counter_trigger_mode_available_read
>> +             }
>> +     };
>> +     const size_t num_ext_info_trigger = ARRAY_SIZE(ext_info_trigger);
>> +     const size_t num_triggers_ext_info = num_ext_info_trigger *
>> +             value->num_triggers;
>> +     const size_t num_ext_info = num_default + num_triggers_ext_info + 1;
>> +     int err;
>> +     struct iio_chan_spec_ext_info *ext_info;
>> +     const struct iio_counter_trigger *trigger;
>> +     size_t i;
>> +     size_t j;
>> +
>> +     /* Construct function_enum for Value */
>> +     value->function_enum.items = value->function_modes;
>> +     value->function_enum.num_items = value->num_function_modes;
>> +     value->function_enum.set = iio_counter_value_function_set;
>> +     value->function_enum.get = iio_counter_value_function_get;
>> +
>> +     ext_info = kmalloc_array(num_ext_info, sizeof(*ext_info), GFP_KERNEL);
>> +     if (!ext_info)
>> +             return -ENOMEM;
>> +     ext_info[num_ext_info - 1].name = NULL;
>> +
>> +     /* Add ext_info for the name, function, function_available, and triggers
>> +      * attributes
>> +      */
>> +     memcpy(ext_info, ext_info_default, sizeof(ext_info_default));
>> +     /* Add ext_info for the trigger_signalX-Z and
>> +      * trigger_signalX-Z_available attributes for each Trigger
>> +      */
>> +     for (i = 0; i < num_triggers_ext_info; i += num_ext_info_trigger)
>> +             memcpy(ext_info + num_default + i, ext_info_trigger,
>> +                     sizeof(ext_info_trigger));
>> +
>> +     /* Set name for each trigger_signalX-Z and trigger_signalX-Z_available
>> +      * attribute; store the respective Signal ID address in each ext_info
>> +      * private member
>> +      */
>> +     for (i = num_default, j = 0; j < value->num_triggers; i++, j++) {
>> +             trigger = value->triggers + j;
>> +
>> +             ext_info[i].name = kasprintf(GFP_KERNEL, "trigger_signal%d-%d",
>> +                     chan->channel, trigger->signal->id);
>> +             if (!ext_info[i].name) {
>> +                     err = -ENOMEM;
>> +                     goto err_name_alloc;
>> +             }
>> +             ext_info[i].private = (void *)&trigger->signal->id;
>> +             i++;
>> +
>> +             ext_info[i].name = kasprintf(GFP_KERNEL,
>> +                     "trigger_signal%d-%d_available",
>> +                     chan->channel, trigger->signal->id);
>> +             if (!ext_info[i].name) {
>> +                     err = -ENOMEM;
>> +                     goto err_name_alloc;
>> +             }
>> +             ext_info[i].private = (void *)&trigger->signal->id;
>> +     }
>> +
>> +     chan->ext_info = ext_info;
>> +
>> +     return 0;
>> +
>> +err_name_alloc:
>> +     while (i-- > num_default)
>> +             kfree(ext_info[i].name);
>> +     kfree(ext_info);
>> +     return err;
>> +}
>> +
>> +static void iio_counter_value_ext_info_free(
>> +     const struct iio_chan_spec *const channel)
>> +{
>> +     size_t i;
>> +     const char *const prefix = "trigger_signal";
>> +     const size_t prefix_len = strlen(prefix);
>> +
>> +     for (i = 0; channel->ext_info[i].name; i++)
>> +             if (!strncmp(channel->ext_info[i].name, prefix, prefix_len))
>> +                     kfree(channel->ext_info[i].name);
>> +     kfree(channel->ext_info);
>> +}
>> +
>> +static const struct iio_chan_spec_ext_info iio_counter_signal_ext_info[] = {
>> +     {
>> +             .name = "name",
>> +             .shared = IIO_SEPARATE,
>> +             .read = iio_counter_signal_name_read
>> +     },
>> +     {}
>> +};
>> +
>> +static int iio_counter_channels_alloc(struct iio_counter *const counter)
>> +{
>> +     const size_t num_channels = counter->num_signals + counter->num_values +
>> +             counter->num_channels;
>> +     int err;
>> +     struct iio_chan_spec *channels;
>> +     size_t j;
>> +     struct iio_counter_value *value;
>> +     size_t i = counter->num_channels;
>> +     const struct iio_counter_signal *signal;
>> +
>> +     channels = kcalloc(num_channels, sizeof(*channels), GFP_KERNEL);
>
> Bring the calculation of num_channels down here - it will make it
> more obvious that this allows space for both sources of channel.
>
>> +     if (!channels)
>> +             return -ENOMEM;
>> +
>> +     /* If any channels were supplied on Counter registration,
>> +      * we add them here to the front of the array
>> +      */
>> +     memcpy(channels, counter->channels,
>> +             counter->num_channels * sizeof(*counter->channels));
>> +
>> +     /* Add channel for each Value */
>> +     for (j = 0; j < counter->num_values; j++) {
>> +             value = counter->values + j;
>> +
>> +             channels[i].type = IIO_COUNT;
>> +             channels[i].channel = counter->id;
>> +             channels[i].channel2 = value->id;
>> +             channels[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
>> +             channels[i].indexed = 1;
>> +             channels[i].counter = 1;
>> +
>> +             /* Add channels for Triggers associated with Value */
> Add channels?  'i' would need incrementing.   Also that's not what this function
> is doing that I can see...
>> +             err = iio_counter_value_ext_info_alloc(channels + i, value);
>> +             if (err)
>> +                     goto err_value_ext_info_alloc;
>> +
>> +             i++;
>> +     }
>> +
>> +     /* Add channel for each Signal */
>> +     for (j = 0; j < counter->num_signals; j++) {
>> +             signal = counter->signals + j;
>> +
>> +             channels[i].type = IIO_SIGNAL;
>> +             channels[i].channel = counter->id;
>> +             channels[i].channel2 = signal->id;
>> +             channels[i].info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
>> +             channels[i].indexed = 1;
>> +             channels[i].counter = 1;
>> +             channels[i].ext_info = iio_counter_signal_ext_info;
>> +
>> +             i++;
>> +     }
>> +
>> +     counter->indio_dev->num_channels = num_channels;
>> +     counter->indio_dev->channels = channels;
>> +
>> +     return 0;
>> +
>> +err_value_ext_info_alloc:
>> +     while (i-- > counter->num_channels)
>> +             iio_counter_value_ext_info_free(channels + i);
>> +     kfree(channels);
>> +     return err;
>> +}
>> +
>> +static void iio_counter_channels_free(const struct iio_counter *const counter)
>> +{
>> +     size_t i = counter->num_channels + counter->indio_dev->num_channels;
>> +     const struct iio_chan_spec *const chans = counter->indio_dev->channels;
>> +
>> +     while (i-- > counter->num_channels)
>> +             /* Only IIO_COUNT channels need to be freed here */
>> +             if (chans[i].type == IIO_COUNT)
>> +                     iio_counter_value_ext_info_free(chans + i);
>> +
>> +     kfree(chans);
>> +}
>> +
>> +static int iio_counter_read_raw(struct iio_dev *indio_dev,
>> +     struct iio_chan_spec const *chan, int *val, int *val2, long mask)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_signal *signal;
>> +     struct iio_counter_value *value;
>> +
>> +     if (mask != IIO_CHAN_INFO_RAW)
>> +             return -EINVAL;
>> +
>> +     switch (chan->type) {
>> +     /* Map read_raw to signal_read for Signal */
>> +     case IIO_SIGNAL:
>> +             if (!counter->ops->signal_read)
>> +                     return -EINVAL;
>> +
>> +             signal = iio_counter_signal_find_by_id(counter, chan->channel2);
>> +             if (!signal)
>> +                     return -EINVAL;
>> +
>> +             return counter->ops->signal_read(counter, signal, val, val2);
>> +     /* Map read_raw to value_read for Value */
>> +     case IIO_COUNT:
>> +             if (!counter->ops->value_read)
>> +                     return -EINVAL;
>> +
>> +             value = iio_counter_value_find_by_id(counter, chan->channel2);
>> +             if (!value)
>> +                     return -EINVAL;
>> +
>> +             return counter->ops->value_read(counter, value, val, val2);
>> +     /* Map read_raw to read_raw for non-counter channel */
>> +     default:
>> +             if (counter->info && counter->info->read_raw)
>> +                     return counter->info->read_raw(indio_dev, chan, val,
>> +                             val2, mask);
>> +     }
>> +
>> +     return -EINVAL;
>> +}
>> +
>> +static int iio_counter_write_raw(struct iio_dev *indio_dev,
>> +     struct iio_chan_spec const *chan, int val, int val2, long mask)
>> +{
>> +     struct iio_counter *const counter = iio_priv_get_counter(indio_dev);
>> +     struct iio_counter_signal *signal;
>> +     struct iio_counter_value *value;
>> +
>> +     if (mask != IIO_CHAN_INFO_RAW)
>> +             return -EINVAL;
>> +
>> +     switch (chan->type) {
>> +     /* Map write_raw to signal_write for Signal */
>> +     case IIO_SIGNAL:
>> +             if (!counter->ops->signal_write)
>> +                     return -EINVAL;
>> +
>> +             signal = iio_counter_signal_find_by_id(counter, chan->channel2);
>> +             if (!signal)
>> +                     return -EINVAL;
>
>         Hmm. have to search is certainly a little ugly.  Particularly as the driver
>         would be able to maintain this as a lookup.  I'd be tempted to pass the
>         signal id down into the callback rather than finding the signal in the core.
>         Might turn out messier though... :)
>
>> +
>> +             return counter->ops->signal_write(counter, signal, val, val2);
>> +     /* Map write_raw to value_write for Value */
>> +     case IIO_COUNT:
>> +             if (!counter->ops->value_write)
>> +                     return -EINVAL;
>> +
>> +             value = iio_counter_value_find_by_id(counter, chan->channel2);
>
> Again, this mapping is a simple lookup in the driver I think, perhaps push
> it down there?
>
>> +             if (!value)
>> +                     return -EINVAL;
>> +
>> +             return counter->ops->value_write(counter, value, val, val2);
>> +     /* Map write_raw to write_raw for non-counter channel */
>> +     default:
>> +             if (counter->info && counter->info->write_raw)
>> +                     return counter->info->write_raw(indio_dev, chan, val,
>> +                             val2, mask);
>> +     }
>> +
>> +     return -EINVAL;
>> +}
>> +
>> +static int iio_counter_signals_validate(const struct iio_counter *const counter)
>> +{
>> +     size_t i;
>> +     const struct iio_counter_signal *signal;
>> +     size_t j;
>> +     int curr_id;
>> +
>> +     /* At least one Signal must be defined */
>> +     if (!counter->num_signals || !counter->signals) {
>> +             pr_err("Counter '%d' Signals undefined\n", counter->id);
>> +             return -EINVAL;
>> +     }
>> +
>> +     for (i = 0; i < counter->num_signals; i++) {
>> +             signal = counter->signals + i;
>> +             /* No two Signals may share the same ID */
>> +             for (j = 0; j < i; j++) {
>> +                     curr_id = counter->signals[j].id;
>> +                     if (curr_id == signal->id) {
>> +                             pr_err("Duplicate Counter '%d' Signal '%d'\n",
>> +                                             counter->id, signal->id);
>> +                             return -EEXIST;
>> +                     }
>> +             }
>> +             for (j = i + 1; j < counter->num_signals; j++) {
>> +                     curr_id = counter->signals[j].id;
>> +                     if (curr_id == signal->id) {
>> +                             pr_err("Duplicate Counter '%d' Signal '%d'\n",
>> +                                             counter->id, signal->id);
>> +                             return -EEXIST;
>> +                     }
>> +             }
>
> Same as below.
>
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int iio_counter_triggers_validate(const int counter_id,
>> +     const struct iio_counter_value *const value)
>> +{
>> +     size_t i;
>> +     const struct iio_counter_trigger *trigger;
>> +     size_t j;
>> +     int curr_id;
>> +
>> +     /* At least one Trigger must be defined */
>> +     if (!value->num_triggers || !value->triggers) {
>> +             pr_err("Counter '%d' Value '%d' Triggers undefined\n",
>> +                     counter_id, value->id);
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* Ensure all Triggers have a defined Signal; this prevents a possible
>> +      * NULL pointer dereference when later validating Trigger Signal IDs
>
> Fix comment syntax throughout...
>
>> +      */
>> +     for (i = 0; i < value->num_triggers; i++)
>> +             if (!value->triggers[i].signal) {
>> +                     pr_err("Counter '%d' Trigger '%zu' Signal undefined\n",
>> +                             counter_id, i);
>> +                     return -EINVAL;
>> +             }
>> +
>> +     /* Verify validity of each Trigger */
>> +     for (i = 0; i < value->num_triggers; i++) {
>> +             trigger = value->triggers + i;
>> +             /* No two Trigger Signals may share the same ID */
>> +             for (j = 0; j < i; j++) {
>> +                     curr_id = value->triggers[j].signal->id;
>> +                     if (curr_id == trigger->signal->id) {
>> +                             pr_err("Signal '%d' is already linked to Counter '%d' Value '%d'\n",
>> +                                     trigger->signal->id, counter_id,
>> +                                     value->id);
>> +                             return -EEXIST;
>> +                     }
>> +             }
>> +             for (j = i + 1; j < value->num_triggers; j++) {
>> +                     curr_id = value->triggers[j].signal->id;
>> +                     if (curr_id == trigger->signal->id) {
>> +                             pr_err("Signal '%d' is already linked to Counter '%d' Value '%d'\n",
>> +                                     trigger->signal->id, counter_id,
>> +                                     value->id);
>> +                             return -EEXIST;
>> +                     }
>> +             }
> Again, one loop with the condition changed so it doesn't fault on the i = j case -- see below and
> note I'm reviewing backwards...
>
>
>> +
>> +             /* At least one trigger mode must be defined for each Trigger */
>> +             if (!trigger->num_trigger_modes || !trigger->trigger_modes) {
>> +                     pr_err("Counter '%d' Signal '%d' trigger modes undefined\n",
>> +                             counter_id, trigger->signal->id);
>> +                     return -EINVAL;
>> +             }
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int iio_counter_values_validate(const struct iio_counter *const counter)
>> +{
>
> Hmm. Pretty heavy weight checking.  Ah well, up to you.
>
>> +     size_t i;
>> +     const struct iio_counter_value *value;
>> +     size_t j;
>> +     int curr_id;
>> +     int err;
>> +
>> +     /* At least one Value must be defined */
>> +     if (!counter->num_values || !counter->values) {
>> +             pr_err("Counter '%d' Values undefined\n", counter->id);
>> +             return -EINVAL;
>> +     }
>> +
>> +     /* Verify validity of each Value */
>> +     for (i = 0; i < counter->num_values; i++) {
>> +             value = counter->values + i;
>> +             /* No two Values may share the same ID */
>> +             for (j = 0; j < i; j++) {
>
> Single loop with a slightly change to condition
> if ((i != j) and (curr_id == value->id))
>
>> +                     curr_id = counter->values[j].id;
>> +                     if (curr_id == value->id) {
>> +                             pr_err("Duplicate Counter '%d' Value '%d'\n",
>> +                                     counter->id, value->id);
>> +                             return -EEXIST;
>> +                     }
>> +             }
>> +             for (j = i + 1; j < counter->num_values; j++) {
>> +                     curr_id = counter->values[j].id;
>> +                     if (curr_id == value->id) {
>> +                             pr_err("Duplicate Counter '%d' Value '%d'\n",
>> +                                     counter->id, value->id);
>> +                             return -EEXIST;
>> +                     }
>> +             }
>> +
>> +             /* At least one function mode must be defined for each Value */
>> +             if (!value->num_function_modes || !value->function_modes) {
>> +                     pr_err("Counter '%d' Value '%d' function modes undefined\n",
>> +                             counter->id, value->id);
>> +                     return -EINVAL;
>> +             }
>> +
>> +             /* Verify the Triggers associated with each Value */
>> +             err = iio_counter_triggers_validate(counter->id, value);
>> +             if (err)
>> +                     return err;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +/**
>> + * iio_counter_register - register Counter to the system
>> + * @counter: pointer to IIO Counter to register
>> + *
>> + * This function piggybacks off of iio_device_register. First, the relevant
>> + * Counter members are validated; the signals and values members must be defined
>> + * and populated by valid Signal and Value structures respectively. Next, a
>> + * struct iio_dev is allocated by a call to iio_device_alloc and initialized for
>> + * the Counter, IIO channels are allocated, the Counter address is stored as the
>> + * private data, and finally iio_device_register is called.
>> + */
>> +int iio_counter_register(struct iio_counter *const counter)
>> +{
>> +     const struct iio_info info_default = {
>> +             .read_raw = iio_counter_read_raw,
>> +             .write_raw = iio_counter_write_raw
>> +     };
>> +     int err;
>> +     struct iio_info *info;
>> +     struct iio_counter **priv;
>> +
>> +     if (!counter)
>> +             return -EINVAL;
>> +
>> +     /* Verify that Signals are valid and IDs do not conflict */
>> +     err = iio_counter_signals_validate(counter);
>> +     if (err)
>> +             return err;
>> +
>> +     /* Verify that Values are valid and IDs do not conflict;
> Fix multiline comment syntax to standard kernel syntax.
> /*
>  * Verify
>  */
>> +      * Triggers for each Value are also verified for validity
>> +      */
>> +     err = iio_counter_values_validate(counter);
>> +     if (err)
>> +             return err;
>> +
>> +     counter->indio_dev = iio_device_alloc(sizeof(counter));
>> +     if (!counter->indio_dev)
>> +             return -ENOMEM;
>> +
>> +     info = kmalloc(sizeof(*info), GFP_KERNEL);
>> +     if (!info) {
>> +             err = -ENOMEM;
>> +             goto err_info_alloc;
>> +     }
>> +     /* If an iio_info has been supplied than we use that,
>> +      * otherwise we set all callbacks to NULL; iio_counter_read_raw
>> +      * and iio_counter_write_raw is used for read_raw and write_raw
>> +      * for either case in order to support counter functionality
>> +      * (supplied read_raw/write_raw will be called from within
>> +      * iio_counter_read_raw/iio_counter_write_raw for non-counter
>> +      * channels)
>> +      */
>
>> +     if (counter->info) {
>> +             memcpy(info, counter->info, sizeof(*counter->info));
>> +             info->read_raw = iio_counter_read_raw;
>> +             info->write_raw = iio_counter_write_raw;
>> +     } else {
>> +             memcpy(info, &info_default, sizeof(info_default));
>> +     }
>> +
>> +     counter->indio_dev->info = info;
>> +     counter->indio_dev->modes = INDIO_DIRECT_MODE;

As I have said in the previous version, stm32 driver will not work with
this mode, so I need way to change it.
One solution could be to use iio_priv to store an iio_counter structure with
ops, arrays etc... Maybe even iio_counter structure could be hiden from drivers.
It could require to split iio_counter allocation and registration to functions.

>> +     counter->indio_dev->name = counter->name;
>> +     counter->indio_dev->dev.parent = counter->dev;
>> +
>> +     /* IIO channels are allocated and set for Signals, Values, and Triggers;
>> +      * any auxiliary IIO channels provided in iio_counter are also set
>> +      */
>> +     err = iio_counter_channels_alloc(counter);
>> +     if (err)
>> +             goto err_channels_alloc;
>> +
>> +     /* Pointer to the counter is stored in indio_dev as a way to refer
>> +      * back to the counter from within various IIO callbacks
>> +      */
>> +     priv = iio_priv(counter->indio_dev);
>> +     memcpy(priv, &counter, sizeof(*priv));
>> +
>> +     err = iio_device_register(counter->indio_dev);
>> +     if (err)
>> +             goto err_iio_device_register;
>> +
>> +     return 0;
>> +
>> +err_iio_device_register:
>> +     iio_counter_channels_free(counter);
>> +err_channels_alloc:
>> +     kfree(info);
>> +err_info_alloc:
>> +     iio_device_free(counter->indio_dev);
>> +     return err;
>> +}
>> +EXPORT_SYMBOL(iio_counter_register);
>> +
>> +/**
>> + * iio_counter_unregister - unregister Counter from the system
>> + * @counter: pointer to IIO Counter to unregister
>> + *
>> + * The Counter is unregistered from the system. The indio_dev is unregistered
>> + * and all allocated memory is freed.
>> + */
>> +void iio_counter_unregister(struct iio_counter *const counter)
>> +{
>> +     const struct iio_info *const info = counter->indio_dev->info;
>> +
>> +     if (!counter)
>> +             return;
>> +
>> +     iio_device_unregister(counter->indio_dev);
>> +
>> +     iio_counter_channels_free(counter);
>> +
>> +     kfree(info);
>> +     iio_device_free(counter->indio_dev);
>> +}
>> +EXPORT_SYMBOL(iio_counter_unregister);
>> +
>> +static void devm_iio_counter_unreg(struct device *dev, void *res)
>> +{
>> +     iio_counter_unregister(*(struct iio_counter **)res);
>> +}
>> +
>> +/**
>> + * devm_iio_counter_register - Resource-managed iio_counter_register
>> + * @dev: Device to allocate iio_counter for
>> + * @counter: pointer to IIO Counter to register
>> + *
>> + * Managed iio_counter_register. The IIO counter registered with this
>> + * function is automatically unregistered on driver detach. This function
>> + * calls iio_counter_register internally. Refer to that function for more
>> + * information.
>> + *
>> + * If an iio counter registered with this function needs to be unregistered
>> + * separately, devm_iio_counter_unregister must be used.
>> + *
>> + * RETURNS:
>> + * 0 on success, negative error number on failure.
>> + */
>> +int devm_iio_counter_register(struct device *dev,
>> +     struct iio_counter *const counter)
>> +{
>> +     struct iio_counter **ptr;
>> +     int ret;
>> +
>> +     ptr = devres_alloc(devm_iio_counter_unreg, sizeof(*ptr), GFP_KERNEL);
>> +     if (!ptr)
>> +             return -ENOMEM;
>> +
>> +     *ptr = counter;
>> +     ret = iio_counter_register(counter);
>> +     if (!ret)
>> +             devres_add(dev, ptr);
>> +     else
>> +             devres_free(ptr);
>> +
>> +     return ret;
>> +}
>> +EXPORT_SYMBOL(devm_iio_counter_register);
>> +
>> +static int devm_iio_counter_match(struct device *dev, void *res, void *data)
>> +{
>> +     struct iio_counter **r = res;
>> +
>> +     if (!r || !*r) {
>> +             WARN_ON(!r || !*r);
>> +             return 0;
>> +     }
>> +
>> +     return *r == data;
>> +}
>> +
>> +/**
>> + * devm_iio_counter_unregister - Resource-managed iio_counter_unregister
>> + * @dev: Device this iio_counter belongs to
>> + * @counter: the iio counter associated with the device
>> + *
>> + * Unregister iio counter registered with devm_iio_counter_register.
>> + */
>> +void devm_iio_counter_unregister(struct device *dev,
>> +     struct iio_counter *const counter)
>> +{
>> +     int rc;
>> +
>> +     rc = devres_release(dev, devm_iio_counter_unreg,
>> +             devm_iio_counter_match, counter);
>> +     WARN_ON(rc);
>> +}
>> +EXPORT_SYMBOL(devm_iio_counter_unregister);
>> diff --git a/include/linux/iio/counter.h b/include/linux/iio/counter.h
>> new file mode 100644
>> index 000000000000..35645406711a
>> --- /dev/null
>> +++ b/include/linux/iio/counter.h
>> @@ -0,0 +1,166 @@
>> +/*
>> + * Industrial I/O counter interface
>> + * Copyright (C) 2017 William Breathitt Gray
>> + *
>> + * 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.
>> + *
>> + * This program is distributed in the hope that it will be useful, but
>> + * WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * General Public License for more details.
>> + */
>> +#ifndef _IIO_COUNTER_H_
>> +#define _IIO_COUNTER_H_
>> +
>> +#ifdef CONFIG_IIO_COUNTER
>> +
>> +#include <linux/device.h>
>> +#include <linux/types.h>
>> +
>> +#include <linux/iio/iio.h>
>> +
>> +/**
>> + * struct iio_counter_signal - IIO Counter Signal node
>> + * @id:              [DRIVER] unique ID used to identify signal
>> + * @name:    [DRIVER] device-specific signal name
>> + */
>> +struct iio_counter_signal {
>> +     int             id;
>> +     const char      *name;
>> +};
>> +
>> +/**
>> + * struct iio_counter_trigger - IIO Counter Trigger node
>> + * @mode:            [DRIVER] current trigger mode state
>> + * @trigger_modes:   [DRIVER] available trigger modes
>> + * @num_trigger_modes:       [DRIVER] number of modes specified in @trigger_modes
>> + * @signal:          [DRIVER] pointer to associated signal
>> + */
>> +struct iio_counter_trigger {
>> +     unsigned int                    mode;
>> +     const char *const               *trigger_modes;
>> +     unsigned int                    num_trigger_modes;
>> +     struct iio_counter_signal       *signal;
>
> Are signals actually changeable? - Or is that pointer constant?
>
>> +};
>> +
>> +/**
>> + * struct iio_counter_value - IIO Counter Value node
>> + * @id:                      [DRIVER] unique ID used to identify value
>> + * @name:            [DRIVER] device-specific value name
>> + * @mode:            [DRIVER] current function mode state
>> + * @function_modes:  [DRIVER] available function modes
>> + * @num_function_modes:      [DRIVER] number of modes specified in @function_modes
>> + * @triggers:                [DRIVER] array of triggers for initialization
>> + * @num_triggers:    [DRIVER] number of triggers specified in @triggers
>> + * @function_enum:   [INTERN] used internally to generate function attributes
>> + */
>> +struct iio_counter_value {
>> +     int                     id;
>> +     const char              *name;
>> +     unsigned int            mode;
>> +     const char *const       *function_modes;
>> +     unsigned int            num_function_modes;
>> +
>> +     struct iio_counter_trigger      *triggers;
>> +     size_t                          num_triggers;
>> +
>> +     struct iio_enum         function_enum;
>> +};
>> +
>> +struct iio_counter;
>> +
>> +/**
>> + * struct iio_counter_ops - IIO Counter related callbacks
>> + * @signal_read:     function to request a signal value from the device.
>> + *                   Return value will specify the type of value returned by
>> + *                   the device. val and val2 will contain the elements
>> + *                   making up the returned value.
>
> Add some detail on the importance of the return value.
>
>> + * @signal_write:    function to write a signal value to the device.
>> + *                      Parameters are interpreted the same as signal_read.
>
> You need a means of establishing the correct format for write (we needed it
> in IIO fairly early on too)
>
>> + * @trigger_mode_set:        function to set the trigger mode. mode is the index of
>> + *                   the requested mode from the value trigger_modes array.
>> + * @trigger_mode_get:        function to get the current trigger mode. Return value
>> + *                   will specify the index of the current mode from the
>> + *                   value trigger_modes array.
>> + * @value_read:              function to request a value value from the device.
>> + *                   Return value will specify the type of value returned by
>> + *                   the device. val and val2 will contain the elements
>> + *                   making up the returned value.
>> + * @value_write:     function to write a value value to the device.
>> + *                      Parameters are interpreted the same as value_read.
>> + * @value_function_set: function to set the value function mode. mode is the
>> + *                   index of the requested mode from the value
>> + *                   function_modes array.
>> + * @value_function_get: function to get the current value function mode. Return
>> + *                   value will specify the index of the current mode from
>> + *                   the value function_modes array.
>> + */
>> +struct iio_counter_ops {
>> +     int (*signal_read)(struct iio_counter *counter,
>> +             struct iio_counter_signal *signal, int *val, int *val2);
>> +     int (*signal_write)(struct iio_counter *counter,
>> +             struct iio_counter_signal *signal, int val, int val2);
>> +     int (*trigger_mode_set)(struct iio_counter *counter,
>> +             struct iio_counter_value *value,
>> +             struct iio_counter_trigger *trigger, unsigned int mode);
>> +     int (*trigger_mode_get)(struct iio_counter *counter,
>> +             struct iio_counter_value *value,
>> +             struct iio_counter_trigger *trigger);
>> +     int (*value_read)(struct iio_counter *counter,
>> +             struct iio_counter_value *value, int *val, int *val2);
>> +     int (*value_write)(struct iio_counter *counter,
>> +             struct iio_counter_value *value, int val, int val2);
>> +     int (*value_function_set)(struct iio_counter *counter,
>> +             struct iio_counter_value *value, unsigned int mode);
>> +     int (*value_function_get)(struct iio_counter *counter,
>> +             struct iio_counter_value *value);
>> +};
>> +
>> +/**
>> + * struct iio_counter - IIO Counter data structure
>> + * @id:                      [DRIVER] unique ID used to identify counter
>> + * @name:            [DRIVER] name of the device
>> + * @dev:             [DRIVER] device structure, should be assigned a parent
>> + *                   and owner
>> + * @ops:             [DRIVER] callbacks from driver for counter components
>> + * @signals:         [DRIVER] array of signals for initialization
>> + * @num_signals:     [DRIVER] number of signals specified in @signals
>> + * @values:          [DRIVER] array of values for initialization
>> + * @num_values:              [DRIVER] number of values specified in @values
>> + * @channels:                [DRIVER] channel specification structure table
>> + * @num_channels:    [DRIVER] number of channels specified in @channels
>> + * @info:            [DRIVER] callbacks and constant info from driver
>> + * @indio_dev:               [INTERN] industrial I/O device structure
>> + * @driver_data:     [DRIVER] driver data
>> + */
>> +struct iio_counter {
>
> Mentioned earlier - I think naming the device counter, is confusing.
> The counters should be named counter - call it iio_counter_device
> or iio_counter_group or something and keep counter for the things
> currently called value.
>
>> +     int                             id;
>> +     const char                      *name;
>> +     struct device                   *dev;
>> +     const struct iio_counter_ops    *ops;
>> +
>> +     struct iio_counter_signal       *signals;
>> +     size_t                          num_signals;
>> +     struct iio_counter_value        *values;
>> +     size_t                          num_values;
>> +
>> +     const struct iio_chan_spec      *channels;
>> +     size_t                          num_channels;
>> +     const struct iio_info           *info;
>> +
>> +     struct iio_dev  *indio_dev;
>> +     void            *driver_data;
>> +};
>> +
>> +int iio_counter_register(struct iio_counter *const counter);
>> +void iio_counter_unregister(struct iio_counter *const counter);
>> +int devm_iio_counter_register(struct device *dev,
>> +     struct iio_counter *const counter);
>> +void devm_iio_counter_unregister(struct device *dev,
>> +     struct iio_counter *const counter);
>> +
>> +#endif /* CONFIG_IIO_COUNTER */
>> +
>> +#endif /* _IIO_COUNTER_H_ */
>



-- 
Benjamin Gaignard

Graphic Study Group

Linaro.org │ Open source software for ARM SoCs

Follow Linaro: Facebook | Twitter | Blog

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ