blob: f314345153db96e3ce2175cccffcd90e2228de38 [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
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100109/*
110 * Looks for a IIO channel modifier at the beginning of the string s. If a
111 * modifier was found the symbolic constant (IIO_MOD_*) is returned, otherwise
112 * IIO_NO_MOD is returned. If a modifier was found len_p will be update with the
113 * length of the modifier.
114 */
115static unsigned int find_modifier(const char *s, size_t *len_p)
116{
117 unsigned int i;
118 size_t len;
119
120 for (i = 0; i < ARRAY_SIZE(modifier_names); i++) {
121 if (!modifier_names[i])
122 continue;
123 len = strlen(modifier_names[i]);
124 if (strncmp(s, modifier_names[i], len) == 0) {
125 if (len_p)
126 *len_p = len;
127 return i;
128 }
129 }
130
131 return IIO_NO_MOD;
132}
133
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100134static void local_shutdown(struct iio_context *ctx)
135{
Paul Cercueil42d12352014-05-05 16:11:58 +0200136 /* Free the backend data stored in every device structure */
Paul Cercueil167d3112014-02-18 12:23:53 +0100137 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200138 for (i = 0; i < ctx->nb_devices; i++)
139 free(ctx->devices[i]->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100140}
141
Michael Hennerich1c8aa572014-11-06 17:42:30 +0100142/** Shrinks the first nb characters of a string
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100143 * e.g. strcut("foobar", 4) replaces the content with "ar". */
144static void strcut(char *str, int nb)
145{
146 char *ptr = str + nb;
147 while (*ptr)
148 *str++ = *ptr++;
149 *str = 0;
150}
151
152static int set_channel_name(struct iio_channel *chn)
153{
154 if (chn->nb_attrs < 2)
155 return 0;
156
157 while (true) {
158 bool can_fix = true;
159 unsigned int i, len;
160 char *name;
Paul Cercueilb34e0222014-05-05 15:32:38 +0200161 const char *attr0 = chn->attrs[0].name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100162 const char *ptr = strchr(attr0, '_');
163 if (!ptr)
164 break;
165
166 len = ptr - attr0;
167 for (i = 1; can_fix && i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200168 can_fix = !strncmp(attr0, chn->attrs[i].name, len);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100169
170 if (!can_fix)
171 break;
172
173 if (chn->name) {
Paul Cercueil8c29e412014-04-07 09:46:45 +0200174 size_t nlen = strlen(chn->name) + len + 2;
175 name = malloc(nlen);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100176 if (!name)
177 return -ENOMEM;
Paul Cercueil8c29e412014-04-07 09:46:45 +0200178 snprintf(name, nlen, "%s_%.*s", chn->name, len, attr0);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100179 DEBUG("Fixing name of channel %s from %s to %s\n",
180 chn->id, chn->name, name);
Paul Cercueilbb618272014-02-20 11:35:52 +0100181 free(chn->name);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100182 } else {
183 name = malloc(len + 2);
184 if (!name)
185 return -ENOMEM;
Paul Cercueil8c29e412014-04-07 09:46:45 +0200186 snprintf(name, len + 2, "%.*s", len, attr0);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100187 DEBUG("Setting name of channel %s to %s\n",
188 chn->id, name);
189 }
190 chn->name = name;
191
192 /* Shrink the attribute name */
193 for (i = 0; i < chn->nb_attrs; i++)
Paul Cercueilb34e0222014-05-05 15:32:38 +0200194 strcut(chn->attrs[i].name, len + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100195 }
196
197 if (chn->name) {
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100198 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100199
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100200 chn->modifier = find_modifier(chn->name, &len);
201 if (chn->modifier != IIO_NO_MOD) {
202 if (chn->name[len]) {
203 /* Shrink the modifier from the extended name */
204 strcut(chn->name, len + 1);
205 } else {
206 free(chn->name);
207 chn->name = NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100208 }
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100209
210 DEBUG("Detected modifier for channel %s: %s\n",
211 chn->id, modifier_names[chn->modifier]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100212 }
213 }
214 return 0;
215}
216
Paul Cercueile1e0a8f2014-06-10 15:40:29 +0200217static int device_check_ready(const struct iio_device *dev, bool do_write)
218{
219 struct pollfd pollfd = {
220 .fd = fileno(dev->pdata->f),
221 .events = do_write ? POLLOUT : POLLIN,
222 };
223 int ret = poll(&pollfd, 1, dev->ctx->rw_timeout_ms);
224 if (ret < 0)
225 return -errno;
226 if (!ret)
227 return -ETIMEDOUT;
228 if (pollfd.revents & POLLNVAL)
229 return -EBADF;
230 if (!(pollfd.revents & (do_write ? POLLOUT : POLLIN)))
231 return -EIO;
232 return 0;
233}
234
Paul Cercueil45c575d2014-03-20 15:14:01 +0100235static ssize_t local_read(const struct iio_device *dev,
236 void *dst, size_t len, uint32_t *mask, size_t words)
Paul Cercueil44010ea2014-02-21 11:47:04 +0100237{
238 ssize_t ret;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200239 struct iio_device_pdata *pdata = dev->pdata;
240 FILE *f = pdata->f;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100241 if (!f)
242 return -EBADF;
Paul Cercueilff778232014-03-24 14:23:08 +0100243 if (words != dev->words)
Paul Cercueil45c575d2014-03-20 15:14:01 +0100244 return -EINVAL;
245
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200246 if (!pdata->buffer_enabled) {
247 ret = local_write_dev_attr(dev,
248 "buffer/enable", "1", 2, false);
249 if (ret < 0)
250 return ret;
251 else
252 pdata->buffer_enabled = true;
253 }
254
Lars-Peter Clausen666cfe52014-07-14 11:43:15 +0200255 ret = device_check_ready(dev, false);
256 if (ret < 0)
257 return ret;
258
Paul Cercueilff778232014-03-24 14:23:08 +0100259 memcpy(mask, dev->mask, words);
Paul Cercueil44010ea2014-02-21 11:47:04 +0100260 ret = fread(dst, 1, len, f);
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200261 fflush(f);
262 if (ferror(f))
263 ret = -errno;
264 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100265}
266
267static ssize_t local_write(const struct iio_device *dev,
268 const void *src, size_t len)
269{
270 ssize_t ret;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200271 struct iio_device_pdata *pdata = dev->pdata;
272 FILE *f = pdata->f;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100273 if (!f)
274 return -EBADF;
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200275
Paul Cercueil91d25ac2014-05-27 10:52:42 +0200276 /* Writing is forbidden in cyclic mode with devices without the
277 * high-speed mmap interface, except for the devices starting with
278 * "cf-": in this case only cyclic mode is allowed. */
Paul Cercueild9d9e4d2014-05-27 11:49:35 +0200279 if (!pdata->is_high_speed && pdata->cyclic !=
280 (dev->name && !strncmp(dev->name, "cf-", 3)))
Paul Cercueilafc17cc2014-05-26 15:18:21 +0200281 return -EACCES;
282
Paul Cercueilafff89b2014-06-12 14:12:42 +0200283 /* We use write() instead of fwrite() here, to avoid the internal
284 * buffering of the FILE API. This ensures that a waveform written in
285 * cyclic mode will be written in only one system call, as the kernel
286 * sizes the buffer according to the length of the first write. */
Paul Cercueil82139cc2014-09-02 15:51:00 +0200287 if (pdata->cyclic) {
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200288 ret = device_check_ready(dev, true);
289 if (ret < 0)
290 return ret;
291
Paul Cercueil82139cc2014-09-02 15:51:00 +0200292 ret = write(fileno(f), src, len);
293 if (ret < 0)
294 return -errno;
295 }
296
297 if (!pdata->buffer_enabled) {
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200298 ssize_t err = local_write_dev_attr(dev,
299 "buffer/enable", "1", 2, false);
300 if (err < 0)
301 return err;
302 else
303 pdata->buffer_enabled = true;
304 }
Paul Cercueil82139cc2014-09-02 15:51:00 +0200305
306 /* In cyclic mode, the buffer must be enabled after writing the samples.
307 * In non-cyclic mode, it must be enabled before writing the samples. */
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200308 if (!pdata->cyclic) {
309 ret = device_check_ready(dev, true);
310 if (ret < 0)
311 return ret;
312
Paul Cercueil82139cc2014-09-02 15:51:00 +0200313 ret = write(fileno(f), src, len);
Paul Cercueil58b93ea2014-09-02 16:42:39 +0200314 }
Paul Cercueil82139cc2014-09-02 15:51:00 +0200315
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200316 return ret ? ret : -EIO;
Paul Cercueil44010ea2014-02-21 11:47:04 +0100317}
318
Paul Cercueil92f46df2014-04-28 13:17:53 +0200319static ssize_t local_get_buffer(const struct iio_device *dev,
Paul Cercueil76ca8842015-03-05 11:16:16 +0100320 void **addr_ptr, size_t bytes_used,
321 uint32_t *mask, size_t words)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200322{
323 struct block block;
324 struct iio_device_pdata *pdata = dev->pdata;
325 FILE *f = pdata->f;
326 ssize_t ret;
327
328 if (!pdata->is_high_speed)
329 return -ENOSYS;
330 if (!f)
331 return -EBADF;
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200332 if (!addr_ptr)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200333 return -EINVAL;
334
Paul Cercueil92f46df2014-04-28 13:17:53 +0200335 if (pdata->last_dequeued >= 0) {
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200336 struct block *last_block = &pdata->blocks[pdata->last_dequeued];
Paul Cercueil71694c72014-05-22 14:02:13 +0200337
338 if (pdata->cyclic) {
339 if (pdata->cyclic_buffer_enqueued)
340 return -EBUSY;
341 pdata->blocks[0].flags |= BLOCK_FLAG_CYCLIC;
342 pdata->cyclic_buffer_enqueued = true;
343 }
344
Paul Cercueil3b6ad442014-05-12 17:43:31 +0200345 last_block->bytes_used = bytes_used;
346 ret = (ssize_t) ioctl(fileno(f),
347 BLOCK_ENQUEUE_IOCTL, last_block);
Paul Cercueil92f46df2014-04-28 13:17:53 +0200348 if (ret) {
349 ret = (ssize_t) -errno;
350 ERROR("Unable to enqueue block: %s\n", strerror(errno));
351 return ret;
352 }
Paul Cercueil71694c72014-05-22 14:02:13 +0200353
354 if (pdata->cyclic) {
355 *addr_ptr = pdata->addrs[pdata->last_dequeued];
356 return (ssize_t) last_block->bytes_used;
357 }
Paul Cercueil92f46df2014-04-28 13:17:53 +0200358 }
359
360 ret = (ssize_t) ioctl(fileno(f), BLOCK_DEQUEUE_IOCTL, &block);
361 if (ret) {
362 ret = (ssize_t) -errno;
363 ERROR("Unable to dequeue block: %s\n", strerror(errno));
364 return ret;
365 }
366
Paul Cercueil558ade42014-11-27 10:59:48 +0100367 /* Requested buffer size is too big! */
368 if (pdata->last_dequeued < 0 && bytes_used != block.size)
369 return -EFBIG;
370
Paul Cercueil92f46df2014-04-28 13:17:53 +0200371 pdata->last_dequeued = block.id;
372 *addr_ptr = pdata->addrs[block.id];
373 return (ssize_t) block.bytes_used;
374}
375
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200376static ssize_t local_read_all_dev_attrs(const struct iio_device *dev,
377 char *dst, size_t len, bool is_debug)
378{
379 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
380 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
381 char *ptr = dst;
382
383 for (i = 0; len >= 4 && i < nb; i++) {
384 /* Recursive! */
385 ssize_t ret = local_read_dev_attr(dev, attrs[i],
386 ptr + 4, len - 4, is_debug);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200387 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200388
389 /* Align the length to 4 bytes */
390 if (ret > 0 && ret & 3)
391 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200392 ptr += 4 + (ret < 0 ? 0 : ret);
393 len -= 4 + (ret < 0 ? 0 : ret);
394 }
395
396 return ptr - dst;
397}
398
399static ssize_t local_read_all_chn_attrs(const struct iio_channel *chn,
400 char *dst, size_t len)
401{
402 unsigned int i;
403 char *ptr = dst;
404
405 for (i = 0; len >= 4 && i < chn->nb_attrs; i++) {
406 /* Recursive! */
407 ssize_t ret = local_read_chn_attr(chn,
408 chn->attrs[i].name, ptr + 4, len - 4);
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200409 *(uint32_t *) ptr = htonl(ret);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200410
411 /* Align the length to 4 bytes */
412 if (ret > 0 && ret & 3)
413 ret = ((ret >> 2) + 1) << 2;
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200414 ptr += 4 + (ret < 0 ? 0 : ret);
415 len -= 4 + (ret < 0 ? 0 : ret);
416 }
417
418 return ptr - dst;
419}
420
Paul Cercueil1da28122014-05-22 10:59:49 +0200421static int local_buffer_analyze(unsigned int nb, const char *src, size_t len)
422{
423 while (nb--) {
424 int32_t val;
425
426 if (len < 4)
427 return -EINVAL;
428
429 val = (int32_t) ntohl(*(uint32_t *) src);
430 src += 4;
431 len -= 4;
432
433 if (val > 0) {
434 if ((uint32_t) val > len)
435 return -EINVAL;
Paul Cercueil33f21452014-06-10 13:57:41 +0200436
437 /* Align the length to 4 bytes */
438 if (val & 3)
439 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200440 len -= val;
441 src += val;
442 }
443 }
444
445 /* We should have analyzed the whole buffer by now */
446 return !len ? 0 : -EINVAL;
447}
448
449static ssize_t local_write_all_dev_attrs(const struct iio_device *dev,
450 const char *src, size_t len, bool is_debug)
451{
452 unsigned int i, nb = is_debug ? dev->nb_debug_attrs : dev->nb_attrs;
453 char **attrs = is_debug ? dev->debug_attrs : dev->attrs;
454 const char *ptr = src;
455
456 /* First step: Verify that the buffer is in the correct format */
457 if (local_buffer_analyze(nb, src, len))
458 return -EINVAL;
459
460 /* Second step: write the attributes */
461 for (i = 0; i < nb; i++) {
462 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
463 ptr += 4;
464
465 if (val > 0) {
466 local_write_dev_attr(dev, attrs[i], ptr, val, is_debug);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200467
468 /* Align the length to 4 bytes */
469 if (val & 3)
470 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200471 ptr += val;
472 }
473 }
474
475 return ptr - src;
476}
477
478static ssize_t local_write_all_chn_attrs(const struct iio_channel *chn,
479 const char *src, size_t len)
480{
481 unsigned int i, nb = chn->nb_attrs;
482 const char *ptr = src;
483
484 /* First step: Verify that the buffer is in the correct format */
485 if (local_buffer_analyze(nb, src, len))
486 return -EINVAL;
487
488 /* Second step: write the attributes */
489 for (i = 0; i < nb; i++) {
490 int32_t val = (int32_t) ntohl(*(uint32_t *) ptr);
491 ptr += 4;
492
493 if (val > 0) {
494 local_write_chn_attr(chn, chn->attrs[i].name, ptr, val);
Paul Cercueil13fb2622014-06-05 15:53:20 +0200495
496 /* Align the length to 4 bytes */
497 if (val & 3)
498 val = ((val >> 2) + 1) << 2;
Paul Cercueil1da28122014-05-22 10:59:49 +0200499 ptr += val;
500 }
501 }
502
503 return ptr - src;
504}
505
Paul Cercueil167d3112014-02-18 12:23:53 +0100506static ssize_t local_read_dev_attr(const struct iio_device *dev,
Paul Cercueil50c762a2014-04-14 15:55:43 +0200507 const char *attr, char *dst, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100508{
Paul Cercueil3e898302014-02-17 16:17:11 +0100509 FILE *f;
510 char buf[1024];
511 ssize_t ret;
512
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200513 if (!attr)
514 return local_read_all_dev_attrs(dev, dst, len, is_debug);
515
Paul Cercueil50c762a2014-04-14 15:55:43 +0200516 if (is_debug)
517 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
518 dev->id, attr);
519 else
520 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
521 dev->id, attr);
Paul Cercueil3e898302014-02-17 16:17:11 +0100522 f = fopen(buf, "r");
523 if (!f)
524 return -errno;
525
526 ret = fread(dst, 1, len, f);
527 if (ret > 0)
528 dst[ret - 1] = '\0';
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100529 fflush(f);
530 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200531 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100532 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200533 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100534}
535
Paul Cercueil167d3112014-02-18 12:23:53 +0100536static ssize_t local_write_dev_attr(const struct iio_device *dev,
Paul Cercueilcecda352014-05-06 18:14:29 +0200537 const char *attr, const char *src, size_t len, bool is_debug)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100538{
Paul Cercueil3e898302014-02-17 16:17:11 +0100539 FILE *f;
540 char buf[1024];
541 ssize_t ret;
Paul Cercueil3e898302014-02-17 16:17:11 +0100542
Paul Cercueil1da28122014-05-22 10:59:49 +0200543 if (!attr)
544 return local_write_all_dev_attrs(dev, src, len, is_debug);
545
Paul Cercueil50c762a2014-04-14 15:55:43 +0200546 if (is_debug)
547 snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
548 dev->id, attr);
549 else
550 snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
551 dev->id, attr);
Andrea Galbusera7f83b832014-07-25 18:23:36 +0200552 f = fopen(buf, "w");
Paul Cercueil3e898302014-02-17 16:17:11 +0100553 if (!f)
554 return -errno;
555
556 ret = fwrite(src, 1, len, f);
Paul Cercueil96dfedd2014-03-11 09:53:09 +0100557 fflush(f);
558 if (ferror(f))
Paul Cercueilf466c6d2014-06-02 17:41:02 +0200559 ret = -errno;
Paul Cercueil3e898302014-02-17 16:17:11 +0100560 fclose(f);
Paul Cercueil6e7f79e2014-04-04 12:27:24 +0200561 return ret ? ret : -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100562}
563
Paul Cercueil167d3112014-02-18 12:23:53 +0100564static const char * get_filename(const struct iio_channel *chn,
565 const char *attr)
566{
Paul Cercueil167d3112014-02-18 12:23:53 +0100567 unsigned int i;
Paul Cercueil42d12352014-05-05 16:11:58 +0200568 for (i = 0; i < chn->nb_attrs; i++)
569 if (!strcmp(attr, chn->attrs[i].name))
570 return chn->attrs[i].filename;
Paul Cercueil167d3112014-02-18 12:23:53 +0100571 return attr;
572}
573
574static ssize_t local_read_chn_attr(const struct iio_channel *chn,
575 const char *attr, char *dst, size_t len)
576{
Paul Cercueil4ca6ddc2014-05-21 14:51:50 +0200577 if (!attr)
578 return local_read_all_chn_attrs(chn, dst, len);
579
Paul Cercueil167d3112014-02-18 12:23:53 +0100580 attr = get_filename(chn, attr);
Paul Cercueil50c762a2014-04-14 15:55:43 +0200581 return local_read_dev_attr(chn->dev, attr, dst, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100582}
583
584static ssize_t local_write_chn_attr(const struct iio_channel *chn,
Paul Cercueilcecda352014-05-06 18:14:29 +0200585 const char *attr, const char *src, size_t len)
Paul Cercueil167d3112014-02-18 12:23:53 +0100586{
Paul Cercueil1da28122014-05-22 10:59:49 +0200587 if (!attr)
588 return local_write_all_chn_attrs(chn, src, len);
589
Paul Cercueil167d3112014-02-18 12:23:53 +0100590 attr = get_filename(chn, attr);
Paul Cercueilcecda352014-05-06 18:14:29 +0200591 return local_write_dev_attr(chn->dev, attr, src, len, false);
Paul Cercueil167d3112014-02-18 12:23:53 +0100592}
593
Paul Cercueilff778232014-03-24 14:23:08 +0100594static int channel_write_state(const struct iio_channel *chn)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100595{
Paul Cercueilff778232014-03-24 14:23:08 +0100596 char *en = iio_channel_is_enabled(chn) ? "1" : "0";
Paul Cercueilcecda352014-05-06 18:14:29 +0200597 ssize_t ret = local_write_chn_attr(chn, "en", en, 2);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100598 if (ret < 0)
599 return (int) ret;
600 else
601 return 0;
602}
603
Paul Cercueil92f46df2014-04-28 13:17:53 +0200604static int enable_high_speed(const struct iio_device *dev)
605{
606 struct block_alloc_req req;
607 struct iio_device_pdata *pdata = dev->pdata;
608 unsigned int i;
609 int ret, fd = fileno(pdata->f);
610
Paul Cercueil71694c72014-05-22 14:02:13 +0200611 if (pdata->cyclic) {
612 pdata->nb_blocks = 1;
613 DEBUG("Enabling cyclic mode\n");
614 } else {
615 pdata->nb_blocks = NB_BLOCKS;
616 DEBUG("Cyclic mode not enabled\n");
617 }
618
Paul Cercueil92f46df2014-04-28 13:17:53 +0200619 req.type = 0;
620 req.size = pdata->samples_count *
621 iio_device_get_sample_size_mask(dev, dev->mask, dev->words);
Paul Cercueil71694c72014-05-22 14:02:13 +0200622 req.count = pdata->nb_blocks;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200623
624 ret = ioctl(fd, BLOCK_ALLOC_IOCTL, &req);
625 if (ret < 0)
626 return -errno;
627
Lars-Peter Clausenc27cc532014-07-08 10:47:26 +0200628 /* We might get less blocks than what we asked for */
629 pdata->nb_blocks = req.count;
630
Paul Cercueil92f46df2014-04-28 13:17:53 +0200631 /* mmap all the blocks */
Paul Cercueil71694c72014-05-22 14:02:13 +0200632 for (i = 0; i < pdata->nb_blocks; i++) {
Paul Cercueil92f46df2014-04-28 13:17:53 +0200633 pdata->blocks[i].id = i;
634 ret = ioctl(fd, BLOCK_QUERY_IOCTL, &pdata->blocks[i]);
635 if (ret) {
636 ret = -errno;
637 goto err_munmap;
638 }
639
640 ret = ioctl(fd, BLOCK_ENQUEUE_IOCTL, &pdata->blocks[i]);
641 if (ret) {
642 ret = -errno;
643 goto err_munmap;
644 }
645
Paul Cercueil032a5652014-05-12 17:11:19 +0200646 pdata->addrs[i] = mmap(0, pdata->blocks[i].size,
647 PROT_READ | PROT_WRITE,
Paul Cercueil92f46df2014-04-28 13:17:53 +0200648 MAP_SHARED, fd, pdata->blocks[i].offset);
649 if (pdata->addrs[i] == MAP_FAILED) {
650 ret = -errno;
651 goto err_munmap;
652 }
653 }
654
Paul Cercueil4a702d32014-05-12 17:02:37 +0200655 pdata->last_dequeued = -1;
Paul Cercueil92f46df2014-04-28 13:17:53 +0200656 return 0;
657
658err_munmap:
659 for (; i > 0; i--)
660 munmap(pdata->addrs[i - 1], pdata->blocks[i - 1].size);
661 ioctl(fd, BLOCK_FREE_IOCTL, 0);
662 return ret;
663}
664
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +0200665/* Some broken drivers expect length in bytes rather than samples */
666static bool local_length_in_bytes(const struct iio_device *dev)
667{
668 const char *name = iio_device_get_name(dev);
669
670 if (!strncmp("ad-mc-", name, 5))
671 return true;
672
673 return false;
674}
675
Paul Cercueil71694c72014-05-22 14:02:13 +0200676static int local_open(const struct iio_device *dev, size_t samples_count,
677 uint32_t *mask, size_t nb, bool cyclic)
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100678{
679 unsigned int i;
680 int ret;
681 char buf[1024];
682 struct iio_device_pdata *pdata = dev->pdata;
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200683 bool write_scan_elements = true;
684
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100685 if (pdata->f)
686 return -EBUSY;
687
Paul Cercueilff778232014-03-24 14:23:08 +0100688 if (nb != dev->words)
Paul Cercueile1311222014-03-12 15:46:16 +0100689 return -EINVAL;
690
Paul Cercueilcecda352014-05-06 18:14:29 +0200691 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
Paul Cercueilf0aeae32014-04-02 13:52:26 +0200692 if (ret < 0)
Paul Cercueil48e39452014-03-14 09:37:53 +0100693 return ret;
694
Lars-Peter Clausenac9e3282014-07-14 13:36:46 +0200695 if (local_length_in_bytes(dev))
696 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count *
697 iio_device_get_sample_size_mask(dev, mask, nb));
698 else
699 snprintf(buf, sizeof(buf), "%lu", (unsigned long) samples_count);
Paul Cercueil71694c72014-05-22 14:02:13 +0200700 ret = local_write_dev_attr(dev, "buffer/length",
701 buf, strlen(buf) + 1, false);
702 if (ret < 0)
703 return ret;
Paul Cercueile6ebf492014-04-02 13:57:36 +0200704
Paul Cercueil8c29e412014-04-07 09:46:45 +0200705 snprintf(buf, sizeof(buf), "/dev/%s", dev->id);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100706 pdata->f = fopen(buf, "r+");
707 if (!pdata->f)
708 return -errno;
709
Paul Cercueilff778232014-03-24 14:23:08 +0100710 memcpy(dev->mask, mask, nb);
711
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200712 /* There was a bug in older kernel versions that cause the kernel to
713 * crash if the scan_elements _en file for a channel was set to 1, so
714 * try to avoid that */
715 if (cyclic) {
716 unsigned int major, minor;
717 struct utsname uts;
718 uname(&uts);
719 sscanf(uts.release, "%u.%u", &major, &minor);
720 if (major < 2 || (major == 3 && minor < 14))
721 write_scan_elements = false;
722 }
723
724
725 if (write_scan_elements) {
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100726 /* Disable channels */
727 for (i = 0; i < dev->nb_channels; i++) {
728 struct iio_channel *chn = dev->channels[i];
729 if (chn->index >= 0 && !iio_channel_is_enabled(chn)) {
730 ret = channel_write_state(chn);
731 if (ret < 0)
732 goto err_close;
733 }
734 }
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200735 /* Enable channels */
736 for (i = 0; i < dev->nb_channels; i++) {
737 struct iio_channel *chn = dev->channels[i];
Lars-Peter Clausen15d7e152015-03-04 15:59:47 +0100738 if (chn->index >= 0 && iio_channel_is_enabled(chn)) {
Lars-Peter Clausen00f80092014-07-01 17:52:05 +0200739 ret = channel_write_state(chn);
740 if (ret < 0)
741 goto err_close;
742 }
Paul Cercueile1311222014-03-12 15:46:16 +0100743 }
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100744 }
745
Paul Cercueil71694c72014-05-22 14:02:13 +0200746 pdata->cyclic = cyclic;
747 pdata->cyclic_buffer_enqueued = false;
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200748 pdata->buffer_enabled = false;
Paul Cercueilb762fc62014-05-12 16:56:09 +0200749 pdata->samples_count = samples_count;
Paul Cercueil71694c72014-05-22 14:02:13 +0200750 pdata->is_high_speed = !enable_high_speed(dev);
Paul Cercueilb762fc62014-05-12 16:56:09 +0200751
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200752 if (!pdata->is_high_speed) {
Paul Cercueil032a5652014-05-12 17:11:19 +0200753 WARNING("High-speed mode not enabled\n");
Paul Cercueil6ea8a752014-06-03 11:35:35 +0200754 } else {
755 /* NOTE: The low-speed interface will enable the buffer after
756 * the first samples are written */
757 ret = local_write_dev_attr(dev, "buffer/enable", "1", 2, false);
758 if (ret < 0)
759 goto err_close;
760 pdata->buffer_enabled = true;
761 }
Paul Cercueil45c575d2014-03-20 15:14:01 +0100762
Paul Cercueil45c575d2014-03-20 15:14:01 +0100763 return 0;
Paul Cercueile1311222014-03-12 15:46:16 +0100764err_close:
765 fclose(pdata->f);
766 pdata->f = NULL;
767 return ret;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100768}
769
770static int local_close(const struct iio_device *dev)
771{
772 struct iio_device_pdata *pdata = dev->pdata;
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100773 int ret;
774
775 if (!pdata->f)
776 return -EBADF;
777
Paul Cercueil92f46df2014-04-28 13:17:53 +0200778 if (pdata->is_high_speed) {
779 unsigned int i;
Paul Cercueil71694c72014-05-22 14:02:13 +0200780 for (i = 0; i < pdata->nb_blocks; i++)
Paul Cercueil92f46df2014-04-28 13:17:53 +0200781 munmap(pdata->addrs[i], pdata->blocks[i].size);
782 ioctl(fileno(pdata->f), BLOCK_FREE_IOCTL, 0);
783 }
784
Paul Cercueilfc8ec4a2014-03-17 16:42:22 +0100785 ret = fclose(pdata->f);
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100786 if (ret)
787 return ret;
788
789 pdata->f = NULL;
Paul Cercueil71694c72014-05-22 14:02:13 +0200790 ret = local_write_dev_attr(dev, "buffer/enable", "0", 2, false);
791 return (ret < 0) ? ret : 0;
Paul Cercueil8a7975e2014-03-12 12:53:43 +0100792}
793
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100794static int local_get_trigger(const struct iio_device *dev,
795 const struct iio_device **trigger)
796{
797 char buf[1024];
798 unsigned int i;
799 ssize_t nb = local_read_dev_attr(dev, "trigger/current_trigger",
Paul Cercueil50c762a2014-04-14 15:55:43 +0200800 buf, sizeof(buf), false);
Paul Cercueild09322a2014-04-02 13:50:18 +0200801 if (nb < 0) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100802 *trigger = NULL;
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100803 return (int) nb;
Paul Cercueild09322a2014-04-02 13:50:18 +0200804 }
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100805
Lars-Peter Clausenb5cdc102014-08-21 14:45:52 +0200806 if (buf[0] == '\0') {
807 *trigger = NULL;
808 return 0;
809 }
810
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100811 nb = dev->ctx->nb_devices;
Paul Cercueil4e2f6652014-04-04 12:41:45 +0200812 for (i = 0; i < (size_t) nb; i++) {
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100813 const struct iio_device *cur = dev->ctx->devices[i];
814 if (cur->name && !strcmp(cur->name, buf)) {
815 *trigger = cur;
816 return 0;
817 }
818 }
819 return -ENXIO;
820}
821
822static int local_set_trigger(const struct iio_device *dev,
823 const struct iio_device *trigger)
824{
825 ssize_t nb;
826 const char *value = trigger ? trigger->name : "";
Paul Cercueilcecda352014-05-06 18:14:29 +0200827 nb = local_write_dev_attr(dev, "trigger/current_trigger",
828 value, strlen(value) + 1, false);
Paul Cercueil096e9aa2014-03-10 12:48:51 +0100829 if (nb < 0)
830 return (int) nb;
831 else
832 return 0;
833}
834
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100835static bool is_channel(const char *attr)
836{
837 unsigned int i;
838 char *ptr = NULL;
Paul Cercueilec6857d2014-03-11 17:23:49 +0100839 if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
840 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100841 if (!strncmp(attr, "in_", 3))
842 ptr = strchr(attr + 3, '_');
843 else if (!strncmp(attr, "out_", 4))
844 ptr = strchr(attr + 4, '_');
845 if (!ptr)
846 return false;
847 if (*(ptr - 1) >= '0' && *(ptr - 1) <= '9')
848 return true;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100849
850 if (find_modifier(ptr + 1, NULL) != IIO_NO_MOD)
851 return true;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100852 return false;
853}
854
855static char * get_channel_id(const char *attr)
856{
857 char *res, *ptr;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100858 size_t len;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100859
860 attr = strchr(attr, '_') + 1;
861 ptr = strchr(attr, '_');
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100862 if (find_modifier(ptr + 1, &len) != IIO_NO_MOD)
863 ptr += len + 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100864
865 res = malloc(ptr - attr + 1);
866 if (!res)
867 return NULL;
868
869 memcpy(res, attr, ptr - attr);
870 res[ptr - attr] = 0;
871 return res;
872}
873
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200874static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100875{
876 char *ptr = strchr(attr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100877 size_t len;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200878
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100879 ptr = strchr(ptr, '_') + 1;
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +0100880 if (find_modifier(ptr, &len) != IIO_NO_MOD)
881 ptr += len + 1;
Lars-Peter Clausen82390f52014-07-30 15:34:56 +0200882
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200883 if (chn->name) {
884 size_t len = strlen(chn->name);
885 if (strncmp(chn->name, ptr, len) == 0 && ptr[len] == '_')
886 ptr += len + 1;
887 }
888
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100889 return strdup(ptr);
890}
891
892static int read_device_name(struct iio_device *dev)
893{
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100894 char buf[1024];
Paul Cercueil8c29e412014-04-07 09:46:45 +0200895 ssize_t ret = iio_device_attr_read(dev, "name", buf, sizeof(buf));
Paul Cercueil30430c72014-02-17 16:52:37 +0100896 if (ret < 0)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100897 return ret;
Paul Cercueil30430c72014-02-17 16:52:37 +0100898 else if (ret == 0)
899 return -EIO;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100900
Paul Cercueil30430c72014-02-17 16:52:37 +0100901 dev->name = strdup(buf);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100902 if (!dev->name)
903 return -ENOMEM;
Paul Cercueil30430c72014-02-17 16:52:37 +0100904 else
905 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100906}
907
908static int add_attr_to_device(struct iio_device *dev, const char *attr)
909{
Paul Cercueilbb618272014-02-20 11:35:52 +0100910 char **attrs, *name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100911 unsigned int i;
912
913 for (i = 0; i < ARRAY_SIZE(device_attrs_blacklist); i++)
914 if (!strcmp(device_attrs_blacklist[i], attr))
915 return 0;
916
917 if (!strcmp(attr, "name"))
918 return read_device_name(dev);
919
920 name = strdup(attr);
921 if (!name)
922 return -ENOMEM;
923
924 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
925 if (!attrs) {
926 free(name);
927 return -ENOMEM;
928 }
929
930 attrs[dev->nb_attrs++] = name;
931 dev->attrs = attrs;
932 DEBUG("Added attr \'%s\' to device \'%s\'\n", attr, dev->id);
933 return 0;
934}
935
Paul Cercueile3fbd952014-03-11 16:58:33 +0100936static int add_attr_to_channel(struct iio_channel *chn,
937 const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100938{
Paul Cercueilb34e0222014-05-05 15:32:38 +0200939 struct iio_channel_attr *attrs;
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200940 char *fn, *name = get_short_attr_name(chn, attr);
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100941 if (!name)
942 return -ENOMEM;
943
Paul Cercueile3fbd952014-03-11 16:58:33 +0100944 fn = strdup(path);
Paul Cercueil167d3112014-02-18 12:23:53 +0100945 if (!fn)
946 goto err_free_name;
947
Paul Cercueilb34e0222014-05-05 15:32:38 +0200948 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) *
949 sizeof(struct iio_channel_attr));
Paul Cercueil167d3112014-02-18 12:23:53 +0100950 if (!attrs)
951 goto err_free_fn;
952
Paul Cercueil42d12352014-05-05 16:11:58 +0200953 attrs[chn->nb_attrs].filename = fn;
Paul Cercueilb34e0222014-05-05 15:32:38 +0200954 attrs[chn->nb_attrs++].name = name;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100955 chn->attrs = attrs;
956 DEBUG("Added attr \'%s\' to channel \'%s\'\n", name, chn->id);
957 return 0;
Paul Cercueil167d3112014-02-18 12:23:53 +0100958
Paul Cercueil167d3112014-02-18 12:23:53 +0100959err_free_fn:
960 free(fn);
961err_free_name:
962 free(name);
963 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +0100964}
965
966static int add_channel_to_device(struct iio_device *dev,
967 struct iio_channel *chn)
968{
969 struct iio_channel **channels = realloc(dev->channels,
970 (dev->nb_channels + 1) * sizeof(struct iio_channel *));
971 if (!channels)
972 return -ENOMEM;
973
974 channels[dev->nb_channels++] = chn;
975 dev->channels = channels;
976 DEBUG("Added channel \'%s\' to device \'%s\'\n", chn->id, dev->id);
977 return 0;
978}
979
980static int add_device_to_context(struct iio_context *ctx,
981 struct iio_device *dev)
982{
983 struct iio_device **devices = realloc(ctx->devices,
984 (ctx->nb_devices + 1) * sizeof(struct iio_device *));
985 if (!devices)
986 return -ENOMEM;
987
988 devices[ctx->nb_devices++] = dev;
989 ctx->devices = devices;
990 DEBUG("Added device \'%s\' to context \'%s\'\n", dev->id, ctx->name);
991 return 0;
992}
993
Lars-Peter Clausende6faf02014-08-25 15:42:51 +0200994/*
995 * Possible return values:
996 * 0 = Attribute should not be moved to the channel
997 * 1 = Attribute should be moved to the channel and it is a shared attribute
998 * 2 = Attribute should be moved to the channel and it is a private attribute
999 */
1000static unsigned int is_global_attr(struct iio_channel *chn, const char *attr)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001001{
1002 unsigned int i, len;
1003 char *ptr;
1004
Paul Cercueil35a01312014-02-20 10:56:57 +01001005 if (!chn->is_output && !strncmp(attr, "in_", 3))
1006 attr += 3;
1007 else if (chn->is_output && !strncmp(attr, "out_", 4))
1008 attr += 4;
1009 else
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001010 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001011
1012 ptr = strchr(attr, '_');
1013 if (!ptr)
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001014 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001015
1016 len = ptr - attr;
1017
1018 if (strncmp(chn->id, attr, len))
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001019 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001020
1021 DEBUG("Found match: %s and %s\n", chn->id, attr);
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001022 if (chn->id[len] >= '0' && chn->id[len] <= '9') {
1023 if (chn->name) {
1024 size_t name_len = strlen(chn->name);
1025 if (strncmp(chn->name, attr + len + 1, name_len) == 0 &&
1026 attr[len + 1 + name_len] == '_')
1027 return 2;
1028 }
1029 return 1;
1030 } else if (chn->id[len] != '_') {
1031 return 0;
1032 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001033
Lars-Peter Clausen2d620de2015-03-27 13:33:55 +01001034 if (find_modifier(chn->id + len + 1, NULL) != IIO_NO_MOD)
1035 return 1;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001036
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001037 return 0;
1038}
1039
1040static int detect_global_attr(struct iio_device *dev, const char *attr,
1041 unsigned int level, bool *match)
1042{
1043 unsigned int i;
1044
1045 *match = false;
1046 for (i = 0; i < dev->nb_channels; i++) {
1047 struct iio_channel *chn = dev->channels[i];
1048 if (is_global_attr(chn, attr) == level) {
1049 int ret;
1050 *match = true;
1051 ret = add_attr_to_channel(chn, attr, attr);
1052 if (ret)
1053 return ret;
1054 }
1055 }
1056
1057 return 0;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001058}
1059
1060static int detect_and_move_global_attrs(struct iio_device *dev)
1061{
1062 unsigned int i;
Paul Cercueilbb618272014-02-20 11:35:52 +01001063 char **ptr = dev->attrs;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001064
1065 for (i = 0; i < dev->nb_attrs; i++) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001066 const char *attr = dev->attrs[i];
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001067 bool match;
1068 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001069
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001070 ret = detect_global_attr(dev, attr, 2, &match);
1071 if (ret)
1072 return ret;
1073
1074 if (!match) {
1075 ret = detect_global_attr(dev, attr, 1, &match);
1076 if (ret)
1077 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001078 }
1079
Lars-Peter Clausende6faf02014-08-25 15:42:51 +02001080 if (match) {
Paul Cercueilbb618272014-02-20 11:35:52 +01001081 free(dev->attrs[i]);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001082 dev->attrs[i] = NULL;
1083 }
1084 }
1085
1086 for (i = 0; i < dev->nb_attrs; i++) {
1087 if (dev->attrs[i])
1088 *ptr++ = dev->attrs[i];
1089 }
1090
1091 dev->nb_attrs = ptr - dev->attrs;
1092 return 0;
1093}
1094
1095static struct iio_channel *create_channel(struct iio_device *dev,
Paul Cercueile3fbd952014-03-11 16:58:33 +01001096 char *id, const char *attr, const char *path)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001097{
1098 struct iio_channel *chn = calloc(1, sizeof(*chn));
1099 if (!chn)
1100 return NULL;
1101
Paul Cercueileaab6582014-02-21 09:35:59 +01001102 if (!strncmp(attr, "out_", 4))
Paul Cercueil35a01312014-02-20 10:56:57 +01001103 chn->is_output = true;
Paul Cercueileaab6582014-02-21 09:35:59 +01001104 else if (strncmp(attr, "in_", 3))
Paul Cercueil42d12352014-05-05 16:11:58 +02001105 goto err_free_chn;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001106
1107 chn->dev = dev;
1108 chn->id = id;
1109 chn->modifier = IIO_NO_MOD;
1110
Paul Cercueile3fbd952014-03-11 16:58:33 +01001111 if (!add_attr_to_channel(chn, attr, path))
Paul Cercueileaab6582014-02-21 09:35:59 +01001112 return chn;
1113
Paul Cercueileaab6582014-02-21 09:35:59 +01001114err_free_chn:
1115 free(chn);
1116 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001117}
1118
Paul Cercueile3fbd952014-03-11 16:58:33 +01001119static int add_attr_or_channel_helper(struct iio_device *dev,
Paul Cercueila91358e2014-04-24 16:40:19 +02001120 const char *path, bool dir_is_scan_elements)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001121{
Paul Cercueil1be57832014-03-11 16:27:16 +01001122 int ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001123 unsigned int i;
Paul Cercueil1be57832014-03-11 16:27:16 +01001124 struct iio_channel *chn;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001125 char buf[1024], *channel_id;
Paul Cercueil1be57832014-03-11 16:27:16 +01001126 const char *name = strrchr(path, '/') + 1;
Paul Cercueila91358e2014-04-24 16:40:19 +02001127
1128 if (dir_is_scan_elements) {
1129 snprintf(buf, sizeof(buf), "scan_elements/%s", name);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001130 path = buf;
Paul Cercueila91358e2014-04-24 16:40:19 +02001131 } else {
1132 path = name;
Paul Cercueile3fbd952014-03-11 16:58:33 +01001133 }
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001134
Paul Cercueil1be57832014-03-11 16:27:16 +01001135 if (!is_channel(name))
1136 return add_attr_to_device(dev, name);
1137
1138 channel_id = get_channel_id(name);
1139 if (!channel_id)
1140 return -ENOMEM;
1141
1142 for (i = 0; i < dev->nb_channels; i++) {
1143 chn = dev->channels[i];
Paul Cercueil5248e792014-03-31 14:39:10 +02001144 if (!strcmp(chn->id, channel_id)
1145 && chn->is_output == (name[0] == 'o')) {
Paul Cercueil1be57832014-03-11 16:27:16 +01001146 free(channel_id);
Paul Cercueila91358e2014-04-24 16:40:19 +02001147 ret = add_attr_to_channel(chn, name, path);
1148 chn->is_scan_element = dir_is_scan_elements && !ret;
1149 return ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001150 }
1151 }
1152
Paul Cercueile3fbd952014-03-11 16:58:33 +01001153 chn = create_channel(dev, channel_id, name, path);
Paul Cercueil1be57832014-03-11 16:27:16 +01001154 if (!chn) {
1155 free(channel_id);
1156 return -ENXIO;
1157 }
1158 ret = add_channel_to_device(dev, chn);
1159 if (ret)
1160 free_channel(chn);
Paul Cercueila91358e2014-04-24 16:40:19 +02001161 else
1162 chn->is_scan_element = dir_is_scan_elements;
Paul Cercueil1be57832014-03-11 16:27:16 +01001163 return ret;
1164}
1165
Paul Cercueile3fbd952014-03-11 16:58:33 +01001166static int add_attr_or_channel(void *d, const char *path)
1167{
Paul Cercueila91358e2014-04-24 16:40:19 +02001168 return add_attr_or_channel_helper((struct iio_device *) d, path, false);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001169}
1170
1171static int add_scan_element(void *d, const char *path)
1172{
Paul Cercueila91358e2014-04-24 16:40:19 +02001173 return add_attr_or_channel_helper((struct iio_device *) d, path, true);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001174}
1175
Paul Cercueil1be57832014-03-11 16:27:16 +01001176static int foreach_in_dir(void *d, const char *path, bool is_dir,
1177 int (*callback)(void *, const char *))
1178{
1179 long name_max;
1180 struct dirent *entry, *result;
1181 DIR *dir = opendir(path);
1182 if (!dir)
1183 return -errno;
1184
1185 name_max = pathconf(path, _PC_NAME_MAX);
1186 if (name_max == -1)
1187 name_max = 255;
1188 entry = malloc(offsetof(struct dirent, d_name) + name_max + 1);
1189 if (!entry) {
1190 closedir(dir);
1191 return -ENOMEM;
1192 }
1193
1194 while (true) {
1195 struct stat st;
1196 char buf[1024];
1197 int ret = readdir_r(dir, entry, &result);
1198 if (ret) {
1199 strerror_r(ret, buf, sizeof(buf));
1200 ERROR("Unable to open directory %s: %s\n", path, buf);
1201 free(entry);
1202 closedir(dir);
Paul Cercueilc57da332015-03-16 17:09:48 +01001203 return -ret;
Paul Cercueil1be57832014-03-11 16:27:16 +01001204 }
1205 if (!result)
1206 break;
1207
1208 snprintf(buf, sizeof(buf), "%s/%s", path, entry->d_name);
1209 if (stat(buf, &st) < 0) {
1210 ret = -errno;
Paul Cercueilc21300c2014-03-13 09:54:14 +01001211 strerror_r(errno, buf, sizeof(buf));
Paul Cercueil1be57832014-03-11 16:27:16 +01001212 ERROR("Unable to stat file: %s\n", buf);
1213 free(entry);
1214 closedir(dir);
1215 return ret;
1216 }
1217
1218 if (is_dir && S_ISDIR(st.st_mode) && entry->d_name[0] != '.')
1219 ret = callback(d, buf);
1220 else if (!is_dir && S_ISREG(st.st_mode))
1221 ret = callback(d, buf);
1222 else
1223 continue;
1224
1225 if (ret < 0) {
1226 free(entry);
1227 closedir(dir);
1228 return ret;
1229 }
1230 }
1231
1232 free(entry);
1233 closedir(dir);
1234 return 0;
1235}
1236
Paul Cercueile3fbd952014-03-11 16:58:33 +01001237static int add_scan_elements(struct iio_device *dev, const char *devpath)
1238{
1239 struct stat st;
1240 char buf[1024];
1241 snprintf(buf, sizeof(buf), "%s/scan_elements", devpath);
1242
1243 if (!stat(buf, &st) && S_ISDIR(st.st_mode)) {
1244 int ret = foreach_in_dir(dev, buf, false, add_scan_element);
1245 if (ret < 0)
1246 return ret;
1247 }
1248
1249 return 0;
1250}
1251
Paul Cercueil1be57832014-03-11 16:27:16 +01001252static int create_device(void *d, const char *path)
1253{
Paul Cercueilff778232014-03-24 14:23:08 +01001254 uint32_t *mask = NULL;
Paul Cercueil1be57832014-03-11 16:27:16 +01001255 unsigned int i;
1256 int ret;
1257 struct iio_context *ctx = d;
1258 struct iio_device *dev = calloc(1, sizeof(*dev));
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001259 if (!dev)
Paul Cercueil1be57832014-03-11 16:27:16 +01001260 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001261
Paul Cercueileaab6582014-02-21 09:35:59 +01001262 dev->pdata = calloc(1, sizeof(*dev->pdata));
1263 if (!dev->pdata) {
1264 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001265 return -ENOMEM;
Paul Cercueileaab6582014-02-21 09:35:59 +01001266 }
1267
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001268 dev->ctx = ctx;
Paul Cercueil1be57832014-03-11 16:27:16 +01001269 dev->id = strdup(strrchr(path, '/') + 1);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001270 if (!dev->id) {
Paul Cercueileaab6582014-02-21 09:35:59 +01001271 free(dev->pdata);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001272 free(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001273 return -ENOMEM;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001274 }
1275
Paul Cercueil1be57832014-03-11 16:27:16 +01001276 ret = foreach_in_dir(dev, path, false, add_attr_or_channel);
1277 if (ret < 0) {
1278 free_device(dev);
1279 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001280 }
1281
Paul Cercueil54913ac2014-03-31 14:48:19 +02001282 for (i = 0; i < dev->nb_channels; i++)
1283 set_channel_name(dev->channels[i]);
1284
Michael Hennerichebe49662014-11-07 10:32:44 +01001285 ret = add_scan_elements(dev, path);
Paul Cercueile3fbd952014-03-11 16:58:33 +01001286 if (ret < 0) {
1287 free_device(dev);
1288 return ret;
1289 }
1290
Michael Hennerichebe49662014-11-07 10:32:44 +01001291 ret = detect_and_move_global_attrs(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001292 if (ret < 0) {
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001293 free_device(dev);
Paul Cercueil1be57832014-03-11 16:27:16 +01001294 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001295 }
1296
Paul Cercueilff778232014-03-24 14:23:08 +01001297 dev->words = (dev->nb_channels + 31) / 32;
1298 if (dev->words) {
1299 mask = calloc(dev->words, sizeof(*mask));
Paul Cercueil45c575d2014-03-20 15:14:01 +01001300 if (!mask) {
1301 free_device(dev);
1302 return ret;
1303 }
Paul Cercueil45c575d2014-03-20 15:14:01 +01001304 }
1305
Paul Cercueilff778232014-03-24 14:23:08 +01001306 dev->mask = mask;
Paul Cercueil45c575d2014-03-20 15:14:01 +01001307
Paul Cercueil1be57832014-03-11 16:27:16 +01001308 ret = add_device_to_context(ctx, dev);
1309 if (ret < 0)
1310 free_device(dev);
1311 return ret;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001312}
1313
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001314static int add_debug_attr(void *d, const char *path)
1315{
1316 struct iio_device *dev = d;
1317 const char *attr = strrchr(path, '/') + 1;
1318 char **attrs, *name = strdup(attr);
1319 if (!name)
1320 return -ENOMEM;
1321
1322 attrs = realloc(dev->debug_attrs,
1323 (1 + dev->nb_debug_attrs) * sizeof(char *));
1324 if (!attrs) {
1325 free(name);
1326 return -ENOMEM;
1327 }
1328
1329 attrs[dev->nb_debug_attrs++] = name;
1330 dev->debug_attrs = attrs;
1331 DEBUG("Added debug attr \'%s\' to device \'%s\'\n", name, dev->id);
1332 return 0;
1333}
1334
1335static int add_debug(void *d, const char *path)
1336{
1337 struct iio_context *ctx = d;
1338 const char *name = strrchr(path, '/') + 1;
1339 struct iio_device *dev = iio_context_find_device(ctx, name);
1340 if (!dev)
1341 return -ENODEV;
1342 else
1343 return foreach_in_dir(dev, path, false, add_debug_attr);
1344}
1345
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001346static int local_set_timeout(struct iio_context *ctx, unsigned int timeout)
1347{
1348 ctx->rw_timeout_ms = timeout;
1349 return 0;
1350}
1351
Paul Cercueil0865e802014-10-28 14:35:19 +01001352static struct iio_context * local_clone(
1353 const struct iio_context *ctx __attribute__((unused)))
1354{
Paul Cercueil63e52182014-12-11 12:52:48 +01001355 return local_create_context();
Paul Cercueil0865e802014-10-28 14:35:19 +01001356}
1357
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001358static struct iio_backend_ops local_ops = {
Paul Cercueil0865e802014-10-28 14:35:19 +01001359 .clone = local_clone,
Paul Cercueil44010ea2014-02-21 11:47:04 +01001360 .open = local_open,
1361 .close = local_close,
1362 .read = local_read,
1363 .write = local_write,
Paul Cercueil92f46df2014-04-28 13:17:53 +02001364 .get_buffer = local_get_buffer,
Paul Cercueil167d3112014-02-18 12:23:53 +01001365 .read_device_attr = local_read_dev_attr,
1366 .write_device_attr = local_write_dev_attr,
1367 .read_channel_attr = local_read_chn_attr,
1368 .write_channel_attr = local_write_chn_attr,
Paul Cercueil096e9aa2014-03-10 12:48:51 +01001369 .get_trigger = local_get_trigger,
1370 .set_trigger = local_set_trigger,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001371 .shutdown = local_shutdown,
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001372 .set_timeout = local_set_timeout,
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001373};
1374
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001375static void init_index(struct iio_channel *chn)
1376{
1377 char buf[1024];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001378 long id = -ENOENT;
1379
1380 if (chn->is_scan_element) {
1381 id = (long) local_read_chn_attr(chn, "index", buf, sizeof(buf));
1382 if (id > 0)
1383 id = atol(buf);
1384 }
1385 chn->index = id;
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001386}
1387
1388static void init_data_format(struct iio_channel *chn)
1389{
1390 char buf[1024];
1391 ssize_t ret;
1392
1393 if (chn->is_scan_element) {
1394 ret = local_read_chn_attr(chn, "type", buf, sizeof(buf));
1395 if (ret < 0) {
1396 chn->format.length = 0;
1397 } else {
1398 char endian, sign;
1399
1400 sscanf(buf, "%ce:%c%u/%u>>%u", &endian, &sign,
1401 &chn->format.bits, &chn->format.length,
1402 &chn->format.shift);
Michael Hennerichfa3c6f62014-08-13 11:21:23 +02001403 chn->format.is_signed = (sign == 's' || sign == 'S');
1404 chn->format.is_fully_defined =
1405 (sign == 'S' || sign == 'U'||
1406 chn->format.bits == chn->format.length);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001407 chn->format.is_be = endian == 'b';
1408 }
1409 }
1410
1411 ret = iio_channel_attr_read(chn, "scale", buf, sizeof(buf));
1412 if (ret < 0) {
1413 chn->format.with_scale = false;
1414 } else {
1415 chn->format.with_scale = true;
1416 chn->format.scale = atof(buf);
1417 }
1418}
1419
1420static void init_scan_elements(struct iio_context *ctx)
1421{
1422 unsigned int i, j;
1423
1424 for (i = 0; i < ctx->nb_devices; i++) {
1425 struct iio_device *dev = ctx->devices[i];
1426
1427 for (j = 0; j < dev->nb_channels; j++) {
1428 struct iio_channel *chn = dev->channels[j];
Paul Cercueil97679ac2014-06-12 10:08:20 +02001429 init_index(chn);
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001430 init_data_format(chn);
1431 }
1432 }
1433}
1434
Paul Cercueil63e52182014-12-11 12:52:48 +01001435struct iio_context * local_create_context(void)
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001436{
Paul Cercueil1be57832014-03-11 16:27:16 +01001437 int ret;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001438 unsigned int len;
1439 struct utsname uts;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001440 struct iio_context *ctx = calloc(1, sizeof(*ctx));
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001441 if (!ctx)
1442 goto err_set_errno_enomem;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001443
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001444 ctx->ops = &local_ops;
1445 ctx->name = "local";
Paul Cercueile1e0a8f2014-06-10 15:40:29 +02001446 local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001447
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001448 uname(&uts);
1449 len = strlen(uts.sysname) + strlen(uts.nodename) + strlen(uts.release)
1450 + strlen(uts.version) + strlen(uts.machine);
1451 ctx->description = malloc(len + 5); /* 4 spaces + EOF */
1452 if (!ctx->description) {
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001453 free(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001454 goto err_set_errno_enomem;
Paul Cercueilc957d9f2015-01-08 15:05:42 +01001455 }
1456
1457 snprintf(ctx->description, len + 5, "%s %s %s %s %s", uts.sysname,
1458 uts.nodename, uts.release, uts.version, uts.machine);
1459
Paul Cercueil1be57832014-03-11 16:27:16 +01001460 ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
1461 if (ret < 0) {
Paul Cercueil1be57832014-03-11 16:27:16 +01001462 iio_context_destroy(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001463 errno = -ret;
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001464 return NULL;
1465 }
1466
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001467 foreach_in_dir(ctx, "/sys/kernel/debug/iio", true, add_debug);
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001468
Paul Cercueilcac16ac2014-06-11 14:32:17 +02001469 init_scan_elements(ctx);
Paul Cercueil97679ac2014-06-12 10:08:20 +02001470 iio_context_init(ctx);
Paul Cercueilddaa26a2014-04-14 17:32:18 +02001471
Paul Cercueilc1ed8482014-06-11 16:29:43 +02001472 ctx->xml = iio_context_create_xml(ctx);
1473 if (!ctx->xml) {
Paul Cercueil4c6729d2014-04-04 17:24:41 +02001474 iio_context_destroy(ctx);
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001475 goto err_set_errno_enomem;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001476 }
Paul Cercueilae88fde2014-03-12 11:47:10 +01001477
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001478 return ctx;
Paul Cercueil3ad8e372015-03-16 17:07:37 +01001479
1480err_set_errno_enomem:
1481 errno = ENOMEM;
1482 return NULL;
Paul Cercueil0b2ce712014-02-17 15:04:18 +01001483}