linux/drivers/iio/inkern.c
<<
>>
Prefs
   1/* The industrial I/O core in kernel channel mapping
   2 *
   3 * Copyright (c) 2011 Jonathan Cameron
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms of the GNU General Public License version 2 as published by
   7 * the Free Software Foundation.
   8 */
   9#include <linux/err.h>
  10#include <linux/export.h>
  11#include <linux/slab.h>
  12#include <linux/mutex.h>
  13
  14#include <linux/iio/iio.h>
  15#include "iio_core.h"
  16#include <linux/iio/machine.h>
  17#include <linux/iio/driver.h>
  18#include <linux/iio/consumer.h>
  19
  20struct iio_map_internal {
  21        struct iio_dev *indio_dev;
  22        struct iio_map *map;
  23        struct list_head l;
  24};
  25
  26static LIST_HEAD(iio_map_list);
  27static DEFINE_MUTEX(iio_map_list_lock);
  28
  29int iio_map_array_register(struct iio_dev *indio_dev, struct iio_map *maps)
  30{
  31        int i = 0, ret = 0;
  32        struct iio_map_internal *mapi;
  33
  34        if (maps == NULL)
  35                return 0;
  36
  37        mutex_lock(&iio_map_list_lock);
  38        while (maps[i].consumer_dev_name != NULL) {
  39                mapi = kzalloc(sizeof(*mapi), GFP_KERNEL);
  40                if (mapi == NULL) {
  41                        ret = -ENOMEM;
  42                        goto error_ret;
  43                }
  44                mapi->map = &maps[i];
  45                mapi->indio_dev = indio_dev;
  46                list_add(&mapi->l, &iio_map_list);
  47                i++;
  48        }
  49error_ret:
  50        mutex_unlock(&iio_map_list_lock);
  51
  52        return ret;
  53}
  54EXPORT_SYMBOL_GPL(iio_map_array_register);
  55
  56
  57/* Assumes the exact same array (e.g. memory locations)
  58 * used at unregistration as used at registration rather than
  59 * more complex checking of contents.
  60 */
  61int iio_map_array_unregister(struct iio_dev *indio_dev,
  62                             struct iio_map *maps)
  63{
  64        int i = 0, ret = 0;
  65        bool found_it;
  66        struct iio_map_internal *mapi;
  67
  68        if (maps == NULL)
  69                return 0;
  70
  71        mutex_lock(&iio_map_list_lock);
  72        while (maps[i].consumer_dev_name != NULL) {
  73                found_it = false;
  74                list_for_each_entry(mapi, &iio_map_list, l)
  75                        if (&maps[i] == mapi->map) {
  76                                list_del(&mapi->l);
  77                                kfree(mapi);
  78                                found_it = true;
  79                                break;
  80                        }
  81                if (found_it == false) {
  82                        ret = -ENODEV;
  83                        goto error_ret;
  84                }
  85                i++;
  86        }
  87error_ret:
  88        mutex_unlock(&iio_map_list_lock);
  89
  90        return ret;
  91}
  92EXPORT_SYMBOL_GPL(iio_map_array_unregister);
  93
  94static const struct iio_chan_spec
  95*iio_chan_spec_from_name(const struct iio_dev *indio_dev, const char *name)
  96{
  97        int i;
  98        const struct iio_chan_spec *chan = NULL;
  99
 100        for (i = 0; i < indio_dev->num_channels; i++)
 101                if (indio_dev->channels[i].datasheet_name &&
 102                    strcmp(name, indio_dev->channels[i].datasheet_name) == 0) {
 103                        chan = &indio_dev->channels[i];
 104                        break;
 105                }
 106        return chan;
 107}
 108
 109
 110struct iio_channel *iio_channel_get(const char *name, const char *channel_name)
 111{
 112        struct iio_map_internal *c_i = NULL, *c = NULL;
 113        struct iio_channel *channel;
 114
 115        if (name == NULL && channel_name == NULL)
 116                return ERR_PTR(-ENODEV);
 117
 118        /* first find matching entry the channel map */
 119        mutex_lock(&iio_map_list_lock);
 120        list_for_each_entry(c_i, &iio_map_list, l) {
 121                if ((name && strcmp(name, c_i->map->consumer_dev_name) != 0) ||
 122                    (channel_name &&
 123                     strcmp(channel_name, c_i->map->consumer_channel) != 0))
 124                        continue;
 125                c = c_i;
 126                iio_device_get(c->indio_dev);
 127                break;
 128        }
 129        mutex_unlock(&iio_map_list_lock);
 130        if (c == NULL)
 131                return ERR_PTR(-ENODEV);
 132
 133        channel = kmalloc(sizeof(*channel), GFP_KERNEL);
 134        if (channel == NULL)
 135                return ERR_PTR(-ENOMEM);
 136
 137        channel->indio_dev = c->indio_dev;
 138
 139        if (c->map->adc_channel_label)
 140                channel->channel =
 141                        iio_chan_spec_from_name(channel->indio_dev,
 142                                                c->map->adc_channel_label);
 143
 144        return channel;
 145}
 146EXPORT_SYMBOL_GPL(iio_channel_get);
 147
 148void iio_channel_release(struct iio_channel *channel)
 149{
 150        iio_device_put(channel->indio_dev);
 151        kfree(channel);
 152}
 153EXPORT_SYMBOL_GPL(iio_channel_release);
 154
 155struct iio_channel *iio_channel_get_all(const char *name)
 156{
 157        struct iio_channel *chans;
 158        struct iio_map_internal *c = NULL;
 159        int nummaps = 0;
 160        int mapind = 0;
 161        int i, ret;
 162
 163        if (name == NULL)
 164                return ERR_PTR(-EINVAL);
 165
 166        mutex_lock(&iio_map_list_lock);
 167        /* first count the matching maps */
 168        list_for_each_entry(c, &iio_map_list, l)
 169                if (name && strcmp(name, c->map->consumer_dev_name) != 0)
 170                        continue;
 171                else
 172                        nummaps++;
 173
 174        if (nummaps == 0) {
 175                ret = -ENODEV;
 176                goto error_ret;
 177        }
 178
 179        /* NULL terminated array to save passing size */
 180        chans = kzalloc(sizeof(*chans)*(nummaps + 1), GFP_KERNEL);
 181        if (chans == NULL) {
 182                ret = -ENOMEM;
 183                goto error_ret;
 184        }
 185
 186        /* for each map fill in the chans element */
 187        list_for_each_entry(c, &iio_map_list, l) {
 188                if (name && strcmp(name, c->map->consumer_dev_name) != 0)
 189                        continue;
 190                chans[mapind].indio_dev = c->indio_dev;
 191                chans[mapind].channel =
 192                        iio_chan_spec_from_name(chans[mapind].indio_dev,
 193                                                c->map->adc_channel_label);
 194                if (chans[mapind].channel == NULL) {
 195                        ret = -EINVAL;
 196                        goto error_free_chans;
 197                }
 198                iio_device_get(chans[mapind].indio_dev);
 199                mapind++;
 200        }
 201        if (mapind == 0) {
 202                ret = -ENODEV;
 203                goto error_free_chans;
 204        }
 205        mutex_unlock(&iio_map_list_lock);
 206
 207        return chans;
 208
 209error_free_chans:
 210        for (i = 0; i < nummaps; i++)
 211                iio_device_put(chans[i].indio_dev);
 212        kfree(chans);
 213error_ret:
 214        mutex_unlock(&iio_map_list_lock);
 215
 216        return ERR_PTR(ret);
 217}
 218EXPORT_SYMBOL_GPL(iio_channel_get_all);
 219
 220void iio_channel_release_all(struct iio_channel *channels)
 221{
 222        struct iio_channel *chan = &channels[0];
 223
 224        while (chan->indio_dev) {
 225                iio_device_put(chan->indio_dev);
 226                chan++;
 227        }
 228        kfree(channels);
 229}
 230EXPORT_SYMBOL_GPL(iio_channel_release_all);
 231
 232int iio_read_channel_raw(struct iio_channel *chan, int *val)
 233{
 234        int val2, ret;
 235
 236        mutex_lock(&chan->indio_dev->info_exist_lock);
 237        if (chan->indio_dev->info == NULL) {
 238                ret = -ENODEV;
 239                goto err_unlock;
 240        }
 241
 242        ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel,
 243                                              val, &val2, 0);
 244err_unlock:
 245        mutex_unlock(&chan->indio_dev->info_exist_lock);
 246
 247        return ret;
 248}
 249EXPORT_SYMBOL_GPL(iio_read_channel_raw);
 250
 251int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2)
 252{
 253        int ret;
 254
 255        mutex_lock(&chan->indio_dev->info_exist_lock);
 256        if (chan->indio_dev->info == NULL) {
 257                ret = -ENODEV;
 258                goto err_unlock;
 259        }
 260
 261        ret = chan->indio_dev->info->read_raw(chan->indio_dev,
 262                                              chan->channel,
 263                                              val, val2,
 264                                              IIO_CHAN_INFO_SCALE);
 265err_unlock:
 266        mutex_unlock(&chan->indio_dev->info_exist_lock);
 267
 268        return ret;
 269}
 270EXPORT_SYMBOL_GPL(iio_read_channel_scale);
 271
 272int iio_get_channel_type(struct iio_channel *chan, enum iio_chan_type *type)
 273{
 274        int ret = 0;
 275        /* Need to verify underlying driver has not gone away */
 276
 277        mutex_lock(&chan->indio_dev->info_exist_lock);
 278        if (chan->indio_dev->info == NULL) {
 279                ret = -ENODEV;
 280                goto err_unlock;
 281        }
 282
 283        *type = chan->channel->type;
 284err_unlock:
 285        mutex_unlock(&chan->indio_dev->info_exist_lock);
 286
 287        return ret;
 288}
 289EXPORT_SYMBOL_GPL(iio_get_channel_type);
 290
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.