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 20 struct iio_map_internal { 21 struct iio_dev *indio_dev; 22 struct iio_map *map; 23 struct list_head l; 24 }; 25 26 static LIST_HEAD(iio_map_list); 27 static DEFINE_MUTEX(iio_map_list_lock); 28 29 int 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 } 49 error_ret: 50 mutex_unlock(&iio_map_list_lock); 51 52 return ret; 53 } 54 EXPORT_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 */ 61 int 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 } 87 error_ret: 88 mutex_unlock(&iio_map_list_lock); 89 90 return ret; 91 } 92 EXPORT_SYMBOL_GPL(iio_map_array_unregister); 93 94 static 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 110 struct 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 } 146 EXPORT_SYMBOL_GPL(iio_channel_get); 147 148 void iio_channel_release(struct iio_channel *channel) 149 { 150 iio_device_put(channel->indio_dev); 151 kfree(channel); 152 } 153 EXPORT_SYMBOL_GPL(iio_channel_release); 154 155 struct 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 209 error_free_chans: 210 for (i = 0; i < nummaps; i++) 211 iio_device_put(chans[i].indio_dev); 212 kfree(chans); 213 error_ret: 214 mutex_unlock(&iio_map_list_lock); 215 216 return ERR_PTR(ret); 217 } 218 EXPORT_SYMBOL_GPL(iio_channel_get_all); 219 220 void 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 } 230 EXPORT_SYMBOL_GPL(iio_channel_release_all); 231 232 int 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); 244 err_unlock: 245 mutex_unlock(&chan->indio_dev->info_exist_lock); 246 247 return ret; 248 } 249 EXPORT_SYMBOL_GPL(iio_read_channel_raw); 250 251 int 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); 265 err_unlock: 266 mutex_unlock(&chan->indio_dev->info_exist_lock); 267 268 return ret; 269 } 270 EXPORT_SYMBOL_GPL(iio_read_channel_scale); 271 272 int 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; 284 err_unlock: 285 mutex_unlock(&chan->indio_dev->info_exist_lock); 286 287 return ret; 288 } 289 EXPORT_SYMBOL_GPL(iio_get_channel_type); 290