blob: e86c2a562385c5919de99f856d16ab4e6ee5e3f2 [file] [log] [blame]
Paul Cercueilbb4401d2014-02-28 16:10:49 +01001/*
2 * libiio - Library for interfacing industrial I/O (IIO) devices
3 *
4 * Copyright (C) 2014 Analog Devices, Inc.
5 * Author: Paul Cercueil <paul.cercueil@analog.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * */
18
Paul Cercueil0b2ce712014-02-17 15:04:18 +010019#include "debug.h"
20#include "iio-private.h"
21
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020022#include <arpa/inet.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010023#include <dirent.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010024#include <errno.h>
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020025#include <poll.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010026#include <stdbool.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010027#include <stddef.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010028#include <stdio.h>
29#include <string.h>
Paul Cercueil92f46df2014-04-28 13:17:53 +020030#include <sys/ioctl.h>
31#include <sys/mman.h>
Paul Cercueil1be57832014-03-11 16:27:16 +010032#include <sys/types.h>
33#include <sys/stat.h>
34#include <unistd.h>
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +020035#include <string.h>
Lars-Peter Clausen00f80092014-07-01 17:52:05 +020036#include <sys/utsname.h>
Paul Cercueil0b2ce712014-02-17 15:04:18 +010037
Paul Cercueile1e0a8f2014-06-10 15:40:29 +020038#define DEFAULT_TIMEOUT_MS 1000
39
Paul Cercueil0b2ce712014-02-17 15:04:18 +010040#define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
Paul Cercueil71694c72014-05-22 14:02:13 +020041#define BIT(x) (1 << (x))
Paul Cercueil0b2ce712014-02-17 15:04:18 +010042
Paul Cercueil92f46df2014-04-28 13:17:53 +020043#define NB_BLOCKS 4
44
45#define BLOCK_ALLOC_IOCTL _IOWR('i', 0xa0, struct block_alloc_req)
46#define BLOCK_FREE_IOCTL _IO('i', 0xa1)
47#define BLOCK_QUERY_IOCTL _IOWR('i', 0xa2, struct block)
48#define BLOCK_ENQUEUE_IOCTL _IOWR('i', 0xa3, struct block)
49#define BLOCK_DEQUEUE_IOCTL _IOWR('i', 0xa4, struct block)
50
Paul Cercueil71694c72014-05-22 14:02:13 +020051#define BLOCK_FLAG_CYCLIC BIT(1)
52
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020053/* Forward declarations */
54static ssize_t local_read_dev_attr(const struct iio_device *dev,
55 const char *attr, char *dst, size_t len, bool is_debug);
56static ssize_t local_read_chn_attr(const struct iio_channel *chn,
57 const char *attr, char *dst, size_t len);
Paul Cercueil1da28122014-05-22 10:59:49 +020058static ssize_t local_write_dev_attr(const struct iio_device *dev,
59 const char *attr, const char *src, size_t len, bool is_debug);
60static ssize_t local_write_chn_attr(const struct iio_channel *chn,
61 const char *attr, const char *src, size_t len);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020062
Paul Cercueil92f46df2014-04-28 13:17:53 +020063struct block_alloc_req {
64 uint32_t type,
65 size,
66 count,
67 id;
68};
69
70struct block {
71 uint32_t id,
72 size,
73 bytes_used,
74 type,
75 flags,
76 offset;
77 uint64_t timestamp;
78};
79
Paul Cercueileaab6582014-02-21 09:35:59 +010080struct iio_device_pdata {
Paul Cercueil44010ea2014-02-21 11:47:04 +010081 FILE *f;
Paul Cercueil71694c72014-05-22 14:02:13 +020082 unsigned int samples_count, nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +020083
84 struct block blocks[NB_BLOCKS];
85 void *addrs[NB_BLOCKS];
86 int last_dequeued;
Paul Cercueil6ea8a752014-06-03 11:35:35 +020087 bool is_high_speed, cyclic, cyclic_buffer_enqueued, buffer_enabled;
Paul Cercueileaab6582014-02-21 09:35:59 +010088};
89
Paul Cercueil0b2ce712014-02-17 15:04:18 +010090static const char * const device_attrs_blacklist[] = {
91 "dev",
92 "uevent",
93};
94
95static const char * const modifier_names[] = {
96 [IIO_MOD_X] = "x",
97 [IIO_MOD_Y] = "y",
98 [IIO_MOD_Z] = "z",
99 [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
100 [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
101 [IIO_MOD_LIGHT_BOTH] = "both",
102 [IIO_MOD_LIGHT_IR] = "ir",
103 [IIO_MOD_LIGHT_CLEAR] = "clear",
104 [IIO_MOD_LIGHT_RED] = "red",
105 [IIO_MOD_LIGHT_GREEN] = "green",
106 [IIO_MOD_LIGHT_BLUE] = "blue",
107};
108
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100109static void local_shutdown(struct iio_context *ctx)
110{
Paul Cercueil42d12352014-05-05 16:11:58 +0200111 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100112 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200113 for (i = 0; i < ctx->nb_devices; i++)
114 free(ctx->devices[i]->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100115}
116
Michael Hennerich1c8aa572014-11-06 17:42:30 +0100117/** Shrinks the first nb characters of a string
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100118 * e.g. strcut("foobar", 4) replaces the content with "ar". */
119static void strcut(char *str, int nb)
120{
121 char *ptr = str + nb;
122 while (*ptr)
123 *str++ = *ptr++;
124 *str = 0;
125}
126
127static int set_channel_name(struct iio_channel *chn)
128{
129 if (chn->nb_attrs < 2)
130 return 0;
131
132 while (true) {
133 bool can_fix = true;
134 unsigned int i, len;
135 char *name;
Paul Cercueilb34e0222014-05-05 15:32:38 +0200136 const char *attr0 = chn->attrs[0].name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100137 const char *ptr = strchr(attr0, '_');
138 if (!ptr)
139 break;
140
141 len = ptr - attr0;
142 for (i = 1; can_fix && i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200143 can_fix = !strncmp(attr0, chn->attrs[i].name, len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100144
145 if (!can_fix)
146 break;
147
148 if (chn->name) {
Paul Cercueil8c29e412014-04-07 09:46:45 +0200149 size_t nlen = strlen(chn->name) + len + 2;
150 name = malloc(nlen);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100151 if (!name)
152 return -ENOMEM;
Paul Cercueil8c29e412014-04-07 09:46:45 +0200153 snprintf(name, nlen, "%s_%.*s", chn->name, len, attr0);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100154 DEBUG("Fixing name of channel %s from %s to %s\n",
155 chn->id, chn->name, name);
Paul Cercueilbb618272014-02-20 11:35:52 +0100156 free(chn->name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100157 } else {
158 name = malloc(len + 2);
159 if (!name)
160 return -ENOMEM;
Paul Cercueil8c29e412014-04-07 09:46:45 +0200161 snprintf(name, len + 2, "%.*s", len, attr0);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100162 DEBUG("Setting name of channel %s to %s\n",
163 chn->id, name);
164 }
165 chn->name = name;
166
167 /* Shrink the attribute name */
168 for (i = 0; i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200169 strcut(chn->attrs[i].name, len + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100170 }
171
172 if (chn->name) {
173 unsigned int i;
174 for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
175 unsigned int len;
176
177 if (!modifier_names[i])
178 continue;
179
180 len = strlen(modifier_names[i]);
181 if (!strncmp(chn->name, modifier_names[i], len)) {
182 if (chn->name[len]) {
183 /* Shrink the modifier from the extended name */
Paul Cercueilbb618272014-02-20 11:35:52 +0100184 strcut(chn->name, len + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100185 } else {
Paul Cercueilbb618272014-02-20 11:35:52 +0100186 free(chn->name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100187 chn->name = NULL;
188 }
189 chn->modifier = i;
190 DEBUG("Detected modifier for channel %s: %s\n",
191 chn->id, modifier_names[i]);
192 break;
193 }
194 }
195 }
196 return 0;
197}
198
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200199static int device_check_ready(const struct iio_device *dev, bool do_write)
200{
201 struct pollfd pollfd = {
202 .fd = fileno(dev->pdata->f),
203 .events = do_write ? POLLOUT : POLLIN,
204 };
205 int ret = poll(&pollfd, 1, dev->ctx->rw_timeout_ms);
206 if (ret < 0)
207 return -errno;
208 if (!ret)
209 return -ETIMEDOUT;
210 if (pollfd.revents & POLLNVAL)
211 return -EBADF;
212 if (!(pollfd.revents & (do_write ? POLLOUT : POLLIN)))
213 return -EIO;
214 return 0;
215}
216
Paul Cercueil45c575d2014-03-20 15:14:01 +0100217static ssize_t local_read(const struct iio_device *dev,
218 void *dst, size_t len, uint32_t *mask, size_t words)
Paul Cercueil44010ea2014-02-21 11:47:04 +0100219{
220 ssize_t ret;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200221 struct iio_device_pdata *pdata = dev->pdata;
222 FILE *f = pdata->f;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100223 if (!f)
224 return -EBADF;
Paul Cercueilff778232014-03-24 14:23:08 +0100225 if (words != dev->words)
Paul Cercueil45c575d2014-03-20 15:14:01 +0100226 return -EINVAL;
227
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200228 if (!pdata->buffer_enabled) {
229 ret = local_write_dev_attr(dev,
230 "buffer/enable", "1", 2, false);
231 if (ret < 0)
232 return ret;
233 else
234 pdata->buffer_enabled = true;
235 }
236
Lars-Peter Clausen666cfe52014-07-14 11:43:15 +0200237 ret = device_check_ready(dev, false);
238 if (ret < 0)
239 return ret;
240
Paul Cercueilff778232014-03-24 14:23:08 +0100241 memcpy(mask, dev->mask, words);
Paul Cercueil44010ea2014-02-21 11:47:04 +0100242 ret = fread(dst, 1, len, f);
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200243 fflush(f);
244 if (ferror(f))
245 ret = -errno;
246 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100247}
248
249static ssize_t local_write(const struct iio_device *dev,
250 const void *src, size_t len)
251{
252 ssize_t ret;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200253 struct iio_device_pdata *pdata = dev->pdata;
254 FILE *f = pdata->f;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100255 if (!f)
256 return -EBADF;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200257
Paul Cercueil91d25ac2014-05-27 10:52:42 +0200258 /* Writing is forbidden in cyclic mode with devices without the
259 * high-speed mmap interface, except for the devices starting with
260 * "cf-": in this case only cyclic mode is allowed. */
Paul Cercueild9d9e4d2014-05-27 11:49:35 +0200261 if (!pdata->is_high_speed && pdata->cyclic !=
262 (dev->name && !strncmp(dev->name, "cf-", 3)))
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200263 return -EACCES;
264
Paul Cercueilafff89b2014-06-12 14:12:42 +0200265 /* We use write() instead of fwrite() here, to avoid the internal
266 * buffering of the FILE API. This ensures that a waveform written in
267 * cyclic mode will be written in only one system call, as the kernel
268 * sizes the buffer according to the length of the first write. */
Paul Cercueil82139cc2014-09-02 15:51:00 +0200269 if (pdata->cyclic) {
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200270 ret = device_check_ready(dev, true);
271 if (ret < 0)
272 return ret;
273
Paul Cercueil82139cc2014-09-02 15:51:00 +0200274 ret = write(fileno(f), src, len);
275 if (ret < 0)
276 return -errno;
277 }
278
279 if (!pdata->buffer_enabled) {
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200280 ssize_t err = local_write_dev_attr(dev,
281 "buffer/enable", "1", 2, false);
282 if (err < 0)
283 return err;
284 else
285 pdata->buffer_enabled = true;
286 }
Paul Cercueil82139cc2014-09-02 15:51:00 +0200287
288 /* In cyclic mode, the buffer must be enabled after writing the samples.
289 * In non-cyclic mode, it must be enabled before writing the samples. */
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200290 if (!pdata->cyclic) {
291 ret = device_check_ready(dev, true);
292 if (ret < 0)
293 return ret;
294
Paul Cercueil82139cc2014-09-02 15:51:00 +0200295 ret = write(fileno(f), src, len);
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200296 }
Paul Cercueil82139cc2014-09-02 15:51:00 +0200297
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200298 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100299}
300
Paul Cercueil92f46df2014-04-28 13:17:53 +0200301static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100302 void **addr_ptr, size_t bytes_used,
303 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200304{
305 struct block block;
306 struct iio_device_pdata *pdata = dev->pdata;
307 FILE *f = pdata->f;
308 ssize_t ret;
309
310 if (!pdata->is_high_speed)
311 return -ENOSYS;
312 if (!f)
313 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200314 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200315 return -EINVAL;
316
Paul Cercueil92f46df2014-04-28 13:17:53 +0200317 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200318 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200319
320 if (pdata->cyclic) {
321 if (pdata->cyclic_buffer_enqueued)
322 return -EBUSY;
323 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
324 pdata->cyclic_buffer_enqueued = true;
325 }
326
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200327 last_block->bytes_used = bytes_used;
328 ret = (ssize_t) ioctl(fileno(f),
329 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200330 if (ret) {
331 ret = (ssize_t) -errno;
332 ERROR("Unable to enqueue block: %s\n", strerror(errno));
333 return ret;
334 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200335
336 if (pdata->cyclic) {
337 *addr_ptr = pdata->addrs[pdata->last_dequeued];
338 return (ssize_t) last_block->bytes_used;
339 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200340 }
341
342 ret = (ssize_t) ioctl(fileno(f), BLOCK_DEQUEUE_IOCTL, &block);
343 if (ret) {
344 ret = (ssize_t) -errno;
345 ERROR("Unable to dequeue block: %s\n", strerror(errno));
346 return ret;
347 }
348
Paul Cercueil558ade42014-11-27 10:59:48 +0100349 /* Requested buffer size is too big! */
350 if (pdata->last_dequeued < 0 && bytes_used != block.size)
351 return -EFBIG;
352
Paul Cercueil92f46df2014-04-28 13:17:53 +0200353 pdata->last_dequeued = block.id;
354 *addr_ptr = pdata->addrs[block.id];
355 return (ssize_t) block.bytes_used;
356}
357
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200358static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
359 char *dst, size_t len, bool is_debug)
360{
361 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
362 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
363 char *ptr = dst;
364
365 for (i = 0; len >= 4 && i < nb; i++) {
366 /* Recursive! */
367 ssize_t ret = local_read_dev_attr(dev, attrs[i],
368 ptr + 4, len - 4, is_debug);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200369 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200370
371 /* Align the length to 4 bytes */
372 if (ret > 0 && ret & 3)
373 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200374 ptr += 4 + (ret < 0 ? 0 : ret);
375 len -= 4 + (ret < 0 ? 0 : ret);
376 }
377
378 return ptr - dst;
379}
380
381static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
382 char *dst, size_t len)
383{
384 unsigned int i;
385 char *ptr = dst;
386
387 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
388 /* Recursive! */
389 ssize_t ret = local_read_chn_attr(chn,
390 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200391 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200392
393 /* Align the length to 4 bytes */
394 if (ret > 0 && ret & 3)
395 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200396 ptr += 4 + (ret < 0 ? 0 : ret);
397 len -= 4 + (ret < 0 ? 0 : ret);
398 }
399
400 return ptr - dst;
401}
402
Paul Cercueil1da28122014-05-22 10:59:49 +0200403static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
404{
405 while (nb--) {
406 int32_t val;
407
408 if (len < 4)
409 return -EINVAL;
410
411 val = (int32_t) ntohl(*(uint32_t *) src);
412 src += 4;
413 len -= 4;
414
415 if (val > 0) {
416 if ((uint32_t) val > len)
417 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200418
419 /* Align the length to 4 bytes */
420 if (val & 3)
421 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200422 len -= val;
423 src += val;
424 }
425 }
426
427 /* We should have analyzed the whole buffer by now */
428 return !len ? 0 : -EINVAL;
429}
430
431static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
432 const char *src, size_t len, bool is_debug)
433{
434 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
435 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
436 const char *ptr = src;
437
438 /* First step: Verify that the buffer is in the correct format */
439 if (local_buffer_analyze(nb, src, len))
440 return -EINVAL;
441
442 /* Second step: write the attributes */
443 for (i = 0; i < nb; i++) {
444 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
445 ptr += 4;
446
447 if (val > 0) {
448 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200449
450 /* Align the length to 4 bytes */
451 if (val & 3)
452 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200453 ptr += val;
454 }
455 }
456
457 return ptr - src;
458}
459
460static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
461 const char *src, size_t len)
462{
463 unsigned int i, nb = chn->nb_attrs;
464 const char *ptr = src;
465
466 /* First step: Verify that the buffer is in the correct format */
467 if (local_buffer_analyze(nb, src, len))
468 return -EINVAL;
469
470 /* Second step: write the attributes */
471 for (i = 0; i < nb; i++) {
472 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
473 ptr += 4;
474
475 if (val > 0) {
476 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200477
478 /* Align the length to 4 bytes */
479 if (val & 3)
480 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200481 ptr += val;
482 }
483 }
484
485 return ptr - src;
486}
487
Paul Cercueil167d3112014-02-18 12:23:53 +0100488static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200489 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100490{
Paul Cercueil3e898302014-02-17 16:17:11 +0100491 FILE *f;
492 char buf[1024];
493 ssize_t ret;
494
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200495 if (!attr)
496 return local_read_all_dev_attrs(dev, dst, len, is_debug);
497
Paul Cercueil50c762a2014-04-14 15:55:43 +0200498 if (is_debug)
499 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
500 dev->id, attr);
501 else
502 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
503 dev->id, attr);
Paul Cercueil3e898302014-02-17 16:17:11 +0100504 f = fopen(buf, "r");
505 if (!f)
506 return -errno;
507
508 ret = fread(dst, 1, len, f);
509 if (ret > 0)
510 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100511 fflush(f);
512 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200513 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100514 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200515 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100516}
517
Paul Cercueil167d3112014-02-18 12:23:53 +0100518static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200519 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100520{
Paul Cercueil3e898302014-02-17 16:17:11 +0100521 FILE *f;
522 char buf[1024];
523 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100524
Paul Cercueil1da28122014-05-22 10:59:49 +0200525 if (!attr)
526 return local_write_all_dev_attrs(dev, src, len, is_debug);
527
Paul Cercueil50c762a2014-04-14 15:55:43 +0200528 if (is_debug)
529 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
530 dev->id, attr);
531 else
532 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
533 dev->id, attr);
Andrea Galbusera7f83b832014-07-25 18:23:36 +0200534 f = fopen(buf, "w");
Paul Cercueil3e898302014-02-17 16:17:11 +0100535 if (!f)
536 return -errno;
537
538 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100539 fflush(f);
540 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200541 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100542 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200543 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100544}
545
Paul Cercueil167d3112014-02-18 12:23:53 +0100546static const char * get_filename(const struct iio_channel *chn,
547 const char *attr)
548{
Paul Cercueil167d3112014-02-18 12:23:53 +0100549 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200550 for (i = 0; i < chn->nb_attrs; i++)
551 if (!strcmp(attr, chn->attrs[i].name))
552 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100553 return attr;
554}
555
556static ssize_t local_read_chn_attr(const struct iio_channel *chn,
557 const char *attr, char *dst, size_t len)
558{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200559 if (!attr)
560 return local_read_all_chn_attrs(chn, dst, len);
561
Paul Cercueil167d3112014-02-18 12:23:53 +0100562 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200563 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100564}
565
566static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200567 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100568{
Paul Cercueil1da28122014-05-22 10:59:49 +0200569 if (!attr)
570 return local_write_all_chn_attrs(chn, src, len);
571
Paul Cercueil167d3112014-02-18 12:23:53 +0100572 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200573 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100574}
575
Paul Cercueilff778232014-03-24 14:23:08 +0100576static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100577{
Paul Cercueilff778232014-03-24 14:23:08 +0100578 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueilcecda352014-05-06 18:14:29 +0200579 ssize_t ret = local_write_chn_attr(chn, "en", en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100580 if (ret < 0)
581 return (int) ret;
582 else
583 return 0;
584}
585
Paul Cercueil92f46df2014-04-28 13:17:53 +0200586static int enable_high_speed(const struct iio_device *dev)
587{
588 struct block_alloc_req req;
589 struct iio_device_pdata *pdata = dev->pdata;
590 unsigned int i;
591 int ret, fd = fileno(pdata->f);
592
Paul Cercueil71694c72014-05-22 14:02:13 +0200593 if (pdata->cyclic) {
594 pdata->nb_blocks = 1;
595 DEBUG("Enabling cyclic mode\n");
596 } else {
597 pdata->nb_blocks = NB_BLOCKS;
598 DEBUG("Cyclic mode not enabled\n");
599 }
600
Paul Cercueil92f46df2014-04-28 13:17:53 +0200601 req.type = 0;
602 req.size = pdata->samples_count *
603 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200604 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200605
606 ret = ioctl(fd, BLOCK_ALLOC_IOCTL, &req);
607 if (ret < 0)
608 return -errno;
609
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200610 /* We might get less blocks than what we asked for */
611 pdata->nb_blocks = req.count;
612
Paul Cercueil92f46df2014-04-28 13:17:53 +0200613 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200614 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200615 pdata->blocks[i].id = i;
616 ret = ioctl(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
617 if (ret) {
618 ret = -errno;
619 goto err_munmap;
620 }
621
622 ret = ioctl(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
623 if (ret) {
624 ret = -errno;
625 goto err_munmap;
626 }
627
Paul Cercueil032a5652014-05-12 17:11:19 +0200628 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
629 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200630 MAP_SHARED, fd, pdata->blocks[i].offset);
631 if (pdata->addrs[i] == MAP_FAILED) {
632 ret = -errno;
633 goto err_munmap;
634 }
635 }
636
Paul Cercueil4a702d32014-05-12 17:02:37 +0200637 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200638 return 0;
639
640err_munmap:
641 for (; i > 0; i--)
642 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
643 ioctl(fd, BLOCK_FREE_IOCTL, 0);
644 return ret;
645}
646
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +0200647/* Some broken drivers expect length in bytes rather than samples */
648static bool local_length_in_bytes(const struct iio_device *dev)
649{
650 const char *name = iio_device_get_name(dev);
651
652 if (!strncmp("ad-mc-", name, 5))
653 return true;
654
655 return false;
656}
657
Paul Cercueil71694c72014-05-22 14:02:13 +0200658static int local_open(const struct iio_device *dev, size_t samples_count,
659 uint32_t *mask, size_t nb, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100660{
661 unsigned int i;
662 int ret;
663 char buf[1024];
664 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200665 bool write_scan_elements = true;
666
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100667 if (pdata->f)
668 return -EBUSY;
669
Paul Cercueilff778232014-03-24 14:23:08 +0100670 if (nb != dev->words)
Paul Cercueile1311222014-03-12 15:46:16 +0100671 return -EINVAL;
672
Paul Cercueilcecda352014-05-06 18:14:29 +0200673 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200674 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100675 return ret;
676
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +0200677 if (local_length_in_bytes(dev))
678 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count *
679 iio_device_get_sample_size_mask(dev, mask, nb));
680 else
681 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200682 ret = local_write_dev_attr(dev, "buffer/length",
683 buf, strlen(buf) + 1, false);
684 if (ret < 0)
685 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200686
Paul Cercueil8c29e412014-04-07 09:46:45 +0200687 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100688 pdata->f = fopen(buf, "r+");
689 if (!pdata->f)
690 return -errno;
691
Paul Cercueilff778232014-03-24 14:23:08 +0100692 memcpy(dev->mask, mask, nb);
693
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200694 /* There was a bug in older kernel versions that cause the kernel to
695 * crash if the scan_elements _en file for a channel was set to 1, so
696 * try to avoid that */
697 if (cyclic) {
698 unsigned int major, minor;
699 struct utsname uts;
700 uname(&uts);
701 sscanf(uts.release, "%u.%u", &major, &minor);
702 if (major < 2 || (major == 3 && minor < 14))
703 write_scan_elements = false;
704 }
705
706
707 if (write_scan_elements) {
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100708 /* Disable channels */
709 for (i = 0; i < dev->nb_channels; i++) {
710 struct iio_channel *chn = dev->channels[i];
711 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
712 ret = channel_write_state(chn);
713 if (ret < 0)
714 goto err_close;
715 }
716 }
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200717 /* Enable channels */
718 for (i = 0; i < dev->nb_channels; i++) {
719 struct iio_channel *chn = dev->channels[i];
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100720 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200721 ret = channel_write_state(chn);
722 if (ret < 0)
723 goto err_close;
724 }
Paul Cercueile1311222014-03-12 15:46:16 +0100725 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100726 }
727
Paul Cercueil71694c72014-05-22 14:02:13 +0200728 pdata->cyclic = cyclic;
729 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200730 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200731 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200732 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200733
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200734 if (!pdata->is_high_speed) {
Paul Cercueil032a5652014-05-12 17:11:19 +0200735 WARNING("High-speed mode not enabled\n");
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200736 } else {
737 /* NOTE: The low-speed interface will enable the buffer after
738 * the first samples are written */
739 ret = local_write_dev_attr(dev, "buffer/enable", "1", 2, false);
740 if (ret < 0)
741 goto err_close;
742 pdata->buffer_enabled = true;
743 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100744
Paul Cercueil45c575d2014-03-20 15:14:01 +0100745 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100746err_close:
747 fclose(pdata->f);
748 pdata->f = NULL;
749 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100750}
751
752static int local_close(const struct iio_device *dev)
753{
754 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100755 int ret;
756
757 if (!pdata->f)
758 return -EBADF;
759
Paul Cercueil92f46df2014-04-28 13:17:53 +0200760 if (pdata->is_high_speed) {
761 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200762 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200763 munmap(pdata->addrs[i], pdata->blocks[i].size);
764 ioctl(fileno(pdata->f), BLOCK_FREE_IOCTL, 0);
765 }
766
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100767 ret = fclose(pdata->f);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100768 if (ret)
769 return ret;
770
771 pdata->f = NULL;
Paul Cercueil71694c72014-05-22 14:02:13 +0200772 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
773 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100774}
775
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100776static int local_get_trigger(const struct iio_device *dev,
777 const struct iio_device **trigger)
778{
779 char buf[1024];
780 unsigned int i;
781 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200782 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200783 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100784 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100785 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200786 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100787
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200788 if (buf[0] == '\0') {
789 *trigger = NULL;
790 return 0;
791 }
792
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100793 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200794 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100795 const struct iio_device *cur = dev->ctx->devices[i];
796 if (cur->name && !strcmp(cur->name, buf)) {
797 *trigger = cur;
798 return 0;
799 }
800 }
801 return -ENXIO;
802}
803
804static int local_set_trigger(const struct iio_device *dev,
805 const struct iio_device *trigger)
806{
807 ssize_t nb;
808 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200809 nb = local_write_dev_attr(dev, "trigger/current_trigger",
810 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100811 if (nb < 0)
812 return (int) nb;
813 else
814 return 0;
815}
816
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100817static bool is_channel(const char *attr)
818{
819 unsigned int i;
820 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +0100821 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
822 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100823 if (!strncmp(attr, "in_", 3))
824 ptr = strchr(attr + 3, '_');
825 else if (!strncmp(attr, "out_", 4))
826 ptr = strchr(attr + 4, '_');
827 if (!ptr)
828 return false;
829 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
830 return true;
831 for (i = 0; i < ARRAY_SIZE(modifier_names); i++)
832 if (modifier_names[i] && !strncmp(ptr + 1, modifier_names[i],
833 strlen(modifier_names[i])))
834 return true;
835 return false;
836}
837
838static char * get_channel_id(const char *attr)
839{
840 char *res, *ptr;
841 unsigned int i;
842
843 attr = strchr(attr, '_') + 1;
844 ptr = strchr(attr, '_');
845 for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
846 if (modifier_names[i] && !strncmp(ptr + 1, modifier_names[i],
847 strlen(modifier_names[i]))) {
848 ptr = strchr(ptr + 1, '_');
849 break;
850 }
851 }
852
853 res = malloc(ptr - attr + 1);
854 if (!res)
855 return NULL;
856
857 memcpy(res, attr, ptr - attr);
858 res[ptr - attr] = 0;
859 return res;
860}
861
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200862static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100863{
864 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200865 unsigned int i;
866
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100867 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200868 for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
869 if (modifier_names[i] &&
870 !strncmp(ptr, modifier_names[i],
871 strlen(modifier_names[i]))) {
872 ptr = strchr(ptr, '_') + 1;
873 break;
874 }
875 }
876
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200877 if (chn->name) {
878 size_t len = strlen(chn->name);
879 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
880 ptr += len + 1;
881 }
882
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100883 return strdup(ptr);
884}
885
886static int read_device_name(struct iio_device *dev)
887{
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100888 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +0200889 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +0100890 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100891 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +0100892 else if (ret == 0)
893 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100894
Paul Cercueil30430c72014-02-17 16:52:37 +0100895 dev->name = strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100896 if (!dev->name)
897 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +0100898 else
899 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100900}
901
902static int add_attr_to_device(struct iio_device *dev, const char *attr)
903{
Paul Cercueilbb618272014-02-20 11:35:52 +0100904 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100905 unsigned int i;
906
907 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
908 if (!strcmp(device_attrs_blacklist[i], attr))
909 return 0;
910
911 if (!strcmp(attr, "name"))
912 return read_device_name(dev);
913
914 name = strdup(attr);
915 if (!name)
916 return -ENOMEM;
917
918 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
919 if (!attrs) {
920 free(name);
921 return -ENOMEM;
922 }
923
924 attrs[dev->nb_attrs++] = name;
925 dev->attrs = attrs;
926 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
927 return 0;
928}
929
Paul Cercueile3fbd952014-03-11 16:58:33 +0100930static int add_attr_to_channel(struct iio_channel *chn,
931 const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100932{
Paul Cercueilb34e0222014-05-05 15:32:38 +0200933 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200934 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100935 if (!name)
936 return -ENOMEM;
937
Paul Cercueile3fbd952014-03-11 16:58:33 +0100938 fn = strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +0100939 if (!fn)
940 goto err_free_name;
941
Paul Cercueilb34e0222014-05-05 15:32:38 +0200942 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
943 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +0100944 if (!attrs)
945 goto err_free_fn;
946
Paul Cercueil42d12352014-05-05 16:11:58 +0200947 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +0200948 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100949 chn->attrs = attrs;
950 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
951 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +0100952
Paul Cercueil167d3112014-02-18 12:23:53 +0100953err_free_fn:
954 free(fn);
955err_free_name:
956 free(name);
957 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100958}
959
960static int add_channel_to_device(struct iio_device *dev,
961 struct iio_channel *chn)
962{
963 struct iio_channel **channels = realloc(dev->channels,
964 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
965 if (!channels)
966 return -ENOMEM;
967
968 channels[dev->nb_channels++] = chn;
969 dev->channels = channels;
970 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
971 return 0;
972}
973
974static int add_device_to_context(struct iio_context *ctx,
975 struct iio_device *dev)
976{
977 struct iio_device **devices = realloc(ctx->devices,
978 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
979 if (!devices)
980 return -ENOMEM;
981
982 devices[ctx->nb_devices++] = dev;
983 ctx->devices = devices;
984 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
985 return 0;
986}
987
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200988/*
989 * Possible return values:
990 * 0 = Attribute should not be moved to the channel
991 * 1 = Attribute should be moved to the channel and it is a shared attribute
992 * 2 = Attribute should be moved to the channel and it is a private attribute
993 */
994static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100995{
996 unsigned int i, len;
997 char *ptr;
998
Paul Cercueil35a01312014-02-20 10:56:57 +0100999 if (!chn->is_output && !strncmp(attr, "in_", 3))
1000 attr += 3;
1001 else if (chn->is_output && !strncmp(attr, "out_", 4))
1002 attr += 4;
1003 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001004 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001005
1006 ptr = strchr(attr, '_');
1007 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001008 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001009
1010 len = ptr - attr;
1011
1012 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001013 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001014
1015 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001016 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1017 if (chn->name) {
1018 size_t name_len = strlen(chn->name);
1019 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1020 attr[len + 1 + name_len] == '_')
1021 return 2;
1022 }
1023 return 1;
1024 } else if (chn->id[len] != '_') {
1025 return 0;
1026 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001027
1028 for (i = 0; i < ARRAY_SIZE(modifier_names); i++)
1029 if (modifier_names[i] &&
1030 !strncmp(chn->id + len + 1, modifier_names[i],
1031 strlen(modifier_names[i])))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001032 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001033
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001034 return 0;
1035}
1036
1037static int detect_global_attr(struct iio_device *dev, const char *attr,
1038 unsigned int level, bool *match)
1039{
1040 unsigned int i;
1041
1042 *match = false;
1043 for (i = 0; i < dev->nb_channels; i++) {
1044 struct iio_channel *chn = dev->channels[i];
1045 if (is_global_attr(chn, attr) == level) {
1046 int ret;
1047 *match = true;
1048 ret = add_attr_to_channel(chn, attr, attr);
1049 if (ret)
1050 return ret;
1051 }
1052 }
1053
1054 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001055}
1056
1057static int detect_and_move_global_attrs(struct iio_device *dev)
1058{
1059 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001060 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001061
1062 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001063 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001064 bool match;
1065 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001066
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001067 ret = detect_global_attr(dev, attr, 2, &match);
1068 if (ret)
1069 return ret;
1070
1071 if (!match) {
1072 ret = detect_global_attr(dev, attr, 1, &match);
1073 if (ret)
1074 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001075 }
1076
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001077 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001078 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001079 dev->attrs[i] = NULL;
1080 }
1081 }
1082
1083 for (i = 0; i < dev->nb_attrs; i++) {
1084 if (dev->attrs[i])
1085 *ptr++ = dev->attrs[i];
1086 }
1087
1088 dev->nb_attrs = ptr - dev->attrs;
1089 return 0;
1090}
1091
1092static struct iio_channel *create_channel(struct iio_device *dev,
Paul Cercueile3fbd952014-03-11 16:58:33 +01001093 char *id, const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001094{
1095 struct iio_channel *chn = calloc(1, sizeof(*chn));
1096 if (!chn)
1097 return NULL;
1098
Paul Cercueileaab6582014-02-21 09:35:59 +01001099 if (!strncmp(attr, "out_", 4))
Paul Cercueil35a01312014-02-20 10:56:57 +01001100 chn->is_output = true;
Paul Cercueileaab6582014-02-21 09:35:59 +01001101 else if (strncmp(attr, "in_", 3))
Paul Cercueil42d12352014-05-05 16:11:58 +02001102 goto err_free_chn;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001103
1104 chn->dev = dev;
1105 chn->id = id;
1106 chn->modifier = IIO_NO_MOD;
1107
Paul Cercueile3fbd952014-03-11 16:58:33 +01001108 if (!add_attr_to_channel(chn, attr, path))
Paul Cercueileaab6582014-02-21 09:35:59 +01001109 return chn;
1110
Paul Cercueileaab6582014-02-21 09:35:59 +01001111err_free_chn:
1112 free(chn);
1113 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001114}
1115
Paul Cercueile3fbd952014-03-11 16:58:33 +01001116static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001117 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001118{
Paul Cercueil1be57832014-03-11 16:27:16 +01001119 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001120 unsigned int i;
Paul Cercueil1be57832014-03-11 16:27:16 +01001121 struct iio_channel *chn;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001122 char buf[1024], *channel_id;
Paul Cercueil1be57832014-03-11 16:27:16 +01001123 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001124
1125 if (dir_is_scan_elements) {
1126 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001127 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001128 } else {
1129 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001130 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001131
Paul Cercueil1be57832014-03-11 16:27:16 +01001132 if (!is_channel(name))
1133 return add_attr_to_device(dev, name);
1134
1135 channel_id = get_channel_id(name);
1136 if (!channel_id)
1137 return -ENOMEM;
1138
1139 for (i = 0; i < dev->nb_channels; i++) {
1140 chn = dev->channels[i];
Paul Cercueil5248e792014-03-31 14:39:10 +02001141 if (!strcmp(chn->id, channel_id)
1142 && chn->is_output == (name[0] == 'o')) {
Paul Cercueil1be57832014-03-11 16:27:16 +01001143 free(channel_id);
Paul Cercueila91358e2014-04-24 16:40:19 +02001144 ret = add_attr_to_channel(chn, name, path);
1145 chn->is_scan_element = dir_is_scan_elements && !ret;
1146 return ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001147 }
1148 }
1149
Paul Cercueile3fbd952014-03-11 16:58:33 +01001150 chn = create_channel(dev, channel_id, name, path);
Paul Cercueil1be57832014-03-11 16:27:16 +01001151 if (!chn) {
1152 free(channel_id);
1153 return -ENXIO;
1154 }
1155 ret = add_channel_to_device(dev, chn);
1156 if (ret)
1157 free_channel(chn);
Paul Cercueila91358e2014-04-24 16:40:19 +02001158 else
1159 chn->is_scan_element = dir_is_scan_elements;
Paul Cercueil1be57832014-03-11 16:27:16 +01001160 return ret;
1161}
1162
Paul Cercueile3fbd952014-03-11 16:58:33 +01001163static int add_attr_or_channel(void *d, const char *path)
1164{
Paul Cercueila91358e2014-04-24 16:40:19 +02001165 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001166}
1167
1168static int add_scan_element(void *d, const char *path)
1169{
Paul Cercueila91358e2014-04-24 16:40:19 +02001170 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001171}
1172
Paul Cercueil1be57832014-03-11 16:27:16 +01001173static int foreach_in_dir(void *d, const char *path, bool is_dir,
1174 int (*callback)(void *, const char *))
1175{
1176 long name_max;
1177 struct dirent *entry, *result;
1178 DIR *dir = opendir(path);
1179 if (!dir)
1180 return -errno;
1181
1182 name_max = pathconf(path, _PC_NAME_MAX);
1183 if (name_max == -1)
1184 name_max = 255;
1185 entry = malloc(offsetof(struct dirent, d_name) + name_max + 1);
1186 if (!entry) {
1187 closedir(dir);
1188 return -ENOMEM;
1189 }
1190
1191 while (true) {
1192 struct stat st;
1193 char buf[1024];
1194 int ret = readdir_r(dir, entry, &result);
1195 if (ret) {
1196 strerror_r(ret, buf, sizeof(buf));
1197 ERROR("Unable to open directory %s: %s\n", path, buf);
1198 free(entry);
1199 closedir(dir);
Paul Cercueilc57da332015-03-16 17:09:48 +01001200 return -ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001201 }
1202 if (!result)
1203 break;
1204
1205 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1206 if (stat(buf, &st) < 0) {
1207 ret = -errno;
Paul Cercueilc21300c2014-03-13 09:54:14 +01001208 strerror_r(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001209 ERROR("Unable to stat file: %s\n", buf);
1210 free(entry);
1211 closedir(dir);
1212 return ret;
1213 }
1214
1215 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1216 ret = callback(d, buf);
1217 else if (!is_dir && S_ISREG(st.st_mode))
1218 ret = callback(d, buf);
1219 else
1220 continue;
1221
1222 if (ret < 0) {
1223 free(entry);
1224 closedir(dir);
1225 return ret;
1226 }
1227 }
1228
1229 free(entry);
1230 closedir(dir);
1231 return 0;
1232}
1233
Paul Cercueile3fbd952014-03-11 16:58:33 +01001234static int add_scan_elements(struct iio_device *dev, const char *devpath)
1235{
1236 struct stat st;
1237 char buf[1024];
1238 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1239
1240 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1241 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1242 if (ret < 0)
1243 return ret;
1244 }
1245
1246 return 0;
1247}
1248
Paul Cercueil1be57832014-03-11 16:27:16 +01001249static int create_device(void *d, const char *path)
1250{
Paul Cercueilff778232014-03-24 14:23:08 +01001251 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001252 unsigned int i;
1253 int ret;
1254 struct iio_context *ctx = d;
1255 struct iio_device *dev = calloc(1, sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001256 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001257 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001258
Paul Cercueileaab6582014-02-21 09:35:59 +01001259 dev->pdata = calloc(1, sizeof(*dev->pdata));
1260 if (!dev->pdata) {
1261 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001262 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001263 }
1264
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001265 dev->ctx = ctx;
Paul Cercueil1be57832014-03-11 16:27:16 +01001266 dev->id = strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001267 if (!dev->id) {
Paul Cercueileaab6582014-02-21 09:35:59 +01001268 free(dev->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001269 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001270 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001271 }
1272
Paul Cercueil1be57832014-03-11 16:27:16 +01001273 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
1274 if (ret < 0) {
1275 free_device(dev);
1276 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001277 }
1278
Paul Cercueil54913ac2014-03-31 14:48:19 +02001279 for (i = 0; i < dev->nb_channels; i++)
1280 set_channel_name(dev->channels[i]);
1281
Michael Hennerichebe49662014-11-07 10:32:44 +01001282 ret = add_scan_elements(dev, path);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001283 if (ret < 0) {
1284 free_device(dev);
1285 return ret;
1286 }
1287
Michael Hennerichebe49662014-11-07 10:32:44 +01001288 ret = detect_and_move_global_attrs(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001289 if (ret < 0) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001290 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001291 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001292 }
1293
Paul Cercueilff778232014-03-24 14:23:08 +01001294 dev->words = (dev->nb_channels + 31) / 32;
1295 if (dev->words) {
1296 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001297 if (!mask) {
1298 free_device(dev);
1299 return ret;
1300 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001301 }
1302
Paul Cercueilff778232014-03-24 14:23:08 +01001303 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001304
Paul Cercueil1be57832014-03-11 16:27:16 +01001305 ret = add_device_to_context(ctx, dev);
1306 if (ret < 0)
1307 free_device(dev);
1308 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001309}
1310
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001311static int add_debug_attr(void *d, const char *path)
1312{
1313 struct iio_device *dev = d;
1314 const char *attr = strrchr(path, '/') + 1;
1315 char **attrs, *name = strdup(attr);
1316 if (!name)
1317 return -ENOMEM;
1318
1319 attrs = realloc(dev->debug_attrs,
1320 (1 + dev->nb_debug_attrs) * sizeof(char *));
1321 if (!attrs) {
1322 free(name);
1323 return -ENOMEM;
1324 }
1325
1326 attrs[dev->nb_debug_attrs++] = name;
1327 dev->debug_attrs = attrs;
1328 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1329 return 0;
1330}
1331
1332static int add_debug(void *d, const char *path)
1333{
1334 struct iio_context *ctx = d;
1335 const char *name = strrchr(path, '/') + 1;
1336 struct iio_device *dev = iio_context_find_device(ctx, name);
1337 if (!dev)
1338 return -ENODEV;
1339 else
1340 return foreach_in_dir(dev, path, false, add_debug_attr);
1341}
1342
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001343static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1344{
1345 ctx->rw_timeout_ms = timeout;
1346 return 0;
1347}
1348
Paul Cercueil0865e802014-10-28 14:35:19 +01001349static struct iio_context * local_clone(
1350 const struct iio_context *ctx __attribute__((unused)))
1351{
Paul Cercueil63e52182014-12-11 12:52:48 +01001352 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001353}
1354
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001355static struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001356 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001357 .open = local_open,
1358 .close = local_close,
1359 .read = local_read,
1360 .write = local_write,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001361 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001362 .read_device_attr = local_read_dev_attr,
1363 .write_device_attr = local_write_dev_attr,
1364 .read_channel_attr = local_read_chn_attr,
1365 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001366 .get_trigger = local_get_trigger,
1367 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001368 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001369 .set_timeout = local_set_timeout,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001370};
1371
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001372static void init_index(struct iio_channel *chn)
1373{
1374 char buf[1024];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001375 long id = -ENOENT;
1376
1377 if (chn->is_scan_element) {
1378 id = (long) local_read_chn_attr(chn, "index", buf, sizeof(buf));
1379 if (id > 0)
1380 id = atol(buf);
1381 }
1382 chn->index = id;
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001383}
1384
1385static void init_data_format(struct iio_channel *chn)
1386{
1387 char buf[1024];
1388 ssize_t ret;
1389
1390 if (chn->is_scan_element) {
1391 ret = local_read_chn_attr(chn, "type", buf, sizeof(buf));
1392 if (ret < 0) {
1393 chn->format.length = 0;
1394 } else {
1395 char endian, sign;
1396
1397 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
1398 &chn->format.bits, &chn->format.length,
1399 &chn->format.shift);
Michael Hennerichfa3c6f62014-08-13 11:21:23 +02001400 chn->format.is_signed = (sign == 's' || sign == 'S');
1401 chn->format.is_fully_defined =
1402 (sign == 'S' || sign == 'U'||
1403 chn->format.bits == chn->format.length);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001404 chn->format.is_be = endian == 'b';
1405 }
1406 }
1407
1408 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1409 if (ret < 0) {
1410 chn->format.with_scale = false;
1411 } else {
1412 chn->format.with_scale = true;
1413 chn->format.scale = atof(buf);
1414 }
1415}
1416
1417static void init_scan_elements(struct iio_context *ctx)
1418{
1419 unsigned int i, j;
1420
1421 for (i = 0; i < ctx->nb_devices; i++) {
1422 struct iio_device *dev = ctx->devices[i];
1423
1424 for (j = 0; j < dev->nb_channels; j++) {
1425 struct iio_channel *chn = dev->channels[j];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001426 init_index(chn);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001427 init_data_format(chn);
1428 }
1429 }
1430}
1431
Paul Cercueil63e52182014-12-11 12:52:48 +01001432struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001433{
Paul Cercueil1be57832014-03-11 16:27:16 +01001434 int ret;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001435 unsigned int len;
1436 struct utsname uts;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001437 struct iio_context *ctx = calloc(1, sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001438 if (!ctx)
1439 goto err_set_errno_enomem;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001440
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001441 ctx->ops = &local_ops;
1442 ctx->name = "local";
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001443 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001444
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001445 uname(&uts);
1446 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1447 + strlen(uts.version) + strlen(uts.machine);
1448 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1449 if (!ctx->description) {
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001450 free(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001451 goto err_set_errno_enomem;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001452 }
1453
1454 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1455 uts.nodename, uts.release, uts.version, uts.machine);
1456
Paul Cercueil1be57832014-03-11 16:27:16 +01001457 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
1458 if (ret < 0) {
Paul Cercueil1be57832014-03-11 16:27:16 +01001459 iio_context_destroy(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001460 errno = -ret;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001461 return NULL;
1462 }
1463
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001464 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001465
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001466 init_scan_elements(ctx);
Paul Cercueil97679ac2014-06-12 10:08:20 +02001467 iio_context_init(ctx);
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001468
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001469 ctx->xml = iio_context_create_xml(ctx);
1470 if (!ctx->xml) {
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001471 iio_context_destroy(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001472 goto err_set_errno_enomem;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001473 }
Paul Cercueilae88fde2014-03-12 11:47:10 +01001474
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001475 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001476
1477err_set_errno_enomem:
1478 errno = ENOMEM;
1479 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001480}