blob: 9e7fcd530cca6a3141e8044e63f3c9fe39f2eeef [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 Cercueil92f46df2014-04-28 13:17:53 +020040#define NB_BLOCKS 4
41
42#define BLOCK_ALLOC_IOCTL _IOWR('i', 0xa0, struct block_alloc_req)
43#define BLOCK_FREE_IOCTL _IO('i', 0xa1)
44#define BLOCK_QUERY_IOCTL _IOWR('i', 0xa2, struct block)
45#define BLOCK_ENQUEUE_IOCTL _IOWR('i', 0xa3, struct block)
46#define BLOCK_DEQUEUE_IOCTL _IOWR('i', 0xa4, struct block)
47
Paul Cercueil71694c72014-05-22 14:02:13 +020048#define BLOCK_FLAG_CYCLIC BIT(1)
49
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020050/* Forward declarations */
51static ssize_t local_read_dev_attr(const struct iio_device *dev,
52 const char *attr, char *dst, size_t len, bool is_debug);
53static ssize_t local_read_chn_attr(const struct iio_channel *chn,
54 const char *attr, char *dst, size_t len);
Paul Cercueil1da28122014-05-22 10:59:49 +020055static ssize_t local_write_dev_attr(const struct iio_device *dev,
56 const char *attr, const char *src, size_t len, bool is_debug);
57static ssize_t local_write_chn_attr(const struct iio_channel *chn,
58 const char *attr, const char *src, size_t len);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +020059
Paul Cercueil92f46df2014-04-28 13:17:53 +020060struct block_alloc_req {
61 uint32_t type,
62 size,
63 count,
64 id;
65};
66
67struct block {
68 uint32_t id,
69 size,
70 bytes_used,
71 type,
72 flags,
73 offset;
74 uint64_t timestamp;
75};
76
Paul Cercueileaab6582014-02-21 09:35:59 +010077struct iio_device_pdata {
Paul Cercueil44010ea2014-02-21 11:47:04 +010078 FILE *f;
Paul Cercueil71694c72014-05-22 14:02:13 +020079 unsigned int samples_count, nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +020080
81 struct block blocks[NB_BLOCKS];
82 void *addrs[NB_BLOCKS];
83 int last_dequeued;
Paul Cercueil6ea8a752014-06-03 11:35:35 +020084 bool is_high_speed, cyclic, cyclic_buffer_enqueued, buffer_enabled;
Paul Cercueileaab6582014-02-21 09:35:59 +010085};
86
Paul Cercueil0b2ce712014-02-17 15:04:18 +010087static const char * const device_attrs_blacklist[] = {
88 "dev",
89 "uevent",
90};
91
92static const char * const modifier_names[] = {
93 [IIO_MOD_X] = "x",
94 [IIO_MOD_Y] = "y",
95 [IIO_MOD_Z] = "z",
96 [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
97 [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
98 [IIO_MOD_LIGHT_BOTH] = "both",
99 [IIO_MOD_LIGHT_IR] = "ir",
100 [IIO_MOD_LIGHT_CLEAR] = "clear",
101 [IIO_MOD_LIGHT_RED] = "red",
102 [IIO_MOD_LIGHT_GREEN] = "green",
103 [IIO_MOD_LIGHT_BLUE] = "blue",
Lars-Peter Clausen60aa4042015-03-27 13:34:55 +0100104 [IIO_MOD_I] = "i",
105 [IIO_MOD_Q] = "q",
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100106};
107
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100108/*
109 * Looks for a IIO channel modifier at the beginning of the string s. If a
110 * modifier was found the symbolic constant (IIO_MOD_*) is returned, otherwise
111 * IIO_NO_MOD is returned. If a modifier was found len_p will be update with the
112 * length of the modifier.
113 */
114static unsigned int find_modifier(const char *s, size_t *len_p)
115{
116 unsigned int i;
117 size_t len;
118
119 for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
120 if (!modifier_names[i])
121 continue;
122 len = strlen(modifier_names[i]);
Lars-Peter Clausenf18f3d52015-03-27 13:42:09 +0100123 if (strncmp(s, modifier_names[i], len) == 0 && s[len] == '_') {
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100124 if (len_p)
125 *len_p = len;
126 return i;
127 }
128 }
129
130 return IIO_NO_MOD;
131}
132
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100133static void local_shutdown(struct iio_context *ctx)
134{
Paul Cercueil42d12352014-05-05 16:11:58 +0200135 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100136 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200137 for (i = 0; i < ctx->nb_devices; i++)
138 free(ctx->devices[i]->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100139}
140
Michael Hennerich1c8aa572014-11-06 17:42:30 +0100141/** Shrinks the first nb characters of a string
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100142 * e.g. strcut("foobar", 4) replaces the content with "ar". */
143static void strcut(char *str, int nb)
144{
145 char *ptr = str + nb;
146 while (*ptr)
147 *str++ = *ptr++;
148 *str = 0;
149}
150
151static int set_channel_name(struct iio_channel *chn)
152{
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100153 size_t prefix_len = 0;
154 const char *attr0;
155 const char *ptr;
156 unsigned int i;
157
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100158 if (chn->nb_attrs < 2)
159 return 0;
160
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100161 attr0 = ptr = chn->attrs[0].name;
162
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100163 while (true) {
164 bool can_fix = true;
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100165 size_t len;
166
167 ptr = strchr(ptr, '_');
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100168 if (!ptr)
169 break;
170
171 len = ptr - attr0;
172 for (i = 1; can_fix && i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200173 can_fix = !strncmp(attr0, chn->attrs[i].name, len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100174
175 if (!can_fix)
176 break;
177
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100178 prefix_len = len;
179 ptr = ptr + 1;
180 }
181
182 if (prefix_len) {
183 char *name;
184
185 name = malloc(prefix_len + 1);
186 if (!name)
187 return -ENOMEM;
188 strncpy(name, attr0, prefix_len);
189 name[prefix_len] = '\0';
190 DEBUG("Setting name of channel %s to %s\n", chn->id, name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100191 chn->name = name;
192
193 /* Shrink the attribute name */
194 for (i = 0; i < chn->nb_attrs; i++)
Lars-Peter Clausen816c4262015-03-27 15:57:43 +0100195 strcut(chn->attrs[i].name, prefix_len + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100196 }
197
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100198 return 0;
199}
200
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200201static int device_check_ready(const struct iio_device *dev, bool do_write)
202{
203 struct pollfd pollfd = {
204 .fd = fileno(dev->pdata->f),
205 .events = do_write ? POLLOUT : POLLIN,
206 };
207 int ret = poll(&pollfd, 1, dev->ctx->rw_timeout_ms);
208 if (ret < 0)
209 return -errno;
210 if (!ret)
211 return -ETIMEDOUT;
212 if (pollfd.revents & POLLNVAL)
213 return -EBADF;
214 if (!(pollfd.revents & (do_write ? POLLOUT : POLLIN)))
215 return -EIO;
216 return 0;
217}
218
Paul Cercueil45c575d2014-03-20 15:14:01 +0100219static ssize_t local_read(const struct iio_device *dev,
220 void *dst, size_t len, uint32_t *mask, size_t words)
Paul Cercueil44010ea2014-02-21 11:47:04 +0100221{
222 ssize_t ret;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200223 struct iio_device_pdata *pdata = dev->pdata;
224 FILE *f = pdata->f;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100225 if (!f)
226 return -EBADF;
Paul Cercueilff778232014-03-24 14:23:08 +0100227 if (words != dev->words)
Paul Cercueil45c575d2014-03-20 15:14:01 +0100228 return -EINVAL;
229
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200230 if (!pdata->buffer_enabled) {
231 ret = local_write_dev_attr(dev,
232 "buffer/enable", "1", 2, false);
233 if (ret < 0)
234 return ret;
235 else
236 pdata->buffer_enabled = true;
237 }
238
Lars-Peter Clausen666cfe52014-07-14 11:43:15 +0200239 ret = device_check_ready(dev, false);
240 if (ret < 0)
241 return ret;
242
Paul Cercueilff778232014-03-24 14:23:08 +0100243 memcpy(mask, dev->mask, words);
Paul Cercueil44010ea2014-02-21 11:47:04 +0100244 ret = fread(dst, 1, len, f);
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200245 fflush(f);
246 if (ferror(f))
247 ret = -errno;
248 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100249}
250
251static ssize_t local_write(const struct iio_device *dev,
252 const void *src, size_t len)
253{
254 ssize_t ret;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200255 struct iio_device_pdata *pdata = dev->pdata;
256 FILE *f = pdata->f;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100257 if (!f)
258 return -EBADF;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200259
Paul Cercueil91d25ac2014-05-27 10:52:42 +0200260 /* Writing is forbidden in cyclic mode with devices without the
261 * high-speed mmap interface, except for the devices starting with
262 * "cf-": in this case only cyclic mode is allowed. */
Paul Cercueild9d9e4d2014-05-27 11:49:35 +0200263 if (!pdata->is_high_speed && pdata->cyclic !=
264 (dev->name && !strncmp(dev->name, "cf-", 3)))
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200265 return -EACCES;
266
Paul Cercueilafff89b2014-06-12 14:12:42 +0200267 /* We use write() instead of fwrite() here, to avoid the internal
268 * buffering of the FILE API. This ensures that a waveform written in
269 * cyclic mode will be written in only one system call, as the kernel
270 * sizes the buffer according to the length of the first write. */
Paul Cercueil82139cc2014-09-02 15:51:00 +0200271 if (pdata->cyclic) {
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200272 ret = device_check_ready(dev, true);
273 if (ret < 0)
274 return ret;
275
Paul Cercueil82139cc2014-09-02 15:51:00 +0200276 ret = write(fileno(f), src, len);
277 if (ret < 0)
278 return -errno;
279 }
280
281 if (!pdata->buffer_enabled) {
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200282 ssize_t err = local_write_dev_attr(dev,
283 "buffer/enable", "1", 2, false);
284 if (err < 0)
285 return err;
286 else
287 pdata->buffer_enabled = true;
288 }
Paul Cercueil82139cc2014-09-02 15:51:00 +0200289
290 /* In cyclic mode, the buffer must be enabled after writing the samples.
291 * In non-cyclic mode, it must be enabled before writing the samples. */
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200292 if (!pdata->cyclic) {
293 ret = device_check_ready(dev, true);
294 if (ret < 0)
295 return ret;
296
Paul Cercueil82139cc2014-09-02 15:51:00 +0200297 ret = write(fileno(f), src, len);
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200298 }
Paul Cercueil82139cc2014-09-02 15:51:00 +0200299
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200300 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100301}
302
Paul Cercueil92f46df2014-04-28 13:17:53 +0200303static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100304 void **addr_ptr, size_t bytes_used,
305 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200306{
307 struct block block;
308 struct iio_device_pdata *pdata = dev->pdata;
309 FILE *f = pdata->f;
310 ssize_t ret;
311
312 if (!pdata->is_high_speed)
313 return -ENOSYS;
314 if (!f)
315 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200316 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200317 return -EINVAL;
318
Paul Cercueil92f46df2014-04-28 13:17:53 +0200319 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200320 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200321
322 if (pdata->cyclic) {
323 if (pdata->cyclic_buffer_enqueued)
324 return -EBUSY;
325 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
326 pdata->cyclic_buffer_enqueued = true;
327 }
328
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200329 last_block->bytes_used = bytes_used;
330 ret = (ssize_t) ioctl(fileno(f),
331 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200332 if (ret) {
333 ret = (ssize_t) -errno;
334 ERROR("Unable to enqueue block: %s\n", strerror(errno));
335 return ret;
336 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200337
338 if (pdata->cyclic) {
339 *addr_ptr = pdata->addrs[pdata->last_dequeued];
340 return (ssize_t) last_block->bytes_used;
341 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200342 }
343
344 ret = (ssize_t) ioctl(fileno(f), BLOCK_DEQUEUE_IOCTL, &block);
345 if (ret) {
346 ret = (ssize_t) -errno;
347 ERROR("Unable to dequeue block: %s\n", strerror(errno));
348 return ret;
349 }
350
Paul Cercueil558ade42014-11-27 10:59:48 +0100351 /* Requested buffer size is too big! */
352 if (pdata->last_dequeued < 0 && bytes_used != block.size)
353 return -EFBIG;
354
Paul Cercueil92f46df2014-04-28 13:17:53 +0200355 pdata->last_dequeued = block.id;
356 *addr_ptr = pdata->addrs[block.id];
357 return (ssize_t) block.bytes_used;
358}
359
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200360static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
361 char *dst, size_t len, bool is_debug)
362{
363 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
364 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
365 char *ptr = dst;
366
367 for (i = 0; len >= 4 && i < nb; i++) {
368 /* Recursive! */
369 ssize_t ret = local_read_dev_attr(dev, attrs[i],
370 ptr + 4, len - 4, is_debug);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200371 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200372
373 /* Align the length to 4 bytes */
374 if (ret > 0 && ret & 3)
375 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200376 ptr += 4 + (ret < 0 ? 0 : ret);
377 len -= 4 + (ret < 0 ? 0 : ret);
378 }
379
380 return ptr - dst;
381}
382
383static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
384 char *dst, size_t len)
385{
386 unsigned int i;
387 char *ptr = dst;
388
389 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
390 /* Recursive! */
391 ssize_t ret = local_read_chn_attr(chn,
392 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200393 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200394
395 /* Align the length to 4 bytes */
396 if (ret > 0 && ret & 3)
397 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200398 ptr += 4 + (ret < 0 ? 0 : ret);
399 len -= 4 + (ret < 0 ? 0 : ret);
400 }
401
402 return ptr - dst;
403}
404
Paul Cercueil1da28122014-05-22 10:59:49 +0200405static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
406{
407 while (nb--) {
408 int32_t val;
409
410 if (len < 4)
411 return -EINVAL;
412
413 val = (int32_t) ntohl(*(uint32_t *) src);
414 src += 4;
415 len -= 4;
416
417 if (val > 0) {
418 if ((uint32_t) val > len)
419 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200420
421 /* Align the length to 4 bytes */
422 if (val & 3)
423 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200424 len -= val;
425 src += val;
426 }
427 }
428
429 /* We should have analyzed the whole buffer by now */
430 return !len ? 0 : -EINVAL;
431}
432
433static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
434 const char *src, size_t len, bool is_debug)
435{
436 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
437 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
438 const char *ptr = src;
439
440 /* First step: Verify that the buffer is in the correct format */
441 if (local_buffer_analyze(nb, src, len))
442 return -EINVAL;
443
444 /* Second step: write the attributes */
445 for (i = 0; i < nb; i++) {
446 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
447 ptr += 4;
448
449 if (val > 0) {
450 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200451
452 /* Align the length to 4 bytes */
453 if (val & 3)
454 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200455 ptr += val;
456 }
457 }
458
459 return ptr - src;
460}
461
462static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
463 const char *src, size_t len)
464{
465 unsigned int i, nb = chn->nb_attrs;
466 const char *ptr = src;
467
468 /* First step: Verify that the buffer is in the correct format */
469 if (local_buffer_analyze(nb, src, len))
470 return -EINVAL;
471
472 /* Second step: write the attributes */
473 for (i = 0; i < nb; i++) {
474 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
475 ptr += 4;
476
477 if (val > 0) {
478 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200479
480 /* Align the length to 4 bytes */
481 if (val & 3)
482 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200483 ptr += val;
484 }
485 }
486
487 return ptr - src;
488}
489
Paul Cercueil167d3112014-02-18 12:23:53 +0100490static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200491 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100492{
Paul Cercueil3e898302014-02-17 16:17:11 +0100493 FILE *f;
494 char buf[1024];
495 ssize_t ret;
496
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200497 if (!attr)
498 return local_read_all_dev_attrs(dev, dst, len, is_debug);
499
Paul Cercueil50c762a2014-04-14 15:55:43 +0200500 if (is_debug)
501 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
502 dev->id, attr);
503 else
504 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
505 dev->id, attr);
Paul Cercueil3e898302014-02-17 16:17:11 +0100506 f = fopen(buf, "r");
507 if (!f)
508 return -errno;
509
510 ret = fread(dst, 1, len, f);
511 if (ret > 0)
512 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100513 fflush(f);
514 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200515 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100516 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200517 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100518}
519
Paul Cercueil167d3112014-02-18 12:23:53 +0100520static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200521 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100522{
Paul Cercueil3e898302014-02-17 16:17:11 +0100523 FILE *f;
524 char buf[1024];
525 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100526
Paul Cercueil1da28122014-05-22 10:59:49 +0200527 if (!attr)
528 return local_write_all_dev_attrs(dev, src, len, is_debug);
529
Paul Cercueil50c762a2014-04-14 15:55:43 +0200530 if (is_debug)
531 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
532 dev->id, attr);
533 else
534 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
535 dev->id, attr);
Andrea Galbusera7f83b832014-07-25 18:23:36 +0200536 f = fopen(buf, "w");
Paul Cercueil3e898302014-02-17 16:17:11 +0100537 if (!f)
538 return -errno;
539
540 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100541 fflush(f);
542 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200543 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100544 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200545 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100546}
547
Paul Cercueil167d3112014-02-18 12:23:53 +0100548static const char * get_filename(const struct iio_channel *chn,
549 const char *attr)
550{
Paul Cercueil167d3112014-02-18 12:23:53 +0100551 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200552 for (i = 0; i < chn->nb_attrs; i++)
553 if (!strcmp(attr, chn->attrs[i].name))
554 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100555 return attr;
556}
557
558static ssize_t local_read_chn_attr(const struct iio_channel *chn,
559 const char *attr, char *dst, size_t len)
560{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200561 if (!attr)
562 return local_read_all_chn_attrs(chn, dst, len);
563
Paul Cercueil167d3112014-02-18 12:23:53 +0100564 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200565 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100566}
567
568static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200569 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100570{
Paul Cercueil1da28122014-05-22 10:59:49 +0200571 if (!attr)
572 return local_write_all_chn_attrs(chn, src, len);
573
Paul Cercueil167d3112014-02-18 12:23:53 +0100574 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200575 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100576}
577
Paul Cercueilff778232014-03-24 14:23:08 +0100578static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100579{
Paul Cercueilff778232014-03-24 14:23:08 +0100580 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueilcecda352014-05-06 18:14:29 +0200581 ssize_t ret = local_write_chn_attr(chn, "en", en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100582 if (ret < 0)
583 return (int) ret;
584 else
585 return 0;
586}
587
Paul Cercueil92f46df2014-04-28 13:17:53 +0200588static int enable_high_speed(const struct iio_device *dev)
589{
590 struct block_alloc_req req;
591 struct iio_device_pdata *pdata = dev->pdata;
592 unsigned int i;
593 int ret, fd = fileno(pdata->f);
594
Paul Cercueil71694c72014-05-22 14:02:13 +0200595 if (pdata->cyclic) {
596 pdata->nb_blocks = 1;
597 DEBUG("Enabling cyclic mode\n");
598 } else {
599 pdata->nb_blocks = NB_BLOCKS;
600 DEBUG("Cyclic mode not enabled\n");
601 }
602
Paul Cercueil92f46df2014-04-28 13:17:53 +0200603 req.type = 0;
604 req.size = pdata->samples_count *
605 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200606 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200607
608 ret = ioctl(fd, BLOCK_ALLOC_IOCTL, &req);
609 if (ret < 0)
610 return -errno;
611
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200612 /* We might get less blocks than what we asked for */
613 pdata->nb_blocks = req.count;
614
Paul Cercueil92f46df2014-04-28 13:17:53 +0200615 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200616 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200617 pdata->blocks[i].id = i;
618 ret = ioctl(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
619 if (ret) {
620 ret = -errno;
621 goto err_munmap;
622 }
623
624 ret = ioctl(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
625 if (ret) {
626 ret = -errno;
627 goto err_munmap;
628 }
629
Paul Cercueil032a5652014-05-12 17:11:19 +0200630 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
631 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200632 MAP_SHARED, fd, pdata->blocks[i].offset);
633 if (pdata->addrs[i] == MAP_FAILED) {
634 ret = -errno;
635 goto err_munmap;
636 }
637 }
638
Paul Cercueil4a702d32014-05-12 17:02:37 +0200639 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200640 return 0;
641
642err_munmap:
643 for (; i > 0; i--)
644 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
645 ioctl(fd, BLOCK_FREE_IOCTL, 0);
646 return ret;
647}
648
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +0200649/* Some broken drivers expect length in bytes rather than samples */
650static bool local_length_in_bytes(const struct iio_device *dev)
651{
652 const char *name = iio_device_get_name(dev);
653
654 if (!strncmp("ad-mc-", name, 5))
655 return true;
656
657 return false;
658}
659
Paul Cercueil92f15c22015-04-20 11:36:51 +0200660static int local_open(const struct iio_device *dev,
661 size_t samples_count, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100662{
663 unsigned int i;
664 int ret;
665 char buf[1024];
666 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200667 bool write_scan_elements = true;
668
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100669 if (pdata->f)
670 return -EBUSY;
671
Paul Cercueilcecda352014-05-06 18:14:29 +0200672 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200673 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100674 return ret;
675
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +0200676 if (local_length_in_bytes(dev))
Paul Cercueil92f15c22015-04-20 11:36:51 +0200677 snprintf(buf, sizeof(buf), "%zu", samples_count *
678 iio_device_get_sample_size(dev));
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +0200679 else
Paul Cercueil92f15c22015-04-20 11:36:51 +0200680 snprintf(buf, sizeof(buf), "%zu", samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200681 ret = local_write_dev_attr(dev, "buffer/length",
682 buf, strlen(buf) + 1, false);
683 if (ret < 0)
684 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200685
Paul Cercueil8c29e412014-04-07 09:46:45 +0200686 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100687 pdata->f = fopen(buf, "r+");
688 if (!pdata->f)
689 return -errno;
690
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200691 /* There was a bug in older kernel versions that cause the kernel to
692 * crash if the scan_elements _en file for a channel was set to 1, so
693 * try to avoid that */
694 if (cyclic) {
695 unsigned int major, minor;
696 struct utsname uts;
697 uname(&uts);
698 sscanf(uts.release, "%u.%u", &major, &minor);
699 if (major < 2 || (major == 3 && minor < 14))
700 write_scan_elements = false;
701 }
702
703
704 if (write_scan_elements) {
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100705 /* Disable channels */
706 for (i = 0; i < dev->nb_channels; i++) {
707 struct iio_channel *chn = dev->channels[i];
708 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
709 ret = channel_write_state(chn);
710 if (ret < 0)
711 goto err_close;
712 }
713 }
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200714 /* Enable channels */
715 for (i = 0; i < dev->nb_channels; i++) {
716 struct iio_channel *chn = dev->channels[i];
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100717 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200718 ret = channel_write_state(chn);
719 if (ret < 0)
720 goto err_close;
721 }
Paul Cercueile1311222014-03-12 15:46:16 +0100722 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100723 }
724
Paul Cercueil71694c72014-05-22 14:02:13 +0200725 pdata->cyclic = cyclic;
726 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200727 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200728 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200729 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200730
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200731 if (!pdata->is_high_speed) {
Paul Cercueil032a5652014-05-12 17:11:19 +0200732 WARNING("High-speed mode not enabled\n");
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200733 } else {
734 /* NOTE: The low-speed interface will enable the buffer after
735 * the first samples are written */
736 ret = local_write_dev_attr(dev, "buffer/enable", "1", 2, false);
737 if (ret < 0)
738 goto err_close;
739 pdata->buffer_enabled = true;
740 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100741
Paul Cercueil45c575d2014-03-20 15:14:01 +0100742 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100743err_close:
744 fclose(pdata->f);
745 pdata->f = NULL;
746 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100747}
748
749static int local_close(const struct iio_device *dev)
750{
751 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100752 int ret;
753
754 if (!pdata->f)
755 return -EBADF;
756
Paul Cercueil92f46df2014-04-28 13:17:53 +0200757 if (pdata->is_high_speed) {
758 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200759 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200760 munmap(pdata->addrs[i], pdata->blocks[i].size);
761 ioctl(fileno(pdata->f), BLOCK_FREE_IOCTL, 0);
762 }
763
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100764 ret = fclose(pdata->f);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100765 if (ret)
766 return ret;
767
768 pdata->f = NULL;
Paul Cercueil71694c72014-05-22 14:02:13 +0200769 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
770 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100771}
772
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100773static int local_get_trigger(const struct iio_device *dev,
774 const struct iio_device **trigger)
775{
776 char buf[1024];
777 unsigned int i;
778 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200779 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200780 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100781 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100782 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200783 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100784
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200785 if (buf[0] == '\0') {
786 *trigger = NULL;
787 return 0;
788 }
789
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100790 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200791 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100792 const struct iio_device *cur = dev->ctx->devices[i];
793 if (cur->name && !strcmp(cur->name, buf)) {
794 *trigger = cur;
795 return 0;
796 }
797 }
798 return -ENXIO;
799}
800
801static int local_set_trigger(const struct iio_device *dev,
802 const struct iio_device *trigger)
803{
804 ssize_t nb;
805 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200806 nb = local_write_dev_attr(dev, "trigger/current_trigger",
807 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100808 if (nb < 0)
809 return (int) nb;
810 else
811 return 0;
812}
813
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100814static bool is_channel(const char *attr)
815{
816 unsigned int i;
817 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +0100818 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
819 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100820 if (!strncmp(attr, "in_", 3))
821 ptr = strchr(attr + 3, '_');
822 else if (!strncmp(attr, "out_", 4))
823 ptr = strchr(attr + 4, '_');
824 if (!ptr)
825 return false;
826 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
827 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100828
829 if (find_modifier(ptr + 1, NULL) != IIO_NO_MOD)
830 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100831 return false;
832}
833
834static char * get_channel_id(const char *attr)
835{
836 char *res, *ptr;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100837 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100838
839 attr = strchr(attr, '_') + 1;
840 ptr = strchr(attr, '_');
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100841 if (find_modifier(ptr + 1, &len) != IIO_NO_MOD)
842 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100843
844 res = malloc(ptr - attr + 1);
845 if (!res)
846 return NULL;
847
848 memcpy(res, attr, ptr - attr);
849 res[ptr - attr] = 0;
850 return res;
851}
852
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200853static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100854{
855 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100856 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200857
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100858 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100859 if (find_modifier(ptr, &len) != IIO_NO_MOD)
860 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200861
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200862 if (chn->name) {
863 size_t len = strlen(chn->name);
864 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
865 ptr += len + 1;
866 }
867
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100868 return strdup(ptr);
869}
870
871static int read_device_name(struct iio_device *dev)
872{
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100873 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +0200874 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +0100875 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100876 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +0100877 else if (ret == 0)
878 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100879
Paul Cercueil30430c72014-02-17 16:52:37 +0100880 dev->name = strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100881 if (!dev->name)
882 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +0100883 else
884 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100885}
886
887static int add_attr_to_device(struct iio_device *dev, const char *attr)
888{
Paul Cercueilbb618272014-02-20 11:35:52 +0100889 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100890 unsigned int i;
891
892 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
893 if (!strcmp(device_attrs_blacklist[i], attr))
894 return 0;
895
896 if (!strcmp(attr, "name"))
897 return read_device_name(dev);
898
899 name = strdup(attr);
900 if (!name)
901 return -ENOMEM;
902
903 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
904 if (!attrs) {
905 free(name);
906 return -ENOMEM;
907 }
908
909 attrs[dev->nb_attrs++] = name;
910 dev->attrs = attrs;
911 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
912 return 0;
913}
914
Paul Cercueile3fbd952014-03-11 16:58:33 +0100915static int add_attr_to_channel(struct iio_channel *chn,
916 const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100917{
Paul Cercueilb34e0222014-05-05 15:32:38 +0200918 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200919 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100920 if (!name)
921 return -ENOMEM;
922
Paul Cercueile3fbd952014-03-11 16:58:33 +0100923 fn = strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +0100924 if (!fn)
925 goto err_free_name;
926
Paul Cercueilb34e0222014-05-05 15:32:38 +0200927 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
928 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +0100929 if (!attrs)
930 goto err_free_fn;
931
Paul Cercueil42d12352014-05-05 16:11:58 +0200932 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +0200933 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100934 chn->attrs = attrs;
935 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
936 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +0100937
Paul Cercueil167d3112014-02-18 12:23:53 +0100938err_free_fn:
939 free(fn);
940err_free_name:
941 free(name);
942 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100943}
944
945static int add_channel_to_device(struct iio_device *dev,
946 struct iio_channel *chn)
947{
948 struct iio_channel **channels = realloc(dev->channels,
949 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
950 if (!channels)
951 return -ENOMEM;
952
953 channels[dev->nb_channels++] = chn;
954 dev->channels = channels;
955 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
956 return 0;
957}
958
959static int add_device_to_context(struct iio_context *ctx,
960 struct iio_device *dev)
961{
962 struct iio_device **devices = realloc(ctx->devices,
963 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
964 if (!devices)
965 return -ENOMEM;
966
967 devices[ctx->nb_devices++] = dev;
968 ctx->devices = devices;
969 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
970 return 0;
971}
972
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200973/*
974 * Possible return values:
975 * 0 = Attribute should not be moved to the channel
976 * 1 = Attribute should be moved to the channel and it is a shared attribute
977 * 2 = Attribute should be moved to the channel and it is a private attribute
978 */
979static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100980{
981 unsigned int i, len;
982 char *ptr;
983
Paul Cercueil35a01312014-02-20 10:56:57 +0100984 if (!chn->is_output && !strncmp(attr, "in_", 3))
985 attr += 3;
986 else if (chn->is_output && !strncmp(attr, "out_", 4))
987 attr += 4;
988 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200989 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100990
991 ptr = strchr(attr, '_');
992 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200993 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100994
995 len = ptr - attr;
996
997 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200998 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100999
1000 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001001 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1002 if (chn->name) {
1003 size_t name_len = strlen(chn->name);
1004 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1005 attr[len + 1 + name_len] == '_')
1006 return 2;
1007 }
1008 return 1;
1009 } else if (chn->id[len] != '_') {
1010 return 0;
1011 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001012
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001013 if (find_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
1014 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001015
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001016 return 0;
1017}
1018
1019static int detect_global_attr(struct iio_device *dev, const char *attr,
1020 unsigned int level, bool *match)
1021{
1022 unsigned int i;
1023
1024 *match = false;
1025 for (i = 0; i < dev->nb_channels; i++) {
1026 struct iio_channel *chn = dev->channels[i];
1027 if (is_global_attr(chn, attr) == level) {
1028 int ret;
1029 *match = true;
1030 ret = add_attr_to_channel(chn, attr, attr);
1031 if (ret)
1032 return ret;
1033 }
1034 }
1035
1036 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001037}
1038
1039static int detect_and_move_global_attrs(struct iio_device *dev)
1040{
1041 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001042 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001043
1044 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001045 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001046 bool match;
1047 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001048
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001049 ret = detect_global_attr(dev, attr, 2, &match);
1050 if (ret)
1051 return ret;
1052
1053 if (!match) {
1054 ret = detect_global_attr(dev, attr, 1, &match);
1055 if (ret)
1056 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001057 }
1058
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001059 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001060 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001061 dev->attrs[i] = NULL;
1062 }
1063 }
1064
1065 for (i = 0; i < dev->nb_attrs; i++) {
1066 if (dev->attrs[i])
1067 *ptr++ = dev->attrs[i];
1068 }
1069
1070 dev->nb_attrs = ptr - dev->attrs;
1071 return 0;
1072}
1073
1074static struct iio_channel *create_channel(struct iio_device *dev,
Paul Cercueile3fbd952014-03-11 16:58:33 +01001075 char *id, const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001076{
1077 struct iio_channel *chn = calloc(1, sizeof(*chn));
1078 if (!chn)
1079 return NULL;
1080
Paul Cercueileaab6582014-02-21 09:35:59 +01001081 if (!strncmp(attr, "out_", 4))
Paul Cercueil35a01312014-02-20 10:56:57 +01001082 chn->is_output = true;
Paul Cercueileaab6582014-02-21 09:35:59 +01001083 else if (strncmp(attr, "in_", 3))
Paul Cercueil42d12352014-05-05 16:11:58 +02001084 goto err_free_chn;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001085
1086 chn->dev = dev;
1087 chn->id = id;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001088
Paul Cercueile3fbd952014-03-11 16:58:33 +01001089 if (!add_attr_to_channel(chn, attr, path))
Paul Cercueileaab6582014-02-21 09:35:59 +01001090 return chn;
1091
Paul Cercueileaab6582014-02-21 09:35:59 +01001092err_free_chn:
1093 free(chn);
1094 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001095}
1096
Paul Cercueile3fbd952014-03-11 16:58:33 +01001097static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001098 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001099{
Paul Cercueil1be57832014-03-11 16:27:16 +01001100 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001101 unsigned int i;
Paul Cercueil1be57832014-03-11 16:27:16 +01001102 struct iio_channel *chn;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001103 char buf[1024], *channel_id;
Paul Cercueil1be57832014-03-11 16:27:16 +01001104 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001105
1106 if (dir_is_scan_elements) {
1107 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001108 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001109 } else {
1110 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001111 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001112
Paul Cercueil1be57832014-03-11 16:27:16 +01001113 if (!is_channel(name))
1114 return add_attr_to_device(dev, name);
1115
1116 channel_id = get_channel_id(name);
1117 if (!channel_id)
1118 return -ENOMEM;
1119
1120 for (i = 0; i < dev->nb_channels; i++) {
1121 chn = dev->channels[i];
Paul Cercueil5248e792014-03-31 14:39:10 +02001122 if (!strcmp(chn->id, channel_id)
1123 && chn->is_output == (name[0] == 'o')) {
Paul Cercueil1be57832014-03-11 16:27:16 +01001124 free(channel_id);
Paul Cercueila91358e2014-04-24 16:40:19 +02001125 ret = add_attr_to_channel(chn, name, path);
1126 chn->is_scan_element = dir_is_scan_elements && !ret;
1127 return ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001128 }
1129 }
1130
Paul Cercueile3fbd952014-03-11 16:58:33 +01001131 chn = create_channel(dev, channel_id, name, path);
Paul Cercueil1be57832014-03-11 16:27:16 +01001132 if (!chn) {
1133 free(channel_id);
1134 return -ENXIO;
1135 }
1136 ret = add_channel_to_device(dev, chn);
1137 if (ret)
1138 free_channel(chn);
Paul Cercueila91358e2014-04-24 16:40:19 +02001139 else
1140 chn->is_scan_element = dir_is_scan_elements;
Paul Cercueil1be57832014-03-11 16:27:16 +01001141 return ret;
1142}
1143
Paul Cercueile3fbd952014-03-11 16:58:33 +01001144static int add_attr_or_channel(void *d, const char *path)
1145{
Paul Cercueila91358e2014-04-24 16:40:19 +02001146 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001147}
1148
1149static int add_scan_element(void *d, const char *path)
1150{
Paul Cercueila91358e2014-04-24 16:40:19 +02001151 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001152}
1153
Paul Cercueil1be57832014-03-11 16:27:16 +01001154static int foreach_in_dir(void *d, const char *path, bool is_dir,
1155 int (*callback)(void *, const char *))
1156{
1157 long name_max;
1158 struct dirent *entry, *result;
1159 DIR *dir = opendir(path);
1160 if (!dir)
1161 return -errno;
1162
1163 name_max = pathconf(path, _PC_NAME_MAX);
1164 if (name_max == -1)
1165 name_max = 255;
1166 entry = malloc(offsetof(struct dirent, d_name) + name_max + 1);
1167 if (!entry) {
1168 closedir(dir);
1169 return -ENOMEM;
1170 }
1171
1172 while (true) {
1173 struct stat st;
1174 char buf[1024];
1175 int ret = readdir_r(dir, entry, &result);
1176 if (ret) {
1177 strerror_r(ret, buf, sizeof(buf));
1178 ERROR("Unable to open directory %s: %s\n", path, buf);
1179 free(entry);
1180 closedir(dir);
Paul Cercueilc57da332015-03-16 17:09:48 +01001181 return -ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001182 }
1183 if (!result)
1184 break;
1185
1186 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1187 if (stat(buf, &st) < 0) {
1188 ret = -errno;
Paul Cercueilc21300c2014-03-13 09:54:14 +01001189 strerror_r(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001190 ERROR("Unable to stat file: %s\n", buf);
1191 free(entry);
1192 closedir(dir);
1193 return ret;
1194 }
1195
1196 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1197 ret = callback(d, buf);
1198 else if (!is_dir && S_ISREG(st.st_mode))
1199 ret = callback(d, buf);
1200 else
1201 continue;
1202
1203 if (ret < 0) {
1204 free(entry);
1205 closedir(dir);
1206 return ret;
1207 }
1208 }
1209
1210 free(entry);
1211 closedir(dir);
1212 return 0;
1213}
1214
Paul Cercueile3fbd952014-03-11 16:58:33 +01001215static int add_scan_elements(struct iio_device *dev, const char *devpath)
1216{
1217 struct stat st;
1218 char buf[1024];
1219 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1220
1221 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1222 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1223 if (ret < 0)
1224 return ret;
1225 }
1226
1227 return 0;
1228}
1229
Paul Cercueil1be57832014-03-11 16:27:16 +01001230static int create_device(void *d, const char *path)
1231{
Paul Cercueilff778232014-03-24 14:23:08 +01001232 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001233 unsigned int i;
1234 int ret;
1235 struct iio_context *ctx = d;
1236 struct iio_device *dev = calloc(1, sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001237 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001238 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001239
Paul Cercueileaab6582014-02-21 09:35:59 +01001240 dev->pdata = calloc(1, sizeof(*dev->pdata));
1241 if (!dev->pdata) {
1242 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001243 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001244 }
1245
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001246 dev->ctx = ctx;
Paul Cercueil1be57832014-03-11 16:27:16 +01001247 dev->id = strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001248 if (!dev->id) {
Paul Cercueileaab6582014-02-21 09:35:59 +01001249 free(dev->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001250 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001251 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001252 }
1253
Paul Cercueil1be57832014-03-11 16:27:16 +01001254 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
1255 if (ret < 0) {
1256 free_device(dev);
1257 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001258 }
1259
Paul Cercueil54913ac2014-03-31 14:48:19 +02001260 for (i = 0; i < dev->nb_channels; i++)
1261 set_channel_name(dev->channels[i]);
1262
Michael Hennerichebe49662014-11-07 10:32:44 +01001263 ret = add_scan_elements(dev, path);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001264 if (ret < 0) {
1265 free_device(dev);
1266 return ret;
1267 }
1268
Michael Hennerichebe49662014-11-07 10:32:44 +01001269 ret = detect_and_move_global_attrs(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001270 if (ret < 0) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001271 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001272 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001273 }
1274
Paul Cercueilff778232014-03-24 14:23:08 +01001275 dev->words = (dev->nb_channels + 31) / 32;
1276 if (dev->words) {
1277 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001278 if (!mask) {
1279 free_device(dev);
1280 return ret;
1281 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001282 }
1283
Paul Cercueilff778232014-03-24 14:23:08 +01001284 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001285
Paul Cercueil1be57832014-03-11 16:27:16 +01001286 ret = add_device_to_context(ctx, dev);
1287 if (ret < 0)
1288 free_device(dev);
1289 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001290}
1291
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001292static int add_debug_attr(void *d, const char *path)
1293{
1294 struct iio_device *dev = d;
1295 const char *attr = strrchr(path, '/') + 1;
1296 char **attrs, *name = strdup(attr);
1297 if (!name)
1298 return -ENOMEM;
1299
1300 attrs = realloc(dev->debug_attrs,
1301 (1 + dev->nb_debug_attrs) * sizeof(char *));
1302 if (!attrs) {
1303 free(name);
1304 return -ENOMEM;
1305 }
1306
1307 attrs[dev->nb_debug_attrs++] = name;
1308 dev->debug_attrs = attrs;
1309 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1310 return 0;
1311}
1312
1313static int add_debug(void *d, const char *path)
1314{
1315 struct iio_context *ctx = d;
1316 const char *name = strrchr(path, '/') + 1;
1317 struct iio_device *dev = iio_context_find_device(ctx, name);
1318 if (!dev)
1319 return -ENODEV;
1320 else
1321 return foreach_in_dir(dev, path, false, add_debug_attr);
1322}
1323
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001324static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1325{
1326 ctx->rw_timeout_ms = timeout;
1327 return 0;
1328}
1329
Paul Cercueil0865e802014-10-28 14:35:19 +01001330static struct iio_context * local_clone(
1331 const struct iio_context *ctx __attribute__((unused)))
1332{
Paul Cercueil63e52182014-12-11 12:52:48 +01001333 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001334}
1335
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001336static struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001337 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001338 .open = local_open,
1339 .close = local_close,
1340 .read = local_read,
1341 .write = local_write,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001342 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001343 .read_device_attr = local_read_dev_attr,
1344 .write_device_attr = local_write_dev_attr,
1345 .read_channel_attr = local_read_chn_attr,
1346 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001347 .get_trigger = local_get_trigger,
1348 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001349 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001350 .set_timeout = local_set_timeout,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001351};
1352
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001353static void init_index(struct iio_channel *chn)
1354{
1355 char buf[1024];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001356 long id = -ENOENT;
1357
1358 if (chn->is_scan_element) {
1359 id = (long) local_read_chn_attr(chn, "index", buf, sizeof(buf));
1360 if (id > 0)
1361 id = atol(buf);
1362 }
1363 chn->index = id;
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001364}
1365
1366static void init_data_format(struct iio_channel *chn)
1367{
1368 char buf[1024];
1369 ssize_t ret;
1370
1371 if (chn->is_scan_element) {
1372 ret = local_read_chn_attr(chn, "type", buf, sizeof(buf));
1373 if (ret < 0) {
1374 chn->format.length = 0;
1375 } else {
1376 char endian, sign;
1377
1378 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
1379 &chn->format.bits, &chn->format.length,
1380 &chn->format.shift);
Michael Hennerichfa3c6f62014-08-13 11:21:23 +02001381 chn->format.is_signed = (sign == 's' || sign == 'S');
1382 chn->format.is_fully_defined =
1383 (sign == 'S' || sign == 'U'||
1384 chn->format.bits == chn->format.length);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001385 chn->format.is_be = endian == 'b';
1386 }
1387 }
1388
1389 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1390 if (ret < 0) {
1391 chn->format.with_scale = false;
1392 } else {
1393 chn->format.with_scale = true;
1394 chn->format.scale = atof(buf);
1395 }
1396}
1397
1398static void init_scan_elements(struct iio_context *ctx)
1399{
1400 unsigned int i, j;
1401
1402 for (i = 0; i < ctx->nb_devices; i++) {
1403 struct iio_device *dev = ctx->devices[i];
1404
1405 for (j = 0; j < dev->nb_channels; j++) {
1406 struct iio_channel *chn = dev->channels[j];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001407 init_index(chn);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001408 init_data_format(chn);
1409 }
1410 }
1411}
1412
Paul Cercueil63e52182014-12-11 12:52:48 +01001413struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001414{
Paul Cercueil1be57832014-03-11 16:27:16 +01001415 int ret;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001416 unsigned int len;
1417 struct utsname uts;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001418 struct iio_context *ctx = calloc(1, sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001419 if (!ctx)
1420 goto err_set_errno_enomem;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001421
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001422 ctx->ops = &local_ops;
1423 ctx->name = "local";
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001424 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001425
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001426 uname(&uts);
1427 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1428 + strlen(uts.version) + strlen(uts.machine);
1429 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1430 if (!ctx->description) {
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001431 free(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001432 goto err_set_errno_enomem;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001433 }
1434
1435 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1436 uts.nodename, uts.release, uts.version, uts.machine);
1437
Paul Cercueil1be57832014-03-11 16:27:16 +01001438 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
1439 if (ret < 0) {
Paul Cercueil1be57832014-03-11 16:27:16 +01001440 iio_context_destroy(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001441 errno = -ret;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001442 return NULL;
1443 }
1444
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001445 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001446
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001447 init_scan_elements(ctx);
Paul Cercueil97679ac2014-06-12 10:08:20 +02001448 iio_context_init(ctx);
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001449
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001450 ctx->xml = iio_context_create_xml(ctx);
1451 if (!ctx->xml) {
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001452 iio_context_destroy(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001453 goto err_set_errno_enomem;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001454 }
Paul Cercueilae88fde2014-03-12 11:47:10 +01001455
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001456 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001457
1458err_set_errno_enomem:
1459 errno = ENOMEM;
1460 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001461}